您好,登錄后才能下訂單哦!
今天小編給大家分享一下Angular13+開發模式太慢如何解決的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
近期在某個高頻迭代七年的 Angular 項目升級至 Angular 13 后,其開發模式的構建速度慢、資源占用高,開發體驗相當差。在一臺僅在開會時偶爾使用的 Macbook air
(近期居家辦公期間轉換為了主要生產力工具) 中啟動構建時,它的風扇會呼呼作響,CPU 負荷被打滿,而在構建完成后,熱更新一次的時間在一分鐘以上。
在經過各種原因分析與排查后,最終在 angular.json
的 schema(./node_modules/@angular/cli/lib/config/schema.json
) 中發現了問題,再結合 Angular 12 release 文檔定位到了具體原因: Angular 12 一個主要的改動是將 aot
、buildOptimizer
、optimization
等參數由默認值 false
改為了 true
。
A number of browser and server builder options have had their default values changed. The aim of these changes is to reduce the configuration complexity and support the new "production builds by default" initiative.
可以看到 Angular 12 后的默認生產模式,對于跨版本升級來說是比較坑爹的。
解決辦法則是在 development
配置中禁用生產模式相關的配置項。示例:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"projects": {
"front": {
"architect": {
"build": {
"configurations": {
"development": {
"tsConfig": "./tsconfig.dev.json",
"aot": false,
"buildOptimizer": false,
"optimization": false,
"extractLicenses": false,
"sourceMap": true,
"vendorChunk": true,
"namedChunks": true
}
}
},
}
},
"defaultProject": "front"
}
需注意 aot
開啟與關閉時,在構建結果表現上可能會有一些差異,需視具體問題而分析。
aot
后 pug
編譯報錯該項目中使用 pug
開發 html 內容。關閉 aot
時構建正常,開啟后則會報錯。
根據報錯內容及位置進行 debugger 調試,可以看到其編譯結果為一個 esModule 的對象。這是由于使用了 raw-loader
,其編譯結果默認為 esModule
模式,禁用 esModule
配置項即可。示例(自定義 webpack 配置可參考下文的 dll 配置相關示例):
{
test: /\.pug$/,
use: [
{
loader: 'raw-loader',
options: {
esModule: false,
},
},
{
loader: 'pug-html-loader',
options: {
doctype: 'html',
},
},
],
},
該項目項目構建上有自定義 webpack
配置的需求,使用了 @angular-builders/custom-webpack
庫實現,但是沒有配置 dll。
Angular
提供了 vendorChunk
參數,開啟它會提取在 package.json
中的依賴等公共資源至獨立 chunk 中,其可以很好的解決熱更新 bundles 過大導致熱更新太慢等的問題,但仍然存在較高的內存占用,而且實際的對比測試中,在存在 webpack5 緩存的情況下,其相比 dll 模式的構建編譯速度以及熱更新速度都稍微慢一些。故對于開發機器性能一般的情況下,給開發模式配置 dll 是會帶來一定的收益的。
首先需要配置自定義 webpack 配置的構建支持。執行如下命令添加依賴:
npm i -D @angular-builders/custom-webpack
修改 angluar.json
配置。內容格式參考:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"cli": {
"analytics": false,
"cache": {
"path": "node_modules/.cache/ng"
}
},
"version": 1,
"newProjectRoot": "projects",
"projects": {
"front": {
"root": "",
"sourceRoot": "src",
"projectType": "application",
"prefix": "app",
"schematics": {
"@schematics/angular:component": {
"style": "less"
}
},
"architect": {
"build": {
"builder": "@angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./webpack.config.js"
},
"indexTransform": "scripts/index-html-transform.js",
"outputHashing": "media",
"deleteOutputPath": true,
"watch": true,
"sourceMap": false,
"outputPath": "dist/dev",
"index": "src/index.html",
"main": "src/app-main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "./tsconfig.app.json",
"baseHref": "./",
"assets": [
"src/assets/",
{
"glob": "**/*",
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
"output": "/assets/"
}
],
"styles": [
"node_modules/angular-tree-component/dist/angular-tree-component.css",
"src/css/index.less"
],
"scripts": []
},
"configurations": {
"development": {
"tsConfig": "./tsconfig.dev.json",
"buildOptimizer": false,
"optimization": false,
"aot": false,
"extractLicenses": false,
"sourceMap": true,
"vendorChunk": true,
"namedChunks": true,
"scripts": [
{
"inject": true,
"input": "./dist/dll/dll.js",
"bundleName": "dll_library"
}
]
},
"production": {
"outputPath": "dist/prod",
"baseHref": "./",
"watch": false,
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": {
"scripts": true,
"styles": {
"minify": true,
"inlineCritical": false
},
"fonts": true
},
"outputHashing": "all",
"sourceMap": false,
"namedChunks": false,
"aot": true,
"extractLicenses": false,
"vendorChunk": false,
"buildOptimizer": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-builders/custom-webpack:dev-server",
"options": {
"browserTarget": "front:build",
"liveReload": false,
"open": false,
"host": "0.0.0.0",
"port": 3002,
"servePath": "/",
"publicHost": "localhost.gf.com.cn",
"proxyConfig": "config/ngcli-proxy-config.js",
"disableHostCheck": true
},
"configurations": {
"production": {
"browserTarget": "front:build:production"
},
"development": {
"browserTarget": "front:build:development"
}
},
"defaultConfiguration": "development"
},
"test": {
"builder": "@angular-builders/custom-webpack:karma",
"options": {
"customWebpackConfig": {
"path": "./webpack.test.config.js"
},
"indexTransform": "scripts/index-html-transform.js",
"main": "src/ngtest.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "./tsconfig.spec.json",
"karmaConfig": "./karma.conf.js",
"assets": [
"src/assets/",
{
"glob": "**/*",
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
"output": "/assets/"
}
],
"styles": [
"node_modules/angular-tree-component/dist/angular-tree-component.css",
"src/css/index.less"
],
"scripts": []
}
}
}
}
},
"defaultProject": "front",
"schematics": {
"@schematics/angular:module": {
"routing": true,
"spec": false
},
"@schematics/angular:component": {
"flat": false,
"inlineStyle": true,
"inlineTemplate": false
}
}
}
該示例中涉及多處自定義配置內容,主要需注意 webpack 相關的部分, 其他內容可視自身項目具體情況對比參考。
新建 webpack.config.js
文件。內容參考:
const { existsSync } = require('node:fs');
const { resolve } = require('node:path');
const webpack = require('webpack');
// require('events').EventEmitter.defaultMaxListeners = 0;
/**
* @param {import('webpack').Configuration} config
* @param {import('@angular-builders/custom-webpack').CustomWebpackBrowserSchema} options
* @param {import('@angular-builders/custom-webpack').TargetOptions} targetOptions
*/
module.exports = (config, options, targetOptions) => {
if (!config.devServer) config.devServer = {};
config.plugins.push(
new webpack.DefinePlugin({ LZWME_DEV: config.mode === 'development' }),
);
const dllDir = resolve(__dirname, './dist/dll');
if (
existsSync(dllDir) &&
config.mode === 'development' &&
options.scripts?.some((d) => d.bundleName === 'dll_library')
) {
console.log('use dll:', dllDir);
config.plugins.unshift(
new webpack.DllReferencePlugin({
manifest: require(resolve(dllDir, 'dll-manifest.json')),
context: __dirname,
})
);
}
config.module.rules = config.module.rules.filter((d) => {
if (d.test instanceof RegExp) {
// 使用 less,移除 sass/stylus loader
return !(d.test.test('x.sass') || d.test.test('x.scss') || d.test.test('x.styl'));
}
return true;
});
config.module.rules.unshift(
{
test: /\.pug$/,
use: [
{
loader: 'raw-loader',
options: {
esModule: false,
},
},
{
loader: 'pug-html-loader',
options: {
doctype: 'html',
},
},
],
},
{
test: /\.html$/,
loader: 'raw-loader',
exclude: [helpers.root('src/index.html')],
},
{
test: /\.svg$/,
loader: 'raw-loader',
},
{
test: /\.(t|les)s/,
loader: require.resolve('@lzwme/strip-loader'),
exclude: /node_modules/,
options: {
disabled: config.mode !== 'production',
},
}
);
// AngularWebpackPlugin,用于自定義 index.html 處理插件
const awPlugin = config.plugins.find((p) => p.options?.hasOwnProperty('directTemplateLoading'));
if (awPlugin) awPlugin.pluginOptions.directTemplateLoading = false;
// 兼容上古遺傳邏輯,禁用部分插件
config.plugins = config.plugins.filter((plugin) => {
const pluginName = plugin.constructor.name;
if (/CircularDependency|CommonJsUsageWarnPlugin/.test(pluginName)) {
console.log('[webpack][plugin] disabled: ', pluginName);
return false;
}
return true;
});
// console.log('[webpack][config]', config.mode, config, options, targetOptions);
return config;
};
新建 webpack.dll.mjs
文件,用于 dll 構建。內容示例:
import { join } from 'node:path';
import webpack from 'webpack';
const rootDir = process.cwd();
const isDev = process.argv.slice(2).includes('--dev') || process.env.NODE_ENV === 'development';
/** @type {import('webpack').Configuration} */
const config = {
context: rootDir,
mode: isDev ? 'development' : 'production',
entry: {
dll: [
'@angular/common',
'@angular/core',
'@angular/forms',
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@angular/router',
'@lzwme/asmd-calc',
// more...
],
},
output: {
path: join(rootDir, 'dist/dll'),
filename: 'dll.js',
library: '[name]_library',
},
plugins: [
new webpack.DllPlugin({
path: join(rootDir, 'dist/dll/[name]-manifest.json'),
name: '[name]_library',
}),
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/,
}),
],
cache: { type: 'filesystem' },
};
webpack(config).run((err, result) => {
console.log(err ? `Failed!` : `Success!`, err || `${result.endTime - result.startTime}ms`);
});
在 angular.json
中添加 dll.js 文件的注入配置,可參考前文示例中 development.scripts
中的配置內容格式。
在 package.json
中增加啟動腳本配置。示例:
{
"scripts": {
"ng:serve": "node --max_old_space_size=8192 node_modules/@angular/cli/bin/ng serve",
"dll": "node config/webpack.dll.mjs",
"dev": "npm run dll -- --dev && npm run ng:serve -- -c development",
}
}
最后,可執行 npm run dev
測試效果是否符合預期。
以上就是“Angular13+開發模式太慢如何解決”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。