最近做了一些前后端分离开发的实践,前端用Angular2 和ES6 进行开发,后端用Rails 提供API。至于为什么用ES6而不是Angular2官方默认的typescript,主要原因在于个人更习惯使用弱类型的编程语言。
大体的思路是:用ES6和Angular2进行前端开发,然后使用 Browserify 和 Babel 将 ES6 转换成 ES5(一个叫 bundle.js 的JS 文件),然后通过Rails 的 Assets Pipeline 将生成的JS文件加载到页面里执行。项目部署的时候直接用 Capistrano 通过 Assets Pipeline 部署 bundle.js 就可以了。
在 Rails 项目中使用 Browserify 和 Babel
Rails 项目中使用 Browserify 的方法有两个:
一开始出于习惯,我直接用了 browserify-rails, 后面发现随着项目代码的不断增多,发现 browserify-rails 有一个难以忍受的问题,就是特别慢,于是果断放弃,改用 npm 的方式。
安装 node
$ brew install node $ npm -v
成功安装 node 之后就可以使用 npm 了。
新建 Rails 工程
$ rails new dev-ops
生成 package.json
$ npm init
然后按照提示完善相关信息,生成package.json 文件。对 npm 和 package.json 不熟悉的朋友可以参看npm 的官方博客以及 Using a package.json这篇。
下面是我生成的 package.json 文件的内容:
// package.json by zuozuo { "name": "dev-ops", "version": "1.0.0", "description": "rails project with angular2 and es6", "main": "index.js", "directories": { "test": "test" }, "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "git+https://github.com/zuozuo/dev-ops.git" }, "keywords": [ "rails", "angular2", "es6" ], "author": "zuozuo", "license": "MIT", "bugs": { "url": "https://github.com/zuozuo/dev-ops/issues" }, "homepage": "https://github.com/zuozuo/dev-ops#readme" }
安装 Angular2
$ npm install angular2@2.0.0-beta.2 --save
上面的 --save 选项会在安装angular2 之后将 Angular2 及其版本写到 package.json 里面。
// package.json里面新增了下面几行代码 "dependencies": { "angular2": "^2.0.0-beta.2", "es6-promise": "^3.1.2", "es6-shim": "^0.33.13", "reflect-metadata": "^0.1.2", "rxjs": "^5.0.0-beta.0", "zone.js": "^0.5.10" }
注:Angular2 的最新版本是 angular2@2.0.0-beta.9 这里之所以没用最新的版本是因为 beta.6 beta.7 beta.8 beta.9 都有一个 bug:TypeError: this.directive_0_0.ngDoCheck is not a function 开发环境下是不会出现这个bug,但是在发布到生产环境对 JS 文件进行压缩和混淆之后,就会出现这个bug ,目前这个bug还没有解决,beta.2 没有这个问题。
安装 browserify 和 watchify
// package.json里面又新增了下面几行代码 "devDependencies": { "browserify": "^13.0.0", "watchify": "^3.7.0" }
安装 babel, babelify 以及 babel-plugin
$ npm install babel-core babel-eslint babel-plugin-angular2-annotations babel-plugin-transform-class-properties babel-plugin-transform-decorators-legacy babel-plugin-transform-flow-strip-types babel-preset-es2015 babel-runtime babelify babylon --save-dev $ npm install babel-polyfill@6.3.14 --save
// package.json 中 devDependencies 部分变成了 "devDependencies": { "babel-core": "^6.7.2", "babel-eslint": "^5.0.0", "babel-plugin-angular2-annotations": "^5.0.0", "babel-plugin-transform-class-properties": "^6.6.0", "babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-plugin-transform-flow-strip-types": "^6.7.0", "babel-preset-es2015": "^6.6.0", "babel-runtime": "^6.6.1", "babelify": "^7.2.0", "babylon": "^6.7.0", "browserify": "^13.0.0", "watchify": "^3.7.0" } // package.json 中 dependencies 部分变成了 "dependencies": { "angular2": "^2.0.0-beta.2", "babel-polyfill": "^6.3.14", "es6-promise": "^3.1.2", "es6-shim": "^0.33.13", "reflect-metadata": "^0.1.2", "rxjs": "^5.0.0-beta.0", "zone.js": "^0.5.10" },
上面的几个 babel-plugin 主要是用来支持 Angular2 的 annotation 的语法。 每个插件的具体功能感兴趣的朋友可以去 npm 上面去搜索查询。
配置 Babel
在根目录下创建文件 .babelrc
$ touch .babelrc
.babelrc 内容如下:
// .babelrc { "presets": ["es2015"], "plugins": [ "angular2-annotations", "transform-decorators-legacy", "transform-class-properties", "transform-flow-strip-types" ] }
注:关于Babel 和 .babelrc 的用法请参考:Babel · The compiler for writing next generation JavaScript 和 babelrc
OK,现在我们开发 Angular2 的基本配置工具都已经安装好了,下面就该开始项目开发了。
Angular2 的 Hello World 程序
创建 Angular2 工程目录
$ mkdir app/assets/angular2 $ cd app/assets/angular2 $ mkdir components services directives pipes
将 angular2 工程目录添加到 assets path 中
打开 config/initializers/assets.rb 文件,再文件末尾添加下面这行代码
# config/initializers/assets.rb Rails.application.config.assets.paths << Rails.root.join("app", "assets", "angular2")
生成 Rails 相关的 controller,view 和 action
$ spring rails g controller home index
# config/routes.rb Rails.application.routes.draw do get 'home/index' root to: "home#index" end
# app/view/home/index.html.erb
启动 rails 服务器
$ rails s
打开浏览器,访问 :3000/
嗯,页面上一片空白,什么都没有,别担心,这是正确的,下面我们就为我们的 Angular2 app 添加内容。
Angular2 的 hello world 程序代码