站長資訊網(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í)間在一分鐘以上。【相關(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)是將 aotbuildOptimizeroptimization 等參數(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ì)比測試中,在存在 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 測試效果是否符合預(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)
www.精品在线| 日韩视频在线观看一区二区| 无码国产精品一区二区免费模式 | 亚洲精品二三区伊人久久| 久久精品免看国产| 91精品全国免费观看青青| 亚洲精品视频免费观看| 亚洲欧洲日韩综合| 国产在线国偷精品产拍| 日韩电影中文字幕| 91精品无码久久久久久五月天| 久久91精品国产91久久麻豆| 国产精品永久久久久久久久久| 日韩在线观看完整版电影| 日韩av无码免费播放| 国产午夜福利久久精品| 在线观看精品国产福利片100| 亚洲av无码成人精品国产 | 久久亚洲精品成人| 国产在线精品免费aaa片| 国内精品久久久久影院网站| 国产精品亚洲视频| 国产精品 猎奇 另类视频| www亚洲精品少妇裸乳一区二区| 国产一区二区三区日韩精品| 亚洲欧美日韩一区二区三区在线| 亚洲日韩乱码中文无码蜜桃臀网站| 国产一卡2卡3卡四卡精品一信息| 尤物在线观看精品国产福利片 | 中日欧洲精品视频在线| 久久国产精品偷99| 日韩电影在线观看第一区| 最新国产精品好看的国产精品| 国产精品无码免费播放| 精品无码专区亚洲| 孩交精品xxxx视频视频| 国内精品一区二区三区在线观看 | 麻豆国产VA免费精品高清在线| 久久久国产精品va麻豆| 久久国产精品成人无码网站 | 国产成人精品免费直播|