この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
丹内です。 掲題のとおり、BetaになっているRails5とAngular2を連携させるまでの手順をまとめました。
バージョン
- ruby 2.3.0
- node 4.2.4
- npm 3.5.3
Rails5アプリの準備
bundle initしてできたGemファイルにRails5を指定します。
source 'https://rubygems.org'
gem 'rails', '5.0.0.beta1'
bundle installしたらアプリを生成します。
$ rbenv exec bundle install
$ bundle exec rails new . -d mysql --skip-bundle -T
exist
create README.md
create Rakefile
create config.ru
create .gitignore
conflict Gemfile
Overwrite /Users/tannai.yuki/dev/sample/Gemfile? (enter "h" for help) [Ynaqdh]
force Gemfile
create app
(省略)
$ bundle exec rails db:create
$ bundle exec rails db:migrate
$ bundle exec rails s
=> Booting Puma
=> Rails 5.0.0.beta1 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
=> Ctrl-C to shutdown server
I, [2016-01-11T11:38:22.205313 #7174] INFO -- : Celluloid 0.17.2 is running in BACKPORTED mode. [ http://git.io/vJf3J ]
Puma 2.15.3 starting...
* Min threads: 0, max threads: 16
* Environment: development
* Listening on tcp://localhost:3000
webrickではなくpumaが使われています。 welcome aboardでRails5になっていることを確認したら、次のステップです。
フロントエンド環境の準備
npm initでもtouchでも良いので、アプリケーションルートにpackage.jsonを生成し、以下のように編集します。
{
"name": "sample-client",
"version": "1.0.0",
"engines": {
"node": ">= 4.2.3 < 5",
"npm": ">= 3"
},
"scripts": {
"start": "webpack -w"
},
"license": "ISC",
"dependencies": {
"angular2": "2.0.0-beta.1",
"es6-promise": "^3.0.2",
"es6-shim": "^0.33.3",
"es7-reflect-metadata": "^1.4.0",
"rxjs": "5.0.0-beta.0",
"zone.js": "0.5.10"
},
"devDependencies": {
"concurrently": "^1.0.0",
"exports-loader": "^0.6.2",
"expose-loader": "^0.7.1",
"imports-loader": "^0.6.5",
"ts-loader": "^0.7.2",
"typescript": "^1.7.3",
"webpack": "^1.12.11"
}
}
同じくアプリケーションルートに、webpack.config.jsを用意します。
const path = require('path');
const webpack = require('webpack');
const CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
module.exports = {
devtool: 'source-map',
debug: true,
entry: {
'vendor': './client/vendor.ts',
'app': './client/bootstrap.ts'
},
output: {
filename: 'bundle.js',
path: './app/assets/javascripts/generated'
},
resolve: {
root: [path.join(__dirname, 'client/assets/scripts')],
extensions: ['', '.webpack.js', '.web.js', '.ts', '.tsx', '.js']
},
module: {
loaders: [
{ test: /\.ts?$/, exclude: /node_modules/, loader: 'ts-loader' }
]
},
plugins: [
new CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.js', minChunks: Infinity }),
new CommonsChunkPlugin({ name: 'common', filename: 'common.js', minChunks: 2, chunks: ['app', 'vendor'] })
]
}
Typescriptのコンパイラ、TSCの設定ファイルであるtsconfig.jsonも用意します。
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
},
"files": [
"./client/vendor.ts",
"./client/bootstrap.ts",
"./client/components/AppComponent.ts"
],
"exclude": [
"node_modules"
],
"compileOnSave": false,
"buildOnSave": false,
"atom": {
"rewriteTsconfig": true
}
}
これらアプリケーションルートに設置する設定ファイルに書かれているように、以後/client
以下にAngular2のファイルを配置していきます。
Angular2の実装
まずは/client/bootstrap.tsにAngular2の設定を書きます。
import {bootstrap} from 'angular2/platform/browser';
import {App} from './app';
import {provide} from 'angular2/core';
import {
ROUTER_PRIMARY_COMPONENT,
APP_BASE_HREF,
ROUTER_PROVIDERS as NG2_ROUTER_PROVIDERS
} from 'angular2/router';
const ROUTER_PROVIDERS: Array<any> = [
NG2_ROUTER_PROVIDERS,
provide(ROUTER_PRIMARY_COMPONENT, {
useValue: App
}),
provide(APP_BASE_HREF, {
useValue: '/'
})
];
const APP_PROVIDERS: Array<any> = [
ROUTER_PROVIDERS
];
window.addEventListener("load", (e) => {
bootstrap(App, APP_PROVIDERS);
});
この中でRouteConfigをアノテートしている、Rootになるコンポーネントを作成します。
import {ViewEncapsulation, Component} from 'angular2/core';
import {CORE_DIRECTIVES} from 'angular2/common';
import {ROUTER_DIRECTIVES, Router, RouteConfig, Location} from 'angular2/router';
import {AppComponent} from './components/AppComponent';
@Component({
moduleId: module.id,
selector: 'app',
encapsulation: ViewEncapsulation.Emulated,
template: `
<h1>This is Root Component</h1>
<router-outlet></router-outlet>
`,
directives: [
CORE_DIRECTIVES,
ROUTER_DIRECTIVES
]
})
@RouteConfig([
{ path: '/', name: 'AppComponent', component: AppComponent }
])
export class App {
router: Router;
location: Location;
constructor(router: Router, location: Location) {
console.log('app.ts');
this.router = router;
this.location = location;
}
}
/client/components以下に、AppComponent.tsを作成します。
import {ViewEncapsulation, Component} from 'angular2/core';
@Component({
template: '<h1>This is AppComponent</h1>'
})
export class AppComponent {
constructor() {
console.log('AppComponent.ts')
}
}
npm startでjavascriptが生成されることを確認します。
$ npm start
> sample-client@1.0.0 start /Users/tannai.yuki/dev/sample
> webpack -w
ts-loader: Using typescript@1.7.5 and /Users/tannai.yuki/dev/sample/tsconfig.json
Hash: f7e52fb9698e7e970aaa
Version: webpack 1.12.11
Time: 5065ms
Asset Size Chunks Chunk Names
bundle.js 3.92 kB 0 [emitted] app
vendor.js 766 kB 1 [emitted] vendor
common.js 4.52 MB 2 [emitted] common
bundle.js.map 3.61 kB 0 [emitted] app
vendor.js.map 889 kB 1 [emitted] vendor
common.js.map 4.81 MB 2 [emitted] common
+ 510 hidden modules
Railsの設定
エントリポイントになるHomeControllerを作成します。
$ bundle exec rails g controller HomeController index
/app/views/layouts/application.html.erbに、ルートコンポーネントで指定したセレクタを追加します。
<!DOCTYPE html>
<html>
<head>
<title>Sample</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<%= csrf_meta_tags %>
<%= action_cable_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_include_tag 'application' %>
</head>
<body>
<app>Loading...</app> <!-- この行です -->
<%= yield %>
</body>
</html>
app/assets/javascripts/application.jsで生成されるjavascriptの読み込み順を設定します。 今回の設定ではcommon、vendor、bundleの3つが生成されますが、この読み込み順によってはエラーが発生してしまうことへの対処です。
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require generated/common
//= require generated/vendor
//= require generated/bundle
//= require_tree .
表示の確認
rails sでアプリを起動してlocalhost:3000が以下のようになっていれば成功です!
このとき、javascript consoleには以下のように表示されます。
まとめ
Rails5でAngular2を動かす設定をご紹介しました。 ActionCableとAngular2の組み合わせはとても強力だと思うので、今後も継続して追っていきたいです。