站長(zhǎng)資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

Angular13+ 開發(fā)模式太慢怎么辦?原因與解決方法介紹

Angular13+ 開發(fā)模式太慢怎么辦?下面本篇文章給大家介紹一下Angular 13+ 開發(fā)模式太慢的原因與構(gòu)建性能優(yōu)化的方法,希望對(duì)大家有所幫助!

Angular13+ 開發(fā)模式太慢怎么辦?原因與解決方法介紹

1 Angular 13+ 開發(fā)模式太慢的原因與解決

近期在某個(gè)高頻迭代七年的 Angular 項(xiàng)目升級(jí)至 Angular 13 后,其開發(fā)模式的構(gòu)建速度慢、資源占用高,開發(fā)體驗(yàn)相當(dāng)差。在一臺(tái)僅在開會(huì)時(shí)偶爾使用的 Macbook air(近期居家辦公期間轉(zhuǎn)換為了主要生產(chǎn)力工具) 中啟動(dòng)構(gòu)建時(shí),它的風(fēng)扇會(huì)呼呼作響,CPU 負(fù)荷被打滿,而在構(gòu)建完成后,熱更新一次的時(shí)間在一分鐘以上?!鞠嚓P(guān)教程推薦:《angular教程》】

在經(jīng)過各種原因分析與排查后,最終在 angular.json 的 schema(./node_modules/@angular/cli/lib/config/schema.json) 中發(fā)現(xiàn)了問題,再結(jié)合 Angular 12 release 文檔定位到了具體原因: Angular 12 一個(gè)主要的改動(dòng)是將 aot、buildOptimizer、optimization 等參數(shù)由默認(rèn)值 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 后的默認(rèn)生產(chǎn)模式,對(duì)于跨版本升級(jí)來說是比較坑爹的。我們可以從這個(gè)提交中了解變動(dòng)細(xì)節(jié):656f8d7

1.1 解決 Angular 12+ 開發(fā)模式慢的問題

解決辦法則是在 development 配置中禁用生產(chǎn)模式相關(guān)的配置項(xiàng)。示例:

{   "$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" }
登錄后復(fù)制

需注意 aot 開啟與關(guān)閉時(shí),在構(gòu)建結(jié)果表現(xiàn)上可能會(huì)有一些差異,需視具體問題而分析。

1.2 問題:開啟 aotpug 編譯報(bào)錯(cuò)

該項(xiàng)目中使用 pug 開發(fā) html 內(nèi)容。關(guān)閉 aot 時(shí)構(gòu)建正常,開啟后則會(huì)報(bào)錯(cuò)。

根據(jù)報(bào)錯(cuò)內(nèi)容及位置進(jìn)行 debugger 調(diào)試,可以看到其編譯結(jié)果為一個(gè) esModule 的對(duì)象。這是由于使用了 raw-loader,其編譯結(jié)果默認(rèn)為 esModule 模式,禁用 esModule 配置項(xiàng)即可。示例(自定義 webpack 配置可參考下文的 dll 配置相關(guān)示例):

{   test: /.pug$/,   use: [     {       loader: 'raw-loader',       options: {         esModule: false,       },     },     {       loader: 'pug-html-loader',       options: {         doctype: 'html',       },     },   ], },
登錄后復(fù)制

2 進(jìn)一步優(yōu)化:Angular 自定義 webpack 配置 dll 支持

該項(xiàng)目項(xiàng)目構(gòu)建上有自定義 webpack 配置的需求,使用了 @angular-builders/custom-webpack 庫實(shí)現(xiàn),但是沒有配置 dll。

Angular 提供了 vendorChunk 參數(shù),開啟它會(huì)提取在 package.json 中的依賴等公共資源至獨(dú)立 chunk 中,其可以很好的解決熱更新 bundles 過大導(dǎo)致熱更新太慢等的問題,但仍然存在較高的內(nèi)存占用,而且實(shí)際的對(duì)比測(cè)試中,在存在 webpack5 緩存的情況下,其相比 dll 模式的構(gòu)建編譯速度以及熱更新速度都稍微慢一些。故對(duì)于開發(fā)機(jī)器性能一般的情況下,給開發(fā)模式配置 dll 是會(huì)帶來一定的收益的。

2.1 Angular 支持自定義 webpack 配置

首先需要配置自定義 webpack 配置的構(gòu)建支持。執(zhí)行如下命令添加依賴:

npm i -D @angular-builders/custom-webpack
登錄后復(fù)制

修改 angluar.json 配置。內(nèi)容格式參考:

{   "$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     }   } }
登錄后復(fù)制

該示例中涉及多處自定義配置內(nèi)容,主要需注意 webpack 相關(guān)的部分, 其他內(nèi)容可視自身項(xiàng)目具體情況對(duì)比參考。一些細(xì)節(jié)也可參考以前的這篇文章中的實(shí)踐介紹:lzw.me/a/update-to…

2.2 為 Angular 配置 webpack dll 支持

新建 webpack.config.js 文件。內(nèi)容參考:

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; };
登錄后復(fù)制

新建 webpack.dll.mjs 文件,用于 dll 構(gòu)建。內(nèi)容示例:

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`); });
登錄后復(fù)制

angular.json 中添加 dll.js 文件的注入配置,可參考前文示例中 development.scripts 中的配置內(nèi)容格式。

package.json 中增加啟動(dòng)腳本配置。示例:

{     "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",     } }
登錄后復(fù)制

最后,可執(zhí)行 npm run dev 測(cè)試效果是否符合預(yù)期。

3 小結(jié)

angular-cli 在升級(jí)至 webpack 5 以后,基于 webpack 5 的緩存能力做了許多編譯優(yōu)化,一般情況下開發(fā)模式二次構(gòu)建速度相比之前會(huì)有大幅的提升。但是相比 snowpackvite 一類的 esm no bundles 方案仍有較大的差距。其從 Angular 13 開始已經(jīng)在嘗試引入 esbuild,但由于其高度定制化的構(gòu)建邏輯適配等問題,對(duì)一些配置參數(shù)的兼容支持相對(duì)較為復(fù)雜。在 Angular 15 中已經(jīng)可以進(jìn)行生產(chǎn)級(jí)配置嘗試了,有興趣也可作升級(jí)配置與嘗試。

贊(0)
分享到: 更多 (0)
網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
福利姬在线精品观看| 亚洲AV日韩精品久久久久久久| 99re热这里有精品首页视频| 亚洲精品国偷自产在线| 国产成人精品在线观看| 成人麻豆日韩在无码视频| 四虎精品久久久久影院| 国产精品萌白酱在线观看| 老司机无码精品A| 宅男宅女精品国产av天堂| 国产精品喷水在线观看| 2022国产成人福利精品视频| 亚洲精品在线免费观看| 久久精品中文騷妇女内射| 无码aⅴ精品一区二区三区浪潮| 精品国内片67194| 538prom精品视频线放| a级精品九九九大片免费看| 久久久久成人精品无码| 精品国产不卡一区二区三区| 国产精品videossex白浆| 国产成人精品曰本亚洲79ren | 国产高清一级毛片精品| 亚欧洲精品在线视频免费观看| 精品视频一区在线观看| 精品一区二区三区在线视频观看| 日韩一区二区a片免费观看| 中文字幕日韩精品在线| 日韩一区二区视频| 国产一区二区三区日韩精品| 精品国自产拍天天拍2021| 五月天婷亚洲天综合网精品偷| 亚洲精品国产精品国自产观看| 国产成人精品曰本亚洲79ren| 久久精品国产亚洲7777| 中文字幕精品一区二区精品| 精品九九人人做人人爱| 亚洲av永久无码精品国产精品| 久久精品成人免费观看| 人妻少妇精品中文字幕av蜜桃| 91精品久久久久久久久久 |