成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

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

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

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

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

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

近期在某個高頻迭代七年的 Angular 項目升級至 Angular 13 后,其開發(fā)模式的構(gòu)建速度慢、資源占用高,開發(fā)體驗相當差。在一臺僅在開會時偶爾使用的 Macbook air(近期居家辦公期間轉(zhuǎn)換為了主要生產(chǎn)力工具) 中啟動構(gòu)建時,它的風扇會呼呼作響,CPU 負荷被打滿,而在構(gòu)建完成后,熱更新一次的時間在一分鐘以上?!鞠嚓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 一個主要的改動是將 aot、buildOptimizer、optimization 等參數(shù)由默認值 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 后的默認生產(chǎn)模式,對于跨版本升級來說是比較坑爹的。我們可以從這個提交中了解變動細節(jié):656f8d7

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

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

{   "$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)閉時,在構(gòu)建結(jié)果表現(xiàn)上可能會有一些差異,需視具體問題而分析。

1.2 問題:開啟 aotpug 編譯報錯

該項目中使用 pug 開發(fā) html 內(nèi)容。關(guān)閉 aot 時構(gòu)建正常,開啟后則會報錯。

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

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

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

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

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

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)容可視自身項目具體情況對比參考。一些細節(jié)也可參考以前的這篇文章中的實踐介紹: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 中增加啟動腳本配置。示例:

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

贊(0)
分享到: 更多 (0)
?
網(wǎng)站地圖   滬ICP備18035694號-2    滬公網(wǎng)安備31011702889846號
美女扒开腿让男人桶爽| 男人下部进女人下部视频| 久久人爽人人爽人人片AV| 久久久久久精品久久久| 妺妺窝人体色www聚色窝仙踪| 欧美成人精品手机在线| 欧美日韩国产免费一区二区三区| 日本人XXXX裸体XXXX| 铜铜铜铜铜铜铜铜好痛好深色板| 午夜精品无人区乱码1区2区| 亚洲高清中文字幕在线看不卡| 亚洲综合精品第一页| 2018AV无码视频在线播放| 被陌生人带去卫生间啪到腿软| 国产AⅤ无码一区二区三区| 国产无遮挡又黄又爽在线观看| 久爱无码精品免费视频在线观看| 妺妺窝人体色www在线观看婚闹| 人人爽人人爽人人爽人人片AV| 天天摸夜夜添添到高潮水汪汪| 亚洲V欧美V日韩V国产V| 中文高清无码人妻| 成熟交BGMBGMBGM在线| 国产亚洲精品精华液| 久久午夜福利无码1000合集| 人妻人人添人人爽夜夜欢视频| 无码高清一区二区三区| 亚洲一区二区三区成人网站 | 中文字幕AV无码一二三区电影| 波多野结衣无内裤护士| 国产啪亚洲国产精品无码| 久久综合亚洲欧美成人| 日韩精品无码人妻免费视频| 亚洲 中文 欧美 日韩 在线| 中文字幕乱近親相姦| 抽出含了一整夜的性器液体流出| 激情五月综合 香亚洲| 欧美肥肥婆另类XXXX000| 玩稚嫩的小屁股眼AV| 一区国产情侣宾馆射| 吃瓜黑料视频永久地址| 精品人妻无码区二区三区密桃| 欧美性大战XXXXX久久久| 亚欧洲乱码视频一二三区| 中文字幕在线无码一区二区三区 | 果冻十麻豆十天美十老师| 男生把小j放进女人屁股视频狂躁| 水多多凹凸福利视频导航| 野花日本大全免费观看版动漫 | 一本大道无码日韩精品影视_ | 护士高潮喷水白浆| 人妻少妇被猛烈进入中文字幕| 亚洲AV无码成人精品区在线欢看| 99偷拍视频精品一区二区| 国产亚洲AV综合人人澡精品| 欧美日韩人妻一区二区三区| 性丰满ⅩXXOOO性HD| AV香港经典A毛片免费观看| 国产精品综合色区在线观看| 欧美白人最猛性XXXXX69交| 亚洲AV日韩AⅤ无码网站| YW尤物无码点击进入| 精品无码无人网站免费视频 | 亚洲国产综合精品 在线 一区| АⅤ资源中文在线天堂| 精品无码一区二区三区不卡| 少妇激情AV一区二区三区| 中国熟妇色XXXXX| 国产在线看片无码人精品| 人人添人人妻人人爽夜欢视AV| 亚洲熟女乱色综合一区| 国产AV无码专区亚洲AV软件| 男男av在线播放| 亚洲国产精品无码中文字视| 低调看JRS直播| 蜜桃人妻一区二区三区| 亚洲插肏熟女人妇的屄网址 | 97成人无码免费一区二区中文 | 亚洲国产成人无码电影| 东京热TOKYO综合久久精品| 免费一对一真人视频APP| 亚洲成AⅤ人片久青草影院| 第一次接20厘米得黑人活| 免费啪啪全程无遮挡60分钟 | 久久久久久久精品无码AV少妇| 无码精品黑人一区二区三区 | 无线乱码A区B区C区D| 被村长狂躁俩小时玉婷| 裸体跳舞XXXX裸体跳舞| 亚洲国产成人精品无码区在线秒播| 丰满熟妇VIDEOSXXXX| 欧美致敬很多经典的黑白MV| 永久免费的啪啪免费网址| 精产国品一二三产区别手机| 无码精品A∨在线观看无广告| 成人午夜亚洲精品无码区| 欧美成在线精品视频| 夜夜精品无码一区二区三区| 国产做无码视频在线观看浪潮| 天天摸天天碰天天添| 成人A片产无码免费视频在线观看| 蜜臀98精品国产免费观看| 亚洲一区二区三区中文字幕在线 | 男男GV白嫩小受GV在线播放| 亚洲一区二区三区日本久久九| 好儿子你插得太深了| 无码人妻侵犯一区侵犯| 高雅人妻被迫沦为玩物| 日韩人妻无码AⅤ中文字幕| MD豆传媒APP网址| 欧美日韩久久中文字幕| 97久久精品无码一区二区天美| 老年镖客视频大全播放| 艳妇乳肉豪妇荡乳ⅩXXO电影| 娇妻宾馆被三根粗大的夹击| 亚洲AV成人精品午夜一区二区| 国产公妇仑乱在线观看| 私はあなたを爱しています怎么读| 吃了继兄给我开的药我做的梦| 人妻无奈被迫屈辱1-9| YSL千人千色8610| 欧美成人精品高清在线播放| 99精品久久久久精品双飞| 男生坤坤放在女生坤坤叫什么| 自偷自拍亚洲综合精品麻豆| 麻豆精品国产综合久久| 中文字幕成熟丰满人妻| 蜜臀亚洲AV无码精品国产午夜| 中国人妻被两个老外三P| 毛茸茸BBWBBW中国妓女| 中文字幕亚洲无线码| 妺妺窝人体色www在线下载人| 中文字幕亚洲精品无码| 男男黄Gay片免费网站www| 9L国产精品久久久久尤物| 欧美做受三级级视频播放| 被夫の上司に犯中文字幕| 日韩人妻无码中文字幕视频| 疯狂揉小泬到失禁高潮| 无卡无码无免费毛片| 国产又色又爽又黄的在线观看| 亚洲第一综合天堂另类专| 精品无码三级在线观看视频| 一边做饭一边躁狂我会怎么样呢| 雷神ちゃんが人気の原因| 中文字幕高清免费日韩视频在线| 牛牛影视亚洲AV成人片| WWW.嫩草AV天堂影院| 色老汉亚洲AV影院天天| 国产精品麻花传媒二三区别| 亚洲AV无码熟妇在线观看| 久久WWW色情成人免费观看| 中国又粗又大XXXXBBBB| 欧美与黑人午夜性猛交久久久 | 无码中文AV波多野结衣| 国内精品伊人久久久久777| 亚洲人成网线在线播放VA| 老汉扛起娇妻玉腿进入| CHINESE东北嫖妓女HD| 色噜噜狠狠色综合网| 国产强被迫伦姧在线观看无码 | 中文国产成人精品久久| 强开小婷嫩苞又嫩又紧韩国视频| 成人无码AⅤ久久精品国产传媒| 无码人妻精品一区二区蜜桃天美 | 亚洲综合色在线观看一区二区| 免费精品无码AV片在线观看| 白白嫩嫩又小又紧| 无人区码一码二码三码网页| 久久精品国产精品久久久| 91精品人妻人人做人碰人人爽| 日韩欧美操逼视频| 国产综合久久久久久鬼色| 尹人香蕉久久99天天拍| 人与野鲁交XXXⅩ视频| 国产强奷在线播放| 伊人久久大香线蕉综合5G| 日本大学学校AAAAA| 国产色母和进口色母区别| 又粗又大又爽又舒服日产| 日本护士HD人XXXX| 国产一区二区三区在线电影| 已婚丰满少妇潮喷21P| 日本熟妇人妻XXXXX-欢迎您| 国精产品一区二区三区糖心269| 中国CHINESE壮男GⅤ军警| 日韩在线视频一区二区三区 | 亚洲无线一二三四区手机| 欧美亚洲国产SUV| 国产精品污WWW在线观看| 永久免费AV无码网站性色AV | 亚洲人成色A777777在线观| 漂亮人妻被中出中文字幕| 国产在线精品一区二区三区不卡| 中文字幕精品亚洲无线码一区 | 国产午夜片无码区在线观看| 最新无码国产在线视频9299| 无码AVAV无码中文字幕| 邻居少妇张开双腿让我爽一夜 | 亚洲AV无码成人精品区浪潮AV|