如何使用 Webpack 运行 Angular 2 AOT
How to run Angular 2 AOT with Webpack
更新
@developer033 提到后,我是 运行ning npm 运行 server:prod 和应用 运行 处于生产模式。但我不确定,如何验证它是否经过 AOT 优化?
如果我检查 main.bundle.js 以检查它是否有 main.browser.aot.ts 的代码:
我看到的是 main.browser.ts 而不是 main.browser.aot.ts
所以我不确定我是否使用 AOT 构建。
原版Post
好的,我可以使用 Webpack 在 AOT 模式下编译我的 Angular2 项目,它创建了两个文件夹,一个是 "dist",另一个是 "compiled",但我不确定如何 运行编译后的AOT工程
构建命令:
"build:aot:prod": "npm run clean:dist && npm run clean:aot && webpack --config config/webpack.prod.js --progress --profile
--bail"
编译后,我运行命令:
npm run webpack-dev-server
现在应用程序 运行s 但我不确定它是否甚至使用 AOT 编译代码。我在浏览器中看到 AOT 和非 AOT 应用程序没有区别。
AOT:
没有 AOT:
tsconfig.webpack.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true,
"baseUrl": "./src",
"outDir": "compiled",
"paths": {},
"lib": [
"es2015",
"dom"
],
"typeRoots": [
"node_modules/@types"
]
},
"exclude": [
"node_modules",
"dist",
"compiled",
"src/**/*.spec.ts",
"src/**/*.e2e.ts"
],
"awesomeTypescriptLoaderOptions": {
"forkChecker": true,
"useWebpackText": true
},
"angularCompilerOptions": {
"genDir": "compiled",
"skipMetadataEmit": true
},
"compileOnSave": false,
"buildOnSave": false,
"atom": {
"rewriteTsconfig": false
}
}
main.browser.aot.ts:
import { platformBrowser } from '@angular/platform-browser';
import { decorateModuleRef } from './app/environment';
import { enableProdMode } from '@angular/core';
import { AppModuleNgFactory } from '../compiled/src/app/app.module.ngfactory';
if (ENV.toLocaleLowerCase() === 'production' || ENV.toLocaleLowerCase() === 'prod') {
enableProdMode();
}
export function main(): Promise<any> {
return platformBrowser()
.bootstrapModuleFactory(AppModuleNgFactory)
.then(decorateModuleRef)
.catch(err => console.error(err));
}
export function bootstrapDomReady() {
document.addEventListener('DOMContentLoaded', main);
}
bootstrapDomReady();
config/webpack.common.js:
const HMR = helpers.hasProcessFlag('hot');
const AOT = helpers.hasNpmFlag('aot');
const METADATA = {
title: 'Angular2 Webpack Starter by @gdi2290 from @AngularClass',
baseUrl: '/',
isDevServer: helpers.isWebpackDevServer()
};
module.exports = function(options) {
isProd = options.env === 'production';
return {
entry: {
'polyfills': './src/polyfills.browser.ts',
'vendor': './src/vendor.browser.ts',
'main': AOT ? './src/main.browser.aot.ts' : './src/main.browser.ts'
},
resolve: { extensions: ['.ts', '.js', '.json', '.css', '.scss'], modules: [helpers.root('src'), 'node_modules'], },
module: {
rules: [
{
test: /\.ts$/,
loaders: [
'@angularclass/hmr-loader?pretty=' + !isProd + '&prod=' + isProd,
'awesome-typescript-loader',
{ loader: 'ng-router-loader', options: { loader: 'async-import', genDir: 'compiled', aot: AOT } },
'angular2-template-loader'
],
exclude: [/\.(spec|e2e)\.ts$/]
},
{
test: /\.scss$/,
exclude: /node_modules/,
loaders: ['raw-loader', 'sass-loader'] // sass-loader not scss-loader
},{ test: /\.json$/, loader: 'json-loader'},
{ test: /\.woff(2)?(\?v=.+)?$/, use: 'url-loader?limit=10000&mimetype=application/font-woff' },
{ test: /\.(ttf|eot|svg)(\?v=.+)?$/, use: 'file-loader' },
{ test: /bootstrap\/dist\/js\/umd\//, use: 'imports-loader?jQuery=jquery' },
{ test: /\.html$/, loader: 'raw-loader', exclude: [helpers.root('src/index.html')] },
{ test: /\.(jpg|png|gif)$/, loader: 'file' },
],
},
plugins: [
new ngcWebpack.NgcWebpackPlugin({
disabled: !AOT,
tsConfig: helpers.root('tsconfig.webpack.json'),
resourceOverride: helpers.root('config/resource-override.js')
}),
new ExtractTextPlugin({ filename: 'initial.css', allChunks: true }),
new AssetsPlugin({ path: helpers.root('dist'), filename: 'webpack-assets.json', prettyPrint: true }),
new CheckerPlugin(),
new CommonsChunkPlugin({ name: 'polyfills', chunks: ['polyfills'] }),
new CommonsChunkPlugin({ name: 'vendor', chunks: ['main'], minChunks: module => /node_modules/.test(module.resource) }),
new CommonsChunkPlugin({ name: ['polyfills', 'vendor'].reverse() }),
new ContextReplacementPlugin( /angular(\|\/)core(\|\/)@angular/, helpers.root('src') ),
new CopyWebpackPlugin([{ from: 'src/assets', to: 'assets', }, { from: 'src/meta', }, ]),
new HtmlWebpackPlugin({ template: 'src/index.html', title: METADATA.title, chunksSortMode: 'dependency', metadata: METADATA, inject: 'head',
//csp: "default-src 'self'; child-src 'none'; object-src 'none'"
}),
new ScriptExtHtmlWebpackPlugin({ defaultAttribute: 'defer' }),
new HtmlElementsPlugin({ headTags: require('./head-config.common') }),
new LoaderOptionsPlugin({}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
}),
// Fix Angular 2
new NormalModuleReplacementPlugin( /facade(\|\/)async/, helpers.root('node_modules/@angular/core/src/facade/async.js') ),
new NormalModuleReplacementPlugin( /facade(\|\/)collection/, helpers.root('node_modules/@angular/core/src/facade/collection.js') ),
new NormalModuleReplacementPlugin( /facade(\|\/)errors/, helpers.root('node_modules/@angular/core/src/facade/errors.js') ),
new NormalModuleReplacementPlugin( /facade(\|\/)lang/, helpers.root('node_modules/@angular/core/src/facade/lang.js') ),
new NormalModuleReplacementPlugin( /facade(\|\/)math/, helpers.root('node_modules/@angular/core/src/facade/math.js') ),
],
node: { global: true, crypto: 'empty', process: true, module: false, clearImmediate: false, setImmediate: false }
};
}
config/webpack.prod.js:
const ENV = process.env.NODE_ENV = process.env.ENV = 'production';
const API_HOST = process.env.HOST || 'localhost';
const API_PORT = process.env.PORT || 8080;
const METADATA = webpackMerge(commonConfig({ env: ENV }).metadata, { API_HOST: API_HOST, API_PORT: API_PORT,
ENV: ENV, HMR: false
});
module.exports = function(env) {
return webpackMerge(commonConfig({ env: ENV }), {
devtool: 'source-map',
output: {
path: helpers.root('dist'),
filename: '[name].[chunkhash].bundle.js',
sourceMapFilename: '[name].[chunkhash].bundle.map',
chunkFilename: '[id].[chunkhash].chunk.js'
},
plugins: [
new WebpackMd5Hash(),
new DefinePlugin({'API_HOST': JSON.stringify(API_HOST), 'API_PORT': JSON.stringify(API_PORT),
'ENV': JSON.stringify(METADATA.ENV), 'NODE_ENV': JSON.stringify(METADATA.ENV), 'HMR': METADATA.HMR,
'process.env': {
'API_HOST': JSON.stringify(API_HOST), 'API_PORT': JSON.stringify(API_PORT),
'ENV': JSON.stringify(METADATA.ENV), 'NODE_ENV': JSON.stringify(METADATA.ENV), 'HMR': METADATA.HMR,
}
}),
new UglifyJsPlugin({
beautify: false, //prod
mangle: { screw_ie8: true, keep_fnames: true }, //prod
compress: { screw_ie8: true }, //prod
comments: false //prod
}),
new NormalModuleReplacementPlugin( /angular2-hmr/, helpers.root('config/modules/angular2-hmr-prod.js') ),
new LoaderOptionsPlugin({
debug: false,
options: {
tslint: { emitErrors: true, failOnHint: true, resourcePath: 'src' },
htmlLoader: { minimize: true, removeAttributeQuotes: false, caseSensitive: true,
customAttrSurround: [ [/#/, /(?:)/], [/\*/, /(?:)/], [/\[?\(?/, /(?:)/] ],
customAttrAssign: [/\)?\]?=/]
},
}
}),
],
node: { global: true, crypto: 'empty', process: false, module: false, clearImmediate: false, setImmediate: false }
});
}
Package.json:
{
"name": "angular2-webpack-starter",
"version": "5.1.1",
"description": "An Angular 2 Webpack Starter kit featuring Angular 2 (Router, Http, Forms, Services, Tests, E2E, Coverage), Karma, Protractor, Jasmine, Istanbul, TypeScript, and Webpack by AngularClass",
"keywords": [
"angular2",
"webpack",
"typescript"
],
"author": "Patrick Stapleton <patrick@angularclass.com>",
"homepage": "https://github.com/angularclass/angular2-webpack-starter",
"license": "MIT",
"scripts": {
"build:dev": "webpack --config config/webpack.dev.js --progress --profile",
"build:docker": "npm run build:prod && docker build -t angular2-webpack-start:latest .",
"build:prod": "webpack --config config/webpack.prod.js --progress --profile --bail",
"build": "npm run build:dev",
"ci": "npm run lint && npm test && npm run e2e",
"clean:dist": "npm run rimraf -- dist",
"clean:install": "npm set progress=false && npm install",
"clean:start": "npm start",
"clean": "npm cache clean && npm run rimraf -- node_modules dist",
"clean:aot": "npm run rimraf -- compiled",
"docker": "docker",
"docs": "npm run typedoc -- --options typedoc.json --exclude '**/*.spec.ts' ./src/",
"e2e:live": "npm run e2e -- --elementExplorer",
"e2e": "npm run protractor",
"github-deploy:dev": "webpack --config config/webpack.github-deploy.js --progress --profile --github-dev",
"github-deploy:prod": "webpack --config config/webpack.github-deploy.js --progress --profile --github-prod",
"github-deploy": "npm run github-deploy:dev",
"lint": "npm run tslint \"src/**/*.ts\"",
"postversion": "git push && git push --tags",
"prebuild:dev": "npm run clean:dist",
"prebuild:prod": "npm run clean:dist",
"preclean:install": "npm run clean",
"preclean:start": "npm run clean",
"pree2e": "npm run webdriver:update -- --standalone",
"preversion": "npm test",
"protractor": "protractor",
"rimraf": "rimraf",
"server:dev:hmr": "npm run server:dev -- --inline --hot",
"server:dev": "webpack-dev-server --config config/webpack.dev.js --progress --profile --watch --content-base src/",
"server:prod": "http-server dist --cors",
"server": "npm run server:dev",
"start:hmr": "npm run server:dev:hmr",
"start": "npm run server:dev",
"test": "karma start",
"tslint": "tslint",
"typedoc": "typedoc",
"version": "npm run build",
"watch:dev:hmr": "npm run watch:dev -- --hot",
"watch:dev": "npm run build:dev -- --watch",
"watch:prod": "npm run build:prod -- --watch",
"watch:test": "npm run test -- --auto-watch --no-single-run",
"watch": "npm run watch:dev",
"build:aot:prod": "npm run clean:dist && npm run clean:aot && webpack --config config/webpack.prod.js --progress --profile --bail",
"webdriver-manager": "webdriver-manager",
"webdriver:start": "npm run webdriver-manager start",
"webdriver:update": "npm run webdriver-manager update",
"webpack-dev-server": "webpack-dev-server",
"webpack": "webpack"
},
"dependencies": {
"@angular/animations": "^4.1.3",
"@angular/common": "4.1.3",
"@angular/compiler": "4.1.3",
"@angular/core": "4.1.3",
"@angular/forms": "^4.1.3",
"@angular/http": "4.1.3",
"@angular/platform-browser": "4.1.3",
"@angular/platform-browser-dynamic": "4.1.3",
"@angular/platform-server": "4.1.3",
"@angular/router": "4.1.3",
"@angularclass/conventions-loader": "^1.0.2",
"@angularclass/hmr": "~1.2.0",
"@angularclass/hmr-loader": "~3.0.2",
"animate.css": "^3.5.2",
"assets-webpack-plugin": "^3.4.0",
"bootstrap": "^4.0.0-alpha.6",
"bootstrap-loader": "^2.1.0",
"bootstrap-sass": "^3.3.7",
"core-js": "^2.4.1",
"error-stack-parser": "^2.0.1",
"extract-text-webpack-plugin": "^2.1.0",
"font-awesome": "^4.7.0",
"font-awesome-sass-loader": "^2.0.1",
"http-server": "^0.10.0",
"ie-shim": "^0.1.0",
"ionicons": "^3.0.0",
"jquery": "^3.2.1",
"lodash": "^4.17.4",
"ng-snotify": "^1.1.6",
"ngc-webpack": "^2.0.0",
"normalize.css": "^7.0.0",
"primeng": "^4.0.1",
"resolve-url-loader": "^2.0.2",
"rxjs": "^5.0.0-rc.1",
"sourcemapped-stacktrace": "^1.1.6",
"stacktrace-gps": "^3.0.1",
"stacktrace-js": "^2.0.0",
"zone.js": "~0.8.11"
},
"devDependencies": {
"@angular/cli": "^1.1.0",
"@angular/compiler-cli": "^4.1.3",
"@ngtools/webpack": "^1.4.1",
"@types/hammerjs": "^2.0.33",
"@types/jasmine": "^2.2.34",
"@types/node": "^7.0.22",
"@types/protractor": "^4.0.0",
"@types/selenium-webdriver": "3.0.4",
"@types/source-map": "^0.5.0",
"@types/uglify-js": "^2.0.27",
"@types/webpack": "^2.2.15",
"angular2-template-loader": "^0.6.0",
"awesome-typescript-loader": "^3.1.3",
"codelyzer": "~3.0.1",
"copy-webpack-plugin": "^4.0.0",
"css-loader": "^0.28.4",
"exports-loader": "^0.6.4",
"expose-loader": "^0.7.1",
"extract-text-webpack-plugin": "^2.1.0",
"file-loader": "^0.11.1",
"gh-pages": "^1.0.0",
"html-webpack-plugin": "^2.21.0",
"imports-loader": "^0.7.1",
"istanbul-instrumenter-loader": "^2.0.0",
"json-loader": "^0.5.4",
"karma": "^1.2.0",
"karma-chrome-launcher": "^2.0.0",
"karma-coverage": "^1.1.1",
"karma-jasmine": "^1.0.2",
"karma-mocha-reporter": "^2.0.0",
"karma-remap-coverage": "^0.1.1",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "2.0.3",
"ng-router-loader": "^2.1.0",
"node-sass": "^4.5.3",
"parse5": "^3.0.2",
"postcss-loader": "^2.0.5",
"protractor": "^5.1.2",
"raw-loader": "0.5.1",
"resolve-url-loader": "^2.0.2",
"rimraf": "^2.5.2",
"sass-loader": "^6.0.5",
"script-ext-html-webpack-plugin": "^1.3.2",
"source-map-loader": "^0.2.1",
"string-replace-loader": "1.2.0",
"style-loader": "^0.18.1",
"to-string-loader": "^1.1.4",
"ts-helpers": "1.1.2",
"ts-node": "^3.0.4",
"tslint": "^5.3.2",
"tslint-loader": "^3.5.3",
"typedoc": "^0.7.1",
"typescript": "2.3.4",
"url-loader": "^0.5.8",
"webpack": "^2.1.0-beta.25",
"webpack-dev-middleware": "^1.6.1",
"webpack-dev-server": "^2.1.0-beta.9",
"webpack-md5-hash": "^0.0.5",
"webpack-merge": "^4.1.0"
},
"repository": {
"type": "git",
"url": "https://github.com/angularclass/angular2-webpack-starter.git"
},
"bugs": {
"url": "https://github.com/angularclass/angular2-webpack-starter/issues"
},
"engines": {
"node": ">= 4.2.1",
"npm": ">= 3"
}
}
如@developer033 所述,在 运行ning npm run build:aot
之后,您应该 运行 npm run server:prod
到 运行 使用基于 dist 文件夹的文件。
app is running after running npm run server:prod, but how do I verify
if its AOT optimized
Angular 应用程序使用不同的方法来引导应用程序,具体取决于它是 AOT 还是 JIT 编译的。对于它使用的 JIT 编译应用程序:
bootstrapModule();
编译的AOT,使用:
bootstrapModuleFactory();
最简单的检查可能是检查加载到浏览器的 main.bundle.js
并查找这两个中的任何一个。
另一个选项可以简单地将编译器注入任何组件,可能是根组件,然后查看 Angular 是否报告错误,因为默认情况下 JIT 编译器不包含在包中。
更新:
正如@developer033 所指出的,ng2-admin 最近更新为 Angular-cli 而不是 angular2-webpack-starter。
原答案:
发布完整答案
运行 以下两个命令用于构建和 运行 服务器(如 @developer033 所述):
npm run build:prod (npm run clean:dist && npm run clean:aot && webpack --config config/webpack.prod.js --progress --profile --bail)
npm run server:prod
在我的例子中,我运行同时在不同的地址上同时构建 JIT 和 AOT:
http://127.0.0.1:8080 是 JIT,其余是 AOT
要验证您的构建是否为 AOT,请按照@Maximus 所述检查您的主捆绑包文件。您也可以暂时禁用 UglifyJsPlugin 优化代码以检查主包 js。
最后我在 AOT 构建中遇到以下错误:
"Uncaught TypeError: Cannot read property 'setGlobalVar' of null"
为了解决这个问题,我简单地评论了 disableDebugTools();在我的 environment.ts 文件中。
注:
我使用 angular2-webpack-starter and for AOT I referred ng2-admin
创建了项目模板
更新
@developer033 提到后,我是 运行ning npm 运行 server:prod 和应用 运行 处于生产模式。但我不确定,如何验证它是否经过 AOT 优化?
如果我检查 main.bundle.js 以检查它是否有 main.browser.aot.ts 的代码:
我看到的是 main.browser.ts 而不是 main.browser.aot.ts 所以我不确定我是否使用 AOT 构建。
原版Post
好的,我可以使用 Webpack 在 AOT 模式下编译我的 Angular2 项目,它创建了两个文件夹,一个是 "dist",另一个是 "compiled",但我不确定如何 运行编译后的AOT工程
构建命令:
"build:aot:prod": "npm run clean:dist && npm run clean:aot && webpack --config config/webpack.prod.js --progress --profile --bail"
编译后,我运行命令:
npm run webpack-dev-server
现在应用程序 运行s 但我不确定它是否甚至使用 AOT 编译代码。我在浏览器中看到 AOT 和非 AOT 应用程序没有区别。
AOT:
没有 AOT:
tsconfig.webpack.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true,
"baseUrl": "./src",
"outDir": "compiled",
"paths": {},
"lib": [
"es2015",
"dom"
],
"typeRoots": [
"node_modules/@types"
]
},
"exclude": [
"node_modules",
"dist",
"compiled",
"src/**/*.spec.ts",
"src/**/*.e2e.ts"
],
"awesomeTypescriptLoaderOptions": {
"forkChecker": true,
"useWebpackText": true
},
"angularCompilerOptions": {
"genDir": "compiled",
"skipMetadataEmit": true
},
"compileOnSave": false,
"buildOnSave": false,
"atom": {
"rewriteTsconfig": false
}
}
main.browser.aot.ts:
import { platformBrowser } from '@angular/platform-browser';
import { decorateModuleRef } from './app/environment';
import { enableProdMode } from '@angular/core';
import { AppModuleNgFactory } from '../compiled/src/app/app.module.ngfactory';
if (ENV.toLocaleLowerCase() === 'production' || ENV.toLocaleLowerCase() === 'prod') {
enableProdMode();
}
export function main(): Promise<any> {
return platformBrowser()
.bootstrapModuleFactory(AppModuleNgFactory)
.then(decorateModuleRef)
.catch(err => console.error(err));
}
export function bootstrapDomReady() {
document.addEventListener('DOMContentLoaded', main);
}
bootstrapDomReady();
config/webpack.common.js:
const HMR = helpers.hasProcessFlag('hot');
const AOT = helpers.hasNpmFlag('aot');
const METADATA = {
title: 'Angular2 Webpack Starter by @gdi2290 from @AngularClass',
baseUrl: '/',
isDevServer: helpers.isWebpackDevServer()
};
module.exports = function(options) {
isProd = options.env === 'production';
return {
entry: {
'polyfills': './src/polyfills.browser.ts',
'vendor': './src/vendor.browser.ts',
'main': AOT ? './src/main.browser.aot.ts' : './src/main.browser.ts'
},
resolve: { extensions: ['.ts', '.js', '.json', '.css', '.scss'], modules: [helpers.root('src'), 'node_modules'], },
module: {
rules: [
{
test: /\.ts$/,
loaders: [
'@angularclass/hmr-loader?pretty=' + !isProd + '&prod=' + isProd,
'awesome-typescript-loader',
{ loader: 'ng-router-loader', options: { loader: 'async-import', genDir: 'compiled', aot: AOT } },
'angular2-template-loader'
],
exclude: [/\.(spec|e2e)\.ts$/]
},
{
test: /\.scss$/,
exclude: /node_modules/,
loaders: ['raw-loader', 'sass-loader'] // sass-loader not scss-loader
},{ test: /\.json$/, loader: 'json-loader'},
{ test: /\.woff(2)?(\?v=.+)?$/, use: 'url-loader?limit=10000&mimetype=application/font-woff' },
{ test: /\.(ttf|eot|svg)(\?v=.+)?$/, use: 'file-loader' },
{ test: /bootstrap\/dist\/js\/umd\//, use: 'imports-loader?jQuery=jquery' },
{ test: /\.html$/, loader: 'raw-loader', exclude: [helpers.root('src/index.html')] },
{ test: /\.(jpg|png|gif)$/, loader: 'file' },
],
},
plugins: [
new ngcWebpack.NgcWebpackPlugin({
disabled: !AOT,
tsConfig: helpers.root('tsconfig.webpack.json'),
resourceOverride: helpers.root('config/resource-override.js')
}),
new ExtractTextPlugin({ filename: 'initial.css', allChunks: true }),
new AssetsPlugin({ path: helpers.root('dist'), filename: 'webpack-assets.json', prettyPrint: true }),
new CheckerPlugin(),
new CommonsChunkPlugin({ name: 'polyfills', chunks: ['polyfills'] }),
new CommonsChunkPlugin({ name: 'vendor', chunks: ['main'], minChunks: module => /node_modules/.test(module.resource) }),
new CommonsChunkPlugin({ name: ['polyfills', 'vendor'].reverse() }),
new ContextReplacementPlugin( /angular(\|\/)core(\|\/)@angular/, helpers.root('src') ),
new CopyWebpackPlugin([{ from: 'src/assets', to: 'assets', }, { from: 'src/meta', }, ]),
new HtmlWebpackPlugin({ template: 'src/index.html', title: METADATA.title, chunksSortMode: 'dependency', metadata: METADATA, inject: 'head',
//csp: "default-src 'self'; child-src 'none'; object-src 'none'"
}),
new ScriptExtHtmlWebpackPlugin({ defaultAttribute: 'defer' }),
new HtmlElementsPlugin({ headTags: require('./head-config.common') }),
new LoaderOptionsPlugin({}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery",
}),
// Fix Angular 2
new NormalModuleReplacementPlugin( /facade(\|\/)async/, helpers.root('node_modules/@angular/core/src/facade/async.js') ),
new NormalModuleReplacementPlugin( /facade(\|\/)collection/, helpers.root('node_modules/@angular/core/src/facade/collection.js') ),
new NormalModuleReplacementPlugin( /facade(\|\/)errors/, helpers.root('node_modules/@angular/core/src/facade/errors.js') ),
new NormalModuleReplacementPlugin( /facade(\|\/)lang/, helpers.root('node_modules/@angular/core/src/facade/lang.js') ),
new NormalModuleReplacementPlugin( /facade(\|\/)math/, helpers.root('node_modules/@angular/core/src/facade/math.js') ),
],
node: { global: true, crypto: 'empty', process: true, module: false, clearImmediate: false, setImmediate: false }
};
}
config/webpack.prod.js:
const ENV = process.env.NODE_ENV = process.env.ENV = 'production';
const API_HOST = process.env.HOST || 'localhost';
const API_PORT = process.env.PORT || 8080;
const METADATA = webpackMerge(commonConfig({ env: ENV }).metadata, { API_HOST: API_HOST, API_PORT: API_PORT,
ENV: ENV, HMR: false
});
module.exports = function(env) {
return webpackMerge(commonConfig({ env: ENV }), {
devtool: 'source-map',
output: {
path: helpers.root('dist'),
filename: '[name].[chunkhash].bundle.js',
sourceMapFilename: '[name].[chunkhash].bundle.map',
chunkFilename: '[id].[chunkhash].chunk.js'
},
plugins: [
new WebpackMd5Hash(),
new DefinePlugin({'API_HOST': JSON.stringify(API_HOST), 'API_PORT': JSON.stringify(API_PORT),
'ENV': JSON.stringify(METADATA.ENV), 'NODE_ENV': JSON.stringify(METADATA.ENV), 'HMR': METADATA.HMR,
'process.env': {
'API_HOST': JSON.stringify(API_HOST), 'API_PORT': JSON.stringify(API_PORT),
'ENV': JSON.stringify(METADATA.ENV), 'NODE_ENV': JSON.stringify(METADATA.ENV), 'HMR': METADATA.HMR,
}
}),
new UglifyJsPlugin({
beautify: false, //prod
mangle: { screw_ie8: true, keep_fnames: true }, //prod
compress: { screw_ie8: true }, //prod
comments: false //prod
}),
new NormalModuleReplacementPlugin( /angular2-hmr/, helpers.root('config/modules/angular2-hmr-prod.js') ),
new LoaderOptionsPlugin({
debug: false,
options: {
tslint: { emitErrors: true, failOnHint: true, resourcePath: 'src' },
htmlLoader: { minimize: true, removeAttributeQuotes: false, caseSensitive: true,
customAttrSurround: [ [/#/, /(?:)/], [/\*/, /(?:)/], [/\[?\(?/, /(?:)/] ],
customAttrAssign: [/\)?\]?=/]
},
}
}),
],
node: { global: true, crypto: 'empty', process: false, module: false, clearImmediate: false, setImmediate: false }
});
}
Package.json:
{
"name": "angular2-webpack-starter",
"version": "5.1.1",
"description": "An Angular 2 Webpack Starter kit featuring Angular 2 (Router, Http, Forms, Services, Tests, E2E, Coverage), Karma, Protractor, Jasmine, Istanbul, TypeScript, and Webpack by AngularClass",
"keywords": [
"angular2",
"webpack",
"typescript"
],
"author": "Patrick Stapleton <patrick@angularclass.com>",
"homepage": "https://github.com/angularclass/angular2-webpack-starter",
"license": "MIT",
"scripts": {
"build:dev": "webpack --config config/webpack.dev.js --progress --profile",
"build:docker": "npm run build:prod && docker build -t angular2-webpack-start:latest .",
"build:prod": "webpack --config config/webpack.prod.js --progress --profile --bail",
"build": "npm run build:dev",
"ci": "npm run lint && npm test && npm run e2e",
"clean:dist": "npm run rimraf -- dist",
"clean:install": "npm set progress=false && npm install",
"clean:start": "npm start",
"clean": "npm cache clean && npm run rimraf -- node_modules dist",
"clean:aot": "npm run rimraf -- compiled",
"docker": "docker",
"docs": "npm run typedoc -- --options typedoc.json --exclude '**/*.spec.ts' ./src/",
"e2e:live": "npm run e2e -- --elementExplorer",
"e2e": "npm run protractor",
"github-deploy:dev": "webpack --config config/webpack.github-deploy.js --progress --profile --github-dev",
"github-deploy:prod": "webpack --config config/webpack.github-deploy.js --progress --profile --github-prod",
"github-deploy": "npm run github-deploy:dev",
"lint": "npm run tslint \"src/**/*.ts\"",
"postversion": "git push && git push --tags",
"prebuild:dev": "npm run clean:dist",
"prebuild:prod": "npm run clean:dist",
"preclean:install": "npm run clean",
"preclean:start": "npm run clean",
"pree2e": "npm run webdriver:update -- --standalone",
"preversion": "npm test",
"protractor": "protractor",
"rimraf": "rimraf",
"server:dev:hmr": "npm run server:dev -- --inline --hot",
"server:dev": "webpack-dev-server --config config/webpack.dev.js --progress --profile --watch --content-base src/",
"server:prod": "http-server dist --cors",
"server": "npm run server:dev",
"start:hmr": "npm run server:dev:hmr",
"start": "npm run server:dev",
"test": "karma start",
"tslint": "tslint",
"typedoc": "typedoc",
"version": "npm run build",
"watch:dev:hmr": "npm run watch:dev -- --hot",
"watch:dev": "npm run build:dev -- --watch",
"watch:prod": "npm run build:prod -- --watch",
"watch:test": "npm run test -- --auto-watch --no-single-run",
"watch": "npm run watch:dev",
"build:aot:prod": "npm run clean:dist && npm run clean:aot && webpack --config config/webpack.prod.js --progress --profile --bail",
"webdriver-manager": "webdriver-manager",
"webdriver:start": "npm run webdriver-manager start",
"webdriver:update": "npm run webdriver-manager update",
"webpack-dev-server": "webpack-dev-server",
"webpack": "webpack"
},
"dependencies": {
"@angular/animations": "^4.1.3",
"@angular/common": "4.1.3",
"@angular/compiler": "4.1.3",
"@angular/core": "4.1.3",
"@angular/forms": "^4.1.3",
"@angular/http": "4.1.3",
"@angular/platform-browser": "4.1.3",
"@angular/platform-browser-dynamic": "4.1.3",
"@angular/platform-server": "4.1.3",
"@angular/router": "4.1.3",
"@angularclass/conventions-loader": "^1.0.2",
"@angularclass/hmr": "~1.2.0",
"@angularclass/hmr-loader": "~3.0.2",
"animate.css": "^3.5.2",
"assets-webpack-plugin": "^3.4.0",
"bootstrap": "^4.0.0-alpha.6",
"bootstrap-loader": "^2.1.0",
"bootstrap-sass": "^3.3.7",
"core-js": "^2.4.1",
"error-stack-parser": "^2.0.1",
"extract-text-webpack-plugin": "^2.1.0",
"font-awesome": "^4.7.0",
"font-awesome-sass-loader": "^2.0.1",
"http-server": "^0.10.0",
"ie-shim": "^0.1.0",
"ionicons": "^3.0.0",
"jquery": "^3.2.1",
"lodash": "^4.17.4",
"ng-snotify": "^1.1.6",
"ngc-webpack": "^2.0.0",
"normalize.css": "^7.0.0",
"primeng": "^4.0.1",
"resolve-url-loader": "^2.0.2",
"rxjs": "^5.0.0-rc.1",
"sourcemapped-stacktrace": "^1.1.6",
"stacktrace-gps": "^3.0.1",
"stacktrace-js": "^2.0.0",
"zone.js": "~0.8.11"
},
"devDependencies": {
"@angular/cli": "^1.1.0",
"@angular/compiler-cli": "^4.1.3",
"@ngtools/webpack": "^1.4.1",
"@types/hammerjs": "^2.0.33",
"@types/jasmine": "^2.2.34",
"@types/node": "^7.0.22",
"@types/protractor": "^4.0.0",
"@types/selenium-webdriver": "3.0.4",
"@types/source-map": "^0.5.0",
"@types/uglify-js": "^2.0.27",
"@types/webpack": "^2.2.15",
"angular2-template-loader": "^0.6.0",
"awesome-typescript-loader": "^3.1.3",
"codelyzer": "~3.0.1",
"copy-webpack-plugin": "^4.0.0",
"css-loader": "^0.28.4",
"exports-loader": "^0.6.4",
"expose-loader": "^0.7.1",
"extract-text-webpack-plugin": "^2.1.0",
"file-loader": "^0.11.1",
"gh-pages": "^1.0.0",
"html-webpack-plugin": "^2.21.0",
"imports-loader": "^0.7.1",
"istanbul-instrumenter-loader": "^2.0.0",
"json-loader": "^0.5.4",
"karma": "^1.2.0",
"karma-chrome-launcher": "^2.0.0",
"karma-coverage": "^1.1.1",
"karma-jasmine": "^1.0.2",
"karma-mocha-reporter": "^2.0.0",
"karma-remap-coverage": "^0.1.1",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "2.0.3",
"ng-router-loader": "^2.1.0",
"node-sass": "^4.5.3",
"parse5": "^3.0.2",
"postcss-loader": "^2.0.5",
"protractor": "^5.1.2",
"raw-loader": "0.5.1",
"resolve-url-loader": "^2.0.2",
"rimraf": "^2.5.2",
"sass-loader": "^6.0.5",
"script-ext-html-webpack-plugin": "^1.3.2",
"source-map-loader": "^0.2.1",
"string-replace-loader": "1.2.0",
"style-loader": "^0.18.1",
"to-string-loader": "^1.1.4",
"ts-helpers": "1.1.2",
"ts-node": "^3.0.4",
"tslint": "^5.3.2",
"tslint-loader": "^3.5.3",
"typedoc": "^0.7.1",
"typescript": "2.3.4",
"url-loader": "^0.5.8",
"webpack": "^2.1.0-beta.25",
"webpack-dev-middleware": "^1.6.1",
"webpack-dev-server": "^2.1.0-beta.9",
"webpack-md5-hash": "^0.0.5",
"webpack-merge": "^4.1.0"
},
"repository": {
"type": "git",
"url": "https://github.com/angularclass/angular2-webpack-starter.git"
},
"bugs": {
"url": "https://github.com/angularclass/angular2-webpack-starter/issues"
},
"engines": {
"node": ">= 4.2.1",
"npm": ">= 3"
}
}
如@developer033 所述,在 运行ning npm run build:aot
之后,您应该 运行 npm run server:prod
到 运行 使用基于 dist 文件夹的文件。
app is running after running npm run server:prod, but how do I verify if its AOT optimized
Angular 应用程序使用不同的方法来引导应用程序,具体取决于它是 AOT 还是 JIT 编译的。对于它使用的 JIT 编译应用程序:
bootstrapModule();
编译的AOT,使用:
bootstrapModuleFactory();
最简单的检查可能是检查加载到浏览器的 main.bundle.js
并查找这两个中的任何一个。
另一个选项可以简单地将编译器注入任何组件,可能是根组件,然后查看 Angular 是否报告错误,因为默认情况下 JIT 编译器不包含在包中。
更新:
正如@developer033 所指出的,ng2-admin 最近更新为 Angular-cli 而不是 angular2-webpack-starter。
原答案:
发布完整答案
运行 以下两个命令用于构建和 运行 服务器(如 @developer033 所述):
npm run build:prod (npm run clean:dist && npm run clean:aot && webpack --config config/webpack.prod.js --progress --profile --bail)
npm run server:prod
在我的例子中,我运行同时在不同的地址上同时构建 JIT 和 AOT:
http://127.0.0.1:8080 是 JIT,其余是 AOT
要验证您的构建是否为 AOT,请按照@Maximus 所述检查您的主捆绑包文件。您也可以暂时禁用 UglifyJsPlugin 优化代码以检查主包 js。
最后我在 AOT 构建中遇到以下错误:
"Uncaught TypeError: Cannot read property 'setGlobalVar' of null"
为了解决这个问题,我简单地评论了 disableDebugTools();在我的 environment.ts 文件中。
注:
我使用 angular2-webpack-starter and for AOT I referred ng2-admin