原创翻译,转载请注明出处。
原文标题:Angular2 with NPM and Webpack
原文地址:https://www.illucit.com/blog/2016/06/angular2-npm-webpack/
这篇文章演示了怎样使用Webpack来配置Angular2工程。这些配置还包含了TypeScript,Less,CSS(例如Bootstrap)和字体(例如FontAwesome)。
-
必须的NPM包
Webpack需要的所有依赖,都放到package.json的devDependencies里,这样的话NPM就能自动安装它们。
package.json
{ "version": "1.0.0", "name": "faces", "dependencies": { "@angular/common": "^2.0.0-rc.1", "@angular/compiler": "^2.0.0-rc.1", "@angular/core": "^2.0.0-rc.1", "@angular/http": "^2.0.0-rc.1", "@angular/router": "^2.0.0-rc.1", "@angular/platform-browser": "^2.0.0-rc.1", "@angular/platform-browser-dynamic": "^2.0.0-rc.1", "core-js": "2.2.2", "rxjs": "5.0.0-beta.6", "reflect-metadata": "0.1.3", "zone.js": "0.6.12" "jquery": "2.2.3", "bootstrap": "3.3.6", "font-awesome": "4.6.1" }, "devDependencies": { "ts-loader": "0.8.2", "typescript": "1.8.10", "typings": "0.7.12", "webpack": "1.12.15", "es6-promise": "3.1.2", "es6-shim": "0.35.0", "extract-text-webpack-plugin": "1.0.1", "file-loader": "0.8.5", "gulp": "3.9.1", "less": "^2.6.1", "less-loader": "2.2.3", "style-loader": "0.13.1", "url-loader": "0.5.7", "webpack-merge": "0.8.4", "webpack-stream": "3.1.0" } }
用NPM把所有的开发依赖包都安装完之后,我们就开始配置Webpack。
-
配置Webpack
webpack.config.js
var webpack = require('webpack'); var path = require('path'); var ExtractTextPlugin = require("extract-text-webpack-plugin"); // Webpack Config var webpackConfig = { entry: { 'polyfills': './wwwroot/polyfills.ts', 'vendor': './wwwroot/vendor.ts', 'app': './wwwroot/app.ts', 'vendor-style': './wwwroot/style/vendor-style.ts', 'app-style': './wwwroot/style/app-style.ts', }, devtool: 'source-map', cache: true, output: { path: './wwwroot/dist', filename: '[name].bundle.js', sourceMapFilename: '[name].map', chunkFilename: '[id].chunk.js' }, resolve: { extensions: ['', '.ts', '.js'] }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: ['app', 'vendor', 'polyfills'], minChunks: Infinity }), new ExtractTextPlugin("[name].css"), new webpack.optimize.DedupePlugin() ], module: { loaders: [ // .ts files for TypeScript { test: /\.ts$/, loader: 'ts-loader' }, { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }, { test: /\.less$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader") }, { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" }, { test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/, loader:"url?prefix=font/&limit=5000" }, { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/octet-stream" }, { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=image/svg+xml" } ] } }; var webpackMerge = require('webpack-merge'); module.exports = webpackMerge(webpackConfig);
对这个配置文件的一些说明。在我的这个Angular2程序里,打包所有的文件需要大约30秒。如果在你每次修改文件之后都需要等20几秒也是挺浪费时间的。另外,所有下面的这些配置文件都需要放在Angular2工程的根目录下。
-
分割工程
一个较好的方法,是把工程分割成polyfills文件,vendor文件和application自身文件。这种方式,在你每次修改都需要打包的时候,会节省不少时间。所以Webpack配置文件里包含了下面的命令:
new webpack.optimize.CommonsChunkPlugin({ name: ['app', 'vendor', 'polyfills'],
Webpack会为每一个entry文件创建一个依赖图。已经包含在polyfills里的依赖将不会被再次放入vendor文件里。同样,已经包含在vendor和polyfills里的依赖将不会被加到app文件里。
polyfills和vendor文件是什么样子的呢:
polyfills.ts
import 'core-js'; import 'zone.js/dist/zone';
vendor.ts
import "@angular/common"; import "@angular/compiler"; import "@angular/core"; import "@angular/http"; import "@angular/router"; import "@angular/platform-browser"; import "@angular/platform-browser-dynamic"; import 'rxjs/Rx';
为了能然Webpack能编译TypeScript文件,你需要引入一个特殊的loader去复制.ts文件。下面的Webpack设定文件的loader部分的设定会达到这个目的。
{ test: /\.ts$/, loader: 'ts-loader' },
这些loader是包含在package.json文件的devDependencies部分的npm包列表里。
-
支持Less和CSS
配置文件里还包含了一些less和css的loader,例如:
{ test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }, { test: /\.less$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader") },
为了把less或者css文件里使用的字体文件也打包,我还增加了一些loader,例如:
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: "file" },
这些包含了一些针对于字体文件的正则表达式。例如bootstrap里的字体文件。
除了loaders之外,我还加了vendor styles 和app styles两个enter点。
vendor-style.ts
import 'bootstrap/dist/css/bootstrap.css'; import 'font-awesome/less/font-awesome.less';
app-style.ts
import './app.less';
-
配置TypeScript
为了完整起见,我把tsconfig.json也贴出来。
{ "compilerOptions": { "module": "commonjs", "target": "es5", "outDir": ".", "rootDir": ".", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "moduleResolution": "node" }, "exclude": [ "typings/main.d.ts", "typings/main", "node_modules" ], "compileOnSave": false, "buildOnSave": false, "atom": { "rewriteTsconfig": false } }
-
配置Typings
Typings继承与tsd。它用来取得用纯javascript写成的库定义文件。你可以用typings命令行工具来为增加的库引入不同的typing定义。
typings.json
{ "name": "myapp", "dependencies": { }, "ambientDependencies": { "es6-collections": "registry:dt/es6-collections#0.5.1+20160215162030", "es6-promise": "registry:dt/es6-promise#0.0.0+20160221190517", "jquery": "registry:dt/jquery#1.10.0+20160316155526" } }
-
使用Webpack打包
首先使用npm安装webpack。之后你可以输入下面的命令开始打包。
webpack -d
它将在开发模式下编译出几个包。它还包含所有输出文件的map文件。这样的话,代码就可以在浏览器里被调试。如果你使用产品模式(在命令行里使用参数 -p),输出文件的大小将变小,并且不包含map文件。
Output:
bundles,font等等文件,都将被输出到在Webpack配置文件里定义的目标文件夹。
你可能注意到编译花费了不少时间。那为什么我们在最初把输出文件分成几块?因为我们可以使用监视模式来启动Webpack。
webpack -d -w
最初它会打包所有的文件。当所有的编译都完了之后,Webpack仍然会以监视模式运行。当你的程序文件被修改的时候,所有被影响的部分都会被重新编译。因为我们把代码分成了polyfills, vendor files和app本身几块,所以大多数情况之后app块被编译了。这样的话能稍微节省点时间。所以在开发阶段,我建议使用监视模式。
-
在Html页面里使用输出文件
输出块被简单的包含在你的html页面里。就像下面所示:
<html> <head> <title>MyApp</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0" /> <meta name="apple-mobile-web-app-capable" content="yes"> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <link rel="stylesheet" href="dist/vendor-style.css" /> <link rel="stylesheet" href="dist/app-style.css" /> </head> <body> <myapp> Loading... </myapp> <script src="dist/polyfills.bundle.js"></script> <script src="dist/vendor.bundle.js"></script> <script async src="dist/app.bundle.js"></script> </body> </html>
webkack还可以使用插件,这样的话你就不用手动在你的html页面里加入输出块文件。
-
关于输出文件大小的附注
在我的例子里,输出文件的大小仍然比较大,开发模式有4M,产品模式下有1M。不管怎样,这些文件最初被加载之后,你的单页应用也不在需要别的依赖了。如果有人告诉我怎样去再缩小输出文件的大小,那将非常棒!
-
总结
这篇文章演示了怎样去打包一个Angular2工程。在把各个方面综合在一起的时候,花费了我一些时间。希望大家在配置Angular2工程的时候,可以节省你的时间。如果有任何问题或者评论,可以在下面提交评论。
(译者注:去原页面评论哦~)
--End--