先创建一个简单的项目。可以从 https://github.com/wuanrin/angular-simple.git 克隆。 1. tsc + system.js 方式用 tsc 编译 typescript 代码,system.js 作为模块加载器。 编译命令: { "scripts": { "build": "tsc --outDir dist" } } 内联的模板文件
System.config({ map: { '@angular/common': 'node_modules/@angular/common/bundles/common.umd.js', '@angular/compiler': 'node_modules/@angular/compiler/bundles/compiler.umd.js', '@angular/core': 'node_modules/@angular/core/bundles/core.umd.js', '@angular/platform-browser': 'node_modules/@angular/platform-browser/bundles/platform-browser.umd.js', '@angular/platform-browser-dynamic': 'node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', 'rxjs': 'node_modules/rxjs' }, packages: { app: { defaultExtension: 'js' }, rxjs: { defaultExtension: 'js' } } }); 需要安装 system.js 的声明包:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Angular Demo</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> </head> <body> <app-root>Loading...</app-root> <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/dist/zone.js"></script> <script src="node_modules/rxjs/bundles/Rx.min.js"></script> <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> </html>
这样一个最简单的项目就编译好了。 单独的模板文件或者样式文件添加模板文件和 css 文件时的情况。在 src/app 目录中添加 app.component.html、app.component.css 并在 app.compnent.ts 中引用: @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) 再编译查看效果,这时会有报错:zone.js:2263 GET http://localhost:3000/app.component.html 404 (Not Found)。解决办法:
var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm; var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g; var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g; export var translate = function(load: {source: string, address: string}){ if (load.source.indexOf('moduleId') != -1) return load; var url = document.createElement('a'); url.href = load.address; var basePathParts = url.pathname.split('/'); basePathParts.pop(); var basePath = basePathParts.join('/'); var baseHref = document.createElement('a'); baseHref.href = this.baseURL; var baseHrefStr = baseHref.pathname; if (!baseHrefStr.startsWith('/base/')) { // it is not karma basePath = basePath.replace(baseHrefStr, ''); } load.source = load.source .replace(templateUrlRegex, function(match, quote, url){ var resolvedUrl = url; if (url.startsWith('.')) { resolvedUrl = basePath + url.substr(1); } return 'templateUrl: "' + resolvedUrl + '"'; }) .replace(stylesRegex, function(match, relativeUrls) { var urls = []; var rs; while ((rs = stringRegex.exec(relativeUrls)) !== null) { if (rs[2].startsWith('.')) { urls.push('"' + basePath + rs[2].substr(1) + '"'); } else { urls.push('"' + rs[2] + '"'); } } return "styleUrls: [" + urls.join(', ') + "]"; }); return load; };
System.config({ // 内容省略... packages: { app: { defaultExtension: 'js', meta: { './*.js': { loader: 'systemjs-angular-loader.js' } } }, // 内容省略... } });
2. tsc + system.js + aot 方式tsc 只是将 typescript 编译为 javascript。而 Angular 需要将模板,css 等编译为 javascript。以上方式是 JIT(just in time 即时编译)。 现在改为 AOT方式(ahead of time 预编译)。
{ "compileOnSave": false, "compilerOptions": { "sourceMap": true, "declaration": false, "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "es5", "typeRoots": [ "node_modules/@types" ], "lib": [ "es2016", "dom" ] }, "files": [ "src/main.aot.ts", "src/app/app.module.ts" ], "exclude": [ "node_modules", "dist", "dist.aot" ], "angularCompilerOptions": { "genDir": "aot", "skipMetadataEmit" : true } } 主要更是添加了 angularCompilerOptions 选项,用于配置编译生成的位置。还有 files 选项,主要是定义需要编译的文件(包含依赖), 因为有些文件是不需要的。
新建一个文件 src/systemjs.config.aot.ts。内容: System.config({ paths: { app: 'src/app' }, map: { '@angular/common': 'node_modules/@angular/common/bundles/common.umd.js', '@angular/compiler': 'node_modules/@angular/compiler/bundles/compiler.umd.js', '@angular/core': 'node_modules/@angular/core/bundles/core.umd.js', '@angular/platform-browser': 'node_modules/@angular/platform-browser/bundles/platform-browser.umd.js', '@angular/platform-browser-dynamic': 'node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', 'rxjs': 'node_modules/rxjs' }, packages: { app: { defaultExtension: 'js' }, aot: { defaultExtension: 'js' }, rxjs: { defaultExtension: 'js' } } }); 更改:
将该文件加入到 tsc 配置文件 tsconfig.aot.json 中。内容: { // 省略... "files": [ // 省略... "src/systemjs.config.aot.ts" ] // 省略... }
import { platformBrowser } from '@angular/platform-browser'; import { enableProdMode } from '@angular/core'; import { AppModuleNgFactory } from '../aot/src/app/app.module.ngfactory'; platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Angular Demo</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> </head> <body> <app-root>Loading...</app-root> <script src="node_modules/core-js/client/shim.min.js"></script> <script src="node_modules/zone.js/dist/zone.js"></script> <script src="node_modules/rxjs/bundles/Rx.min.js"></script> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="src/systemjs.config.aot.js"></script> <script> System.import('src/main.aot.js').catch(function(err){ console.error(err); }); </script> </body> </html> 主要是目录引用的更改。
ngc 命令 @angular/compiler-cli 包包含的一个编译工具。 命令: { "scripts": { "build": "tsc --outDir dist", "build.aot": "ngc -p tsconfig.aot.json", "server": "lite-server" } }
3. webpack 方式可以分为开发模式和生产模式。 开发模式
import 'core-js/es6'; import 'core-js/es7/reflect'; require('zone.js/dist/zone'); if (process.env.ENV === 'production') { // Production } else { // Development and test Error['stackTraceLimit'] = Infinity; require('zone.js/dist/long-stack-trace-zone'); }
// Angular import '@angular/platform-browser'; import '@angular/platform-browser-dynamic'; import '@angular/core'; import '@angular/common'; // RxJS import 'rxjs';
var path = require('path'); var webpack = require('webpack'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var HtmlWebpackPlugin = require('html-webpack-plugin'); // 输出目录 var distPath = path.join(__dirname, 'dist.webpack'); var appPath = path.join(__dirname, 'src', 'app'); module.exports = { devtool: 'cheap-module-eval-source-map', resolve: { extensions: ['.ts', '.js'] }, entry: { polyfills: './src/polyfills.ts', vendor: './src/vendor.ts', app: './src/main.ts' }, output: { path: distPath, publicPath: '/', filename: '[name].js', chunkFilename: '[id].chunk.js' }, module: { rules: [ { test: /\.ts$/, loaders: [ 'awesome-typescript-loader', 'angular2-template-loader' ] }, { test: /\.html$/, loader: 'html-loader' }, { test: /\.css$/, exclude: appPath, loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap' }) }, { test: /\.css$/, include: appPath, loader: 'raw-loader' } ] }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: ['app', 'vendor', 'polyfills'] }), new HtmlWebpackPlugin({ template: 'src/index.html' }) ] };
命令: { "scripts": { "build": "tsc --outDir dist", "build.aot": "ngc -p tsconfig.aot.json", "build.webpack": "webpack --progress --profile --bail", "server": "lite-server", "server.aot": "lite-server -c bs-config.aot.json" } }
webpack 提供了一个开发服务器 webpack-dev-server。该服务器启动一个服务器的同时也会编译工程,和 webpack 编译一样, 区别是 webpack 会生成文件,而 webpack-dev-server 不会生成文件,而是编译在内存中。
{ "scripts": { "build": "tsc --outDir dist", "build.aot": "ngc -p tsconfig.aot.json", "build.webpack": "webpack --progress --profile --bail", "server": "lite-server", "server.aot": "lite-server -c bs-config.aot.json", "server.webpack": "webpack-dev-server --open --inline --progress --hot" } } 生产模式
var path = require('path'); var webpack = require('webpack'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var HtmlWebpackPlugin = require('html-webpack-plugin'); // 输出目录 var distPath = path.join(__dirname, 'dist.webpack.prod'); var appPath = path.join(__dirname, 'src', 'app'); module.exports = { devtool: 'source-map', resolve: { extensions: ['.ts', '.js'] }, entry: { polyfills: './src/polyfills.ts', vendor: './src/vendor.ts', app: './src/main.aot.ts' }, output: { path: distPath, publicPath: '/', filename: '[name].[hash].js', chunkFilename: '[id].[hash].chunk.js' }, module: { rules: [ { test: /\.ts$/, loaders: [ { loader: 'awesome-typescript-loader', options: { configFileName: 'tsconfig.aot.json' } }, 'angular2-template-loader' ] }, { test: /\.html$/, loader: 'html-loader' }, { test: /\.css$/, exclude: appPath, loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap' }) }, { test: /\.css$/, include: appPath, loader: 'raw-loader' } ] }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: ['app', 'vendor', 'polyfills'] }), new HtmlWebpackPlugin({ template: 'src/index.html' }), new webpack.NoEmitOnErrorsPlugin(), new webpack.optimize.UglifyJsPlugin({ mangle: { keep_fnames: true } }) ] }; 注意:入口文件 entry.app 改为了 main.aot.ts。
start 用于开发,publish 用于发布。 { "scripts": { "start": "npm run server.webpack", "publish": "npm run build.webpack.prod", "build": "tsc --outDir dist", "build.aot": "ngc -p tsconfig.aot.json", "build.webpack": "webpack --progress --profile --bail --hot", "build.webpack.prod": "webpack --progress --profile --bail --config webpack.prod.js", "server": "lite-server", "server.aot": "lite-server -c bs-config.aot.json", "server.webpack": "webpack-dev-server --open --inline --progress --hot" } } |
|
来自: 涅槃沉殇 > 《Angular编译运行》