angular.ioのaot-compilerを読む
はじめに
- angular初学者なので、多々誤りがあると思って読んでください。これは備忘録です。
- Tour of heroの部分をベースに読んでいきます
- 完成品をDLすることもできますが、チュートリアルに自分で変更を加えていきます。
index.html
- AOTとroolupは時間がかかるので、開発時はJIT、本番ではAOTに分ける必要があります。src/index.htmlをaot配下にコピーして、aot/index.htmlに対して変更を加えていきます。
- バンドルのロードにSystemJSのようなモジュールローダーを必要としないので、aot/index.htmlから不要部分を削除します。
<script src="node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('main.js').catch(function(err){ console.error(err); }); </script>
- 代わりにバンドルファイルをロードするのでbodyタグの閉じタグの後にscriptタグを挿入します。
<script src="dist/build.js"></script>
main.ts
- AOTとJITは大部分は同じように起動しますが、bootstrapが大きく異なります。JITではAppModuleによるbootstrapではなく、tsconfig-aotに沿ってコンパイルされる時に出力されるNgFactoryファイル群によってbootstrapされます。
- main.tsと同階層にmain-aot.tsを作成し、NgFactoryをimportします。
import { platformBrowser } from '@angular/platform-browser'; import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory'; platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
typescript configuration
- AOTではTree Shaking(のRollup)でimport/exportをトレースするのでes2015(es6)でトランスパイルされる必要があるのに対して、JITではcommonJSでトランスパイルされるのが好ましいので、configファイルは明示的に分けるべきです。
- tsconfig-aot.jsonとして、以下のように準備します。
{ "compilerOptions": { "target": "es5", "module": "es2015", "moduleResolution": "node", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "lib": [ "es2015", "dom" ], "noImplicitAny": true, "suppressImplicitAnyIndexErrors": true, "typeRoots": [ "./node_modules/@types/" ] }, "files": [ "src/app/app.module.ts", "src/main-aot.ts" ], "angularCompilerOptions": { "genDir": "aot", "skipMetadataEmit" : true } }
tree shaking
- tree shakingの1つとしてRollUpが実行されます。
- configファイルとしてrollup-config.jsを以下のように設定し、ルート配下に配置します。
// import rollup from 'rollup' import nodeResolve from 'rollup-plugin-node-resolve' import commonjs from 'rollup-plugin-commonjs'; import uglify from 'rollup-plugin-uglify' export default { entry: 'src/main-aot.js', dest: 'aot/dist/build.js', // output a single application bundle sourceMap: true, sourceMapFile: 'aot/dist/build.js.map', format: 'iife', onwarn: function(warning) { // Skip certain warnings // should intercept ... but doesn't in some rollup versions if ( warning.code === 'THIS_IS_UNDEFINED' ) { return; } // console.warn everything else console.warn( warning.message ); }, plugins: [ nodeResolve({jsnext: true, module: true}), commonjs({ include: 'node_modules/rxjs/**', }), uglify() ] }
Running the application
パッケージのインストール
- platform-serverがなければ入れる。
npm install @angular/compiler-cli @angular/platform-server --save
- rollup系のプラグインもなければ入れる
npm install rollup rollup-plugin-node-resolve rollup-plugin-commonjs rollup-plugin-uglify --save-dev
copy-dist-files
- AOT配布ファイルをaot/配下にコピーするスクリプトを作成します。
var fs = require('fs'); var resources = [ 'node_modules/core-js/client/shim.min.js', 'node_modules/zone.js/dist/zone.min.js', 'src/styles.css' ]; resources.map(function(f) { var path = f.split('/'); var t = 'aot/' + path[path.length-1]; fs.createReadStream(f).pipe(fs.createWriteStream(t)); });
- pakcage.jsonのcopy-dist-filesを実行します。
node copy-dist-files
tree shaking補足
- tree shakingはAOTコンパイラによってセットされたステージ上のファイルを全検索して不要なコードを除きます。これによってアプリケーションサイズが小さくなります。
Rollup
- tree shakingのプラグイン①
- import/exportのトレースによるアプリケーションの静的解析ユーティリティ
- 再記になるがtsconfig-aot.jsonでmoduleにes2015を指定したのは、requireではなくimport/exportが使われている必要があるから
- Rollupユーティリティをインストール
npm install rollup rollup-plugin-node-resolve rollup-plugin-commonjs rollup-plugin-uglify --save-dev
- rollup-config.js(rollupの設定ファイル)をルート配下に作成します。内容はとりあえずサンプル通り何ですが、1行目のコードは不要なのでコメントアウトする。
// import rollup from 'rollup'
これをしないと、以下の警告が出る
'default' is imported from external module 'rollup' but never used