我正在使用混合Angular应用处理性能问题。 它在3s左右自举。而且我注意到AoT没有运行(捆绑包中有JIT编译器)。 我正在使用@ ngtools / webpack loader和AngularCompilerPlugin,它们应该处理AoT,但不会。 无法弄清楚我的配置有什么问题。
版本:
角度6.1.2
Angular.js 1.7.3
Webpack 4.16.5
webpack.common.js
const webpack = require('webpack');
const helper = require('./helper');
const outputDir = helper.root('build-webpack');
const postcssPlugins = require('./postcss');
const rxPaths = require('rxjs/_esm5/path-mapping');
const entryPoints = ['inline', 'polyfills', 'sw-register', 'styles', 'vendor', 'main'];
const convertPathsToAliases = require('convert-tsconfig-paths-to-webpack-aliases').default;
const tsconfig = require(helper.root('tsconfig.json'));
const aliases = convertPathsToAliases(tsconfig);
const CircularDependencyPlugin = require('circular-dependency-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const copyWebpackOptions = [
{
from: helper.root('src/content/fonts'),
to: `${outputDir}/content/fonts`
},
{
from: helper.root('src/content/assets'),
to: `${outputDir}/content/assets`
},
{
from: helper.root('src/content/img'),
to: `${outputDir}/content/img`
},
{
from: helper.root('src/content/toc'),
to: `${outputDir}/content/toc`
}
];
module.exports = (env) => {
const babelLoader = {
loader: 'babel-loader',
options: {
// annotate for Angular.js code to be minified
plugins: env.optimize ? [require('babel-plugin-angularjs-annotate')] : [],
presets: [
[
'@babel/preset-env',
{
shippedProposals: true,
sourceMaps: false,
targets: { browsers: ['ie >= 11'] },
useBuiltIns: 'usage'
}
]
]
}
};
return {
entry: {
main: ['main.ts'],
polyfills: ['polyfills.ts'],
styles: ['less/styles.less']
},
mode: 'development',
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif|woff|woff2)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: '[name].[hash:20].[ext]'
}
}
]
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
use: [
{
loader: 'file-loader',
options: {
limit: 10000,
name: '/content/fonts/[name].[hash:20].[ext]'
}
}
]
},
{
test: /\.tpl.html/,
use: [
'ngtemplate-loader',
{
loader: 'html-loader',
options: { minimize: true }
},
{
loader: 'html-minifier-loader',
options: { collapseWhitespace: true }
}
]
},
{
exclude: [
helper.root('src/less/styles.less')
],
test: /\.css$/,
use: [
{ loader: 'raw-loader' },
{
loader: 'postcss-loader',
options: {
ident: 'embedded',
plugins: postcssPlugins,
sourceMap: true
}
}
]
},
{
exclude: [
helper.root('src/less/styles.less')
],
test: /\.less$/,
use: [
{ loader: 'raw-loader' },
{
loader: 'postcss-loader',
options: {
ident: 'embedded',
plugins: postcssPlugins,
sourceMap: true
}
},
{
loader: 'less-loader',
options: { sourceMap: true }
}
]
},
{
include: [
helper.root('src/less/styles.less')
],
test: /\.css$/,
use: [
'style-loader',
{ loader: 'raw-loader' },
{
loader: 'postcss-loader',
options: {
ident: 'embedded',
plugins: postcssPlugins,
sourceMap: true
}
}
]
},
{
include: [
helper.root('src/less/styles.less')
],
test: /\.less$/,
use: [
'style-loader',
{ loader: 'raw-loader' },
{
loader: 'postcss-loader',
options: {
ident: 'embedded',
plugins: postcssPlugins,
sourceMap: true
}
},
{
loader: 'less-loader',
options: { sourceMap: true }
}
]
},
{
exclude: /node_modules/,
test: /\.ts$/,
use: [
// 'cache-loader',
babelLoader,
'@ngtools/webpack'
]
},
{
exclude: /node_modules/,
test: /\.js$/,
use: [
// 'cache-loader',
babelLoader
]
}
]
},
node: {
clearImmediate: false,
crypto: 'empty',
fs: 'empty',
global: true,
module: false,
net: 'empty',
process: true,
setImmediate: false,
tls: 'empty'
},
output: {
chunkFilename: 'scripts/[id].[hash].chunk.js',
crossOriginLoading: false,
filename: 'scripts/[name].[hash].bundle.js',
path: outputDir
},
plugins: [
new CopyWebpackPlugin(copyWebpackOptions),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.ProgressPlugin(),
new CircularDependencyPlugin({
cwd: process.cwd(),
exclude: /(\\|\/)node_modules(\\|\/)/,
failOnError: false,
onDetected: false
}),
new HtmlWebpackPlugin({
cache: true,
chunks: 'all',
chunksSortMode: (left, right) => {
const leftIdx = entryPoints.indexOf(left.names[0]);
const rightIdx = entryPoints.indexOf(right.names[0]);
if (leftIdx > rightIdx) {
return 1;
} else if (leftIdx < rightIdx) {
return -1;
}
return 0;
},
compile: true,
excludeChunks: [],
favicon: false,
filename: 'index.html',
hash: false,
inject: true,
// HTML minification
minify: env.optimize ? {
collapseWhitespace: true,
html5: true,
minifyCSS: true,
preserveLineBreaks: false,
removeAttributeQuotes: true,
removeComments: true
} : false,
showErrors: true,
template: './src/index.pug'
}),
new webpack.NamedModulesPlugin({}),
new webpack.ProvidePlugin({
$: 'jquery',
_: 'underscore',
jQuery: 'jquery',
moment: 'moment',
'window.jQuery': 'jquery'
}),
// Ignore moment locales (https://github.com/moment/moment/issues/4025)
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
],
resolve: {
alias: {
...rxPaths(),
...aliases
},
// note that .ts extension should be before .js
// https://github.com/angular/angular-cli/issues/8508
extensions: [
'.ts',
'.js'
],
mainFields: [
'browser',
'module',
'main'
],
modules: [helper.root('node_modules'), helper.root('src')],
symlinks: true
},
resolveLoader: {
alias: rxPaths(),
modules: [helper.root('node_modules')]
},
target: 'web'
};
};
webpack.prod.js
const { AngularCompilerPlugin } = require('@ngtools/webpack');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const webpackMerge = require('webpack-merge');
const commonConfig = require('./webpack.common');
const RobotstxtPlugin = require('robotstxt-webpack-plugin').default;
// load configs
console.log('loading prod config');
module.exports = (env) => {
env = env ? env : {};
return webpackMerge(commonConfig(env), {
devtool: false,
mode: 'production',
module: {
rules: [
{
test: /\.pug$/,
use: [
'raw-loader',
{
loader: 'pug-html-loader',
options: { data: { gtmAccountId: '"GTM-5DR847C"' }, doctype: 'html' }
}
]
}
]
},
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true,
uglifyOptions: {
output: {
beautify: false,
comments: false
},
warnings: false
}
})
]
},
plugins: [
new AngularCompilerPlugin({
compilerOptions: {},
hostReplacementPaths: { 'config/index.ts': 'config/prod.ts' },
mainPath: 'main.ts',
platform: 0,
skipCodeGeneration: true,
sourceMap: true,
tsConfigPath: 'src/tsconfig.app.json'
})
]
});
};
tsconfig.app.json
{
"extends": "../tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": false,
"forceConsistentCasingInFileNames": false,
"module": "es2015",
"newLine": "lf",
"noImplicitAny": true,
"removeComments": true
},
"exclude": [
"test.ts",
"**/*.spec.ts",
"tests/index.js",
"**/*.spec.js"
]
}
main.ts
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { setAngularLib } from '@angular/upgrade/static';
import { AppModule } from '@crexi/app.module';
import { config } from '@crexi/config';
import { UrlService } from '@uirouter/core';
import angular from 'angular';
setAngularLib(angular);
if (config.production) {
enableProdMode();
}
// We delay bootstrapping so the browser has time to render the splash screen. Doing so
// within requestAnimationFrame and setTimeout minimizes that delay.
requestAnimationFrame(() => {
setTimeout(() => {
platformBrowserDynamic().bootstrapModule(AppModule)
.then((platformRef) => {
const url: UrlService = platformRef.injector.get(UrlService);
url.listen();
url.sync();
})
.catch((err) => {
console.log(err);
});
}, 0);
});
app.module.ts(摘录)
export class AppModule {
constructor (private upgrade: UpgradeModule) {}
ngDoBootstrap () {
downgrades();
this.upgrade.bootstrap(document.documentElement, ['crexi']);
}
}