Angular13+ 開發模式太慢怎麼辦?原因與解決方法介紹
Angular13 開發模式太慢怎麼辦?以下這篇文章跟大家介紹一下Angular 13 開發模式太慢的原因與建構效能優化的方法,希望對大家有幫助!
1 Angular 13 開發模式太慢的原因與解決
近期在某個高頻迭代七年的Angular 項目升級至Angular 13 後,其開發模式的建置速度慢、資源佔用高,開發體驗相當差。在一台僅在開會時偶爾使用的Macbook air
(近期居家辦公期間轉換為了主要生產力工具) 中啟動構建時,它的風扇會呼呼作響,CPU 負荷被打滿,而在建造完成後,熱更新一次的時間在一分鐘以上。 【相關教學推薦:《angular教學》】
在經過各種原因分析與檢驗後,最後在angular.json
的schema(. /node_modules/@angular/cli/lib/config/schema.json
) 中發現了問題,再結合Angular 12 release 文件定位到了具體原因: Angular 12 一個主要的改變是將aot
、buildOptimizer
、optimization
等參數由預設值false
改為true
。
可以看到Angular 12 後的預設生產模式,對於跨版本升級來說是比較坑爹的。我們可以從這個提交中了解變動細節: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 buil by default" initiative
#1.1 解決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 開啟與關閉時,在建置結果表現上可能會有一些差異,需視具體問題而分析。
1.2 問題:開啟aot 後
pug 編譯錯誤
該專案中使用pug開發html 內容。關閉
aot 時建置正常,開啟後則會報錯。
raw-loader,其編譯結果預設為
esModule 模式,停用
esModule 設定項目即可。範例(自訂webpack 配置可參考下文的dll 配置相關範例):
{ test: /\.pug$/, use: [ { loader: 'raw-loader', options: { esModule: false, }, }, { loader: 'pug-html-loader', options: { doctype: 'html', }, }, ], },
#2 進一步最佳化:Angular 自訂webpack 配置dll 支援
#此專案專案構建上有自訂webpack 配置的需求,使用了
@angular-builders/custom-webpack 函式庫實現,但是沒有配置dll。
Angular 提供了
vendorChunk 參數,開啟它會提取在
package.json 中的依賴等公共資源至獨立chunk 中,其可以很好的解決熱更新bundles 過大導致熱更新太慢等的問題,但仍然存在較高的內存佔用,而且實際的對比測試中,在存在webpack5 緩存的情況下,其相比dll 模式的構建編譯速度以及熱更新速度都稍微慢一點。故對於開發機器性能一般的情況下,給開發模式配置 dll 是會帶來一定的收益的。
2.1 Angular 支援自訂 webpack 配置
#首先需要設定自訂 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 } } }
2.2 為Angular 配置webpack dll 支援
新建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
测试效果是否符合预期。
3 小结
angular-cli
在升级至 webpack 5 以后,基于 webpack 5 的缓存能力做了许多编译优化,一般情况下开发模式二次构建速度相比之前会有大幅的提升。但是相比 snowpack
和 vite
一类的 esm no bundles 方案仍有较大的差距。其从 Angular 13
开始已经在尝试引入 esbuild
,但由于其高度定制化的构建逻辑适配等问题,对一些配置参数的兼容支持相对较为复杂。在 Angular 15
中已经可以进行生产级配置尝试了,有兴趣也可作升级配置与尝试。
更多编程相关知识,请访问:编程教学!!
以上是Angular13+ 開發模式太慢怎麼辦?原因與解決方法介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

Angular.js是一種可自由存取的JavaScript平台,用於建立動態應用程式。它允許您透過擴展HTML的語法作為模板語言,以快速、清晰地表示應用程式的各個方面。 Angular.js提供了一系列工具,可協助您編寫、更新和測試程式碼。此外,它還提供了許多功能,如路由和表單管理。本指南將討論在Ubuntu24上安裝Angular的方法。首先,您需要安裝Node.js。 Node.js是一個基於ChromeV8引擎的JavaScript運行環境,可讓您在伺服器端執行JavaScript程式碼。要在Ub

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

Angular框架中元件的預設顯示行為不是區塊級元素。這種設計選擇促進了元件樣式的封裝,並鼓勵開發人員有意識地定義每個元件的顯示方式。透過明確設定CSS屬性 display,Angular組件的顯示可以完全控制,從而實現所需的佈局和響應能力。

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest
