最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Angular 13+開(kāi)發(fā)模式慢的原因及構(gòu)建性能優(yōu)化解析

 更新時(shí)間:2022年12月20日 09:02:41   作者:任俠  
這篇文章主要為大家介紹了Angular 13+開(kāi)發(fā)模式慢的原因及構(gòu)建性能優(yōu)化解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

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

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

在經(jīng)過(guò)各種原因分析與排查后,最終在 angular.json 的 schema(./node_modules/@angular/cli/lib/config/schema.json) 中發(fā)現(xiàn)了問(wè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í)來(lái)說(shuō)是比較坑爹的。我們可以從這個(gè)提交中了解變動(dòng)細(xì)節(jié):656f8d7

1.1 解決 Angular 12+ 開(kāi)發(fā)模式慢的問(wèn)題

解決辦法則是在 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"
}

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

1.2 問(wèn)題:開(kāi)啟 aot 后 pug 編譯報(bào)錯(cuò)

該項(xiàng)目中使用 pug 開(kāi)發(fā) html 內(nèi)容。關(guān)閉 aot 時(shí)構(gòu)建正常,開(kāi)啟后則會(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',
      },
    },
  ],
},

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

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

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

2.1 Angular 支持自定義 webpack 配置

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

npm i -D @angular-builders/custom-webpack

修改 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
    }
  }
}

該示例中涉及多處自定義配置內(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;
};

新建 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`);
});

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",
    }
}

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

3 小結(jié)

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

以上就是Angular 13+開(kāi)發(fā)模式慢的原因及構(gòu)建性能優(yōu)化解析的詳細(xì)內(nèi)容,更多關(guān)于Angular 13+性能優(yōu)化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • angularjs中判斷ng-repeat是否迭代完的實(shí)例

    angularjs中判斷ng-repeat是否迭代完的實(shí)例

    今天小編就為大家分享一篇angularjs中判斷ng-repeat是否迭代完的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • Angularjs material 實(shí)現(xiàn)搜索框功能

    Angularjs material 實(shí)現(xiàn)搜索框功能

    這篇文章主要介紹了Angularjs material 實(shí)現(xiàn)搜索框功能的相關(guān)資料,需要的朋友可以參考下
    2016-03-03
  • Angular ElementRef簡(jiǎn)介及其使用

    Angular ElementRef簡(jiǎn)介及其使用

    這篇文章主要介紹了Angular ElementRef簡(jiǎn)介及其使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-10-10
  • 利用JavaScript的AngularJS庫(kù)制作電子名片的方法

    利用JavaScript的AngularJS庫(kù)制作電子名片的方法

    這篇文章主要介紹了利用JavaScript的AngularJS庫(kù)制作電子名片的方法,其中需要使用到HTML5的canvas畫布,需要的朋友可以參考下
    2015-06-06
  • 詳解angular2 控制視圖的封裝模式

    詳解angular2 控制視圖的封裝模式

    這篇文章主要介紹了詳解angular2 控制視圖的封裝模式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • 關(guān)于使用axios的一些心得技巧分享

    關(guān)于使用axios的一些心得技巧分享

    vue更新到2.0之后,作者就宣告不再對(duì)vue-resource更新,而是推薦的axios,所以下面這篇文章主要給大家分享了關(guān)于使用axios的一些心得技巧,文中介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-07-07
  • 如何解決手機(jī)瀏覽器頁(yè)面點(diǎn)擊不跳轉(zhuǎn)瀏覽器雙擊放大網(wǎng)頁(yè)

    如何解決手機(jī)瀏覽器頁(yè)面點(diǎn)擊不跳轉(zhuǎn)瀏覽器雙擊放大網(wǎng)頁(yè)

    這篇文章主要介紹了如何解決手機(jī)瀏覽器頁(yè)面點(diǎn)擊不跳轉(zhuǎn)瀏覽器雙擊放大網(wǎng)頁(yè)的相關(guān)資料,需要的朋友可以參考下
    2016-07-07
  • AngularJS基礎(chǔ) ng-class-odd 指令示例

    AngularJS基礎(chǔ) ng-class-odd 指令示例

    本文主要介紹AngularJS ng-class-odd 指令,這里對(duì)ng-class-odd基礎(chǔ)知識(shí)做了詳細(xì)整理,并有示例代碼和效果圖,學(xué)習(xí)AngularJS的同學(xué)可以參考下
    2016-08-08
  • 詳解關(guān)于Angular4 ng-zorro使用過(guò)程中遇到的問(wèn)題

    詳解關(guān)于Angular4 ng-zorro使用過(guò)程中遇到的問(wèn)題

    這篇文章主要介紹了詳解關(guān)于Angular4 ng-zorro使用過(guò)程中遇到的問(wèn)題,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • AngularJS基礎(chǔ)學(xué)習(xí)筆記之簡(jiǎn)單介紹

    AngularJS基礎(chǔ)學(xué)習(xí)筆記之簡(jiǎn)單介紹

    AngularJS 不僅僅是一個(gè)類庫(kù),而是提供了一個(gè)完整的框架。它避免了您和多個(gè)類庫(kù)交互,需要熟悉多套接口的繁瑣工作。它由Google Chrome的開(kāi)發(fā)人員設(shè)計(jì),引領(lǐng)著下一代Web應(yīng)用開(kāi)發(fā)。也許我們5年或10年后不會(huì)使用AngularJS,但是它的設(shè)計(jì)精髓將會(huì)一直被沿用。
    2015-05-05

最新評(píng)論

巫溪县| 桓台县| 临西县| 夏邑县| 遂川县| 贞丰县| 铁岭县| 开鲁县| 彭泽县| 定南县| 青田县| 京山县| 罗平县| 汶川县| 天津市| 敦化市| 普洱| 新竹县| 盐城市| 鄂温| 德令哈市| 周口市| 阳曲县| 南康市| 特克斯县| 广宗县| 营口市| 武义县| 桃园县| 淮阳县| 会宁县| 临泉县| 康平县| 樟树市| 乐亭县| 津市市| 兴化市| 财经| 香河县| 五大连池市| 景谷|