ホームページ  >  記事  >  ウェブフロントエンド  >  Angular13+ 開発モードが遅すぎる場合はどうすればよいですか?原因と解決策

Angular13+ 開発モードが遅すぎる場合はどうすればよいですか?原因と解決策

青灯夜游
青灯夜游転載
2022-12-22 21:15:562528ブラウズ

Angular13 開発モードが遅すぎる場合はどうすればよいですか?以下の記事では、Angular 13 開発モードが遅すぎる原因とビルド パフォーマンスを最適化する方法を紹介しますので、お役に立てれば幸いです。

Angular13+ 開発モードが遅すぎる場合はどうすればよいですか?原因と解決策

1 Angular 13 開発モードが遅すぎる理由と解決策

最近、7 人で高頻度の Angular プロジェクトに取り組みましたAngular 13 にアップグレードした後、その開発モードでは構築速度が遅く、リソースの使用量が多く、開発経験が貧弱です。会議で時々しか使用しない Macbook air でビルドを起動すると (最近、在宅勤務期間中の主な生産性向上ツールになっています)、ファンがうなり声を上げ、CPU が最大値に達し、ビルドが完了した後、ホット アップデートには 1 分以上かかります。 [関連チュートリアルの推奨事項: "angular チュートリアル "]

さまざまな理由を分析してトラブルシューティングした結果、最終的にスキーマ (. /node_modules/@angular/cli/lib/config) が見つかりました。 /schema.json) を参照し、Angular 12 リリース ドキュメント と組み合わせると、特定の原因が特定されました。Angular 12 の大きな変更点は aotbuildOptimizer# です。 ##、optimization およびその他のパラメーターは、デフォルト値 false から true に変更されました。 多くのブラウザおよびサーバー ビルダー オプションのデフォルト値が変更されました。これらの変更の目的は、構成の複雑さを軽減し、新しい「デフォルトで実稼働ビルド」イニシアチブをサポートすることです。

##Angular 12 以降のデフォルトの実稼働モードは、バージョンをまたがるアップグレードにとって非常に難しいことがわかります。変更の詳細は、この提出から学ぶことができます:

656f8d7

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

Note aot これをオンにした場合とオフにした場合、ビルド結果のパフォーマンスに多少の違いが生じる可能性があるため、特定の問題に基づいて分析する必要があります。

1.2 問題: aot

を開いた後、

pug がコンパイルされ、エラーが報告されますpugこのプロジェクトでは HTML コンテンツを開発します。

aot

がオフの場合、ビルドは正常に行われますが、オンにするとエラーが報告されます。 エラー内容と発生箇所を基にデバッガデバッグを実行すると、コンパイル結果が esModule オブジェクトになっていることがわかります。これは、raw-loader の使用によるもので、そのコンパイル結果はデフォルトで

esModule

モードになります。esModule 構成項目を無効にするだけです。例 (カスタム Webpack 構成については、以下の DLL 構成関連の例を参照してください): <pre class="brush:js;toolbar:false;">{ test: /\.pug$/, use: [ { loader: &amp;#39;raw-loader&amp;#39;, options: { esModule: false, }, }, { loader: &amp;#39;pug-html-loader&amp;#39;, options: { doctype: &amp;#39;html&amp;#39;, }, }, ], },</pre>2 さらなる最適化: Angular カスタム Webpack 構成 DLL は、

プロジェクト構築をサポートします。これはカスタム webpack 構成の要件であり、

@angular-builders/custom-webpack

ライブラリを使用して実装されますが、DLL は構成されていません。 Angular

vendorChunk

パラメータを提供します。これをオンにすると、package.json 内の依存関係などのパブリック リソースが独立したチャンクに抽出されます。ホット アップデート バンドルが大きすぎる、ホット アップデートが遅すぎるなどの問題は解決されましたが、依然としてメモリ使用量が高く、実際の比較テストでは webpack5 キャッシュが存在する場合、 dll モードのビルド コンパイル速度とホット アップデート速度はわずかに遅くなります。したがって、開発マシンのパフォーマンスが平均的な場合、dll を開発モードで構成すると一定のメリットが得られます。 2.1 Angular はカスタム Webpack 構成をサポートします

最初に、カスタム Webpack 構成のビルド サポートを構成する必要があります。次のコマンドを実行して依存関係を追加します:
npm i -D @angular-builders/custom-webpack
Modify

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

この例には多くのカスタム構成コンテンツが含まれています。主に webpack 関連の部分に注目してください。他のコンテンツは、独自のプロジェクトの特定の状況に基づいて比較および参照できます。詳細については、以前の記事の実践的な紹介も参照してください: lzw.me/a/update-to…

2.2 Angular 用の webpack dll サポートの構成

新しいwebpack.config.js ファイル。コンテンツ参照:

const { existsSync } = require(&#39;node:fs&#39;);
const { resolve } = require(&#39;node:path&#39;);
const webpack = require(&#39;webpack&#39;);

// require(&#39;events&#39;).EventEmitter.defaultMaxListeners = 0;

/**
 * @param {import(&#39;webpack&#39;).Configuration} config
 * @param {import(&#39;@angular-builders/custom-webpack&#39;).CustomWebpackBrowserSchema} options
 * @param {import(&#39;@angular-builders/custom-webpack&#39;).TargetOptions} targetOptions
 */
module.exports = (config, options, targetOptions) => {
  if (!config.devServer) config.devServer = {};

  config.plugins.push(
    new webpack.DefinePlugin({ LZWME_DEV: config.mode === &#39;development&#39; }),
  );

  const dllDir = resolve(__dirname, &#39;./dist/dll&#39;);
  if (
    existsSync(dllDir) &&
    config.mode === &#39;development&#39; &&
    options.scripts?.some((d) => d.bundleName === &#39;dll_library&#39;)
  ) {
    console.log(&#39;use dll:&#39;, dllDir);
    config.plugins.unshift(
      new webpack.DllReferencePlugin({
        manifest: require(resolve(dllDir, &#39;dll-manifest.json&#39;)),
        context: __dirname,
      })
    );
  }

  config.module.rules = config.module.rules.filter((d) => {
    if (d.test instanceof RegExp) {
      // 使用 less,移除 sass/stylus loader
      return !(d.test.test(&#39;x.sass&#39;) || d.test.test(&#39;x.scss&#39;) || d.test.test(&#39;x.styl&#39;));
    }
    return true;
  });

  config.module.rules.unshift(
    {
      test: /\.pug$/,
      use: [
        {
          loader: &#39;raw-loader&#39;,
          options: {
            esModule: false,
          },
        },
        {
          loader: &#39;pug-html-loader&#39;,
          options: {
            doctype: &#39;html&#39;,
          },
        },
      ],
    },
    {
      test: /\.html$/,
      loader: &#39;raw-loader&#39;,
      exclude: [helpers.root(&#39;src/index.html&#39;)],
    },
    {
      test: /\.svg$/,
      loader: &#39;raw-loader&#39;,
    },
    {
      test: /\.(t|les)s/,
      loader: require.resolve(&#39;@lzwme/strip-loader&#39;),
      exclude: /node_modules/,
      options: {
        disabled: config.mode !== &#39;production&#39;,
      },
    }
  );

  // AngularWebpackPlugin,用于自定义 index.html 处理插件
  const awPlugin = config.plugins.find((p) => p.options?.hasOwnProperty(&#39;directTemplateLoading&#39;));
  if (awPlugin) awPlugin.pluginOptions.directTemplateLoading = false;

  // 兼容上古遗传逻辑,禁用部分插件
  config.plugins = config.plugins.filter((plugin) => {
    const pluginName = plugin.constructor.name;
    if (/CircularDependency|CommonJsUsageWarnPlugin/.test(pluginName)) {
      console.log(&#39;[webpack][plugin] disabled: &#39;, pluginName);
      return false;
    }

    return true;
  });
  // console.log(&#39;[webpack][config]&#39;, config.mode, config, options, targetOptions);
  return config;
};

DLL ビルド用の新しい webpack.dll.mjs ファイルを作成します。内容例:

import { join } from &#39;node:path&#39;;
import webpack from &#39;webpack&#39;;

const rootDir = process.cwd();
const isDev = process.argv.slice(2).includes(&#39;--dev&#39;) || process.env.NODE_ENV === &#39;development&#39;;

/** @type {import(&#39;webpack&#39;).Configuration} */
const config = {
  context: rootDir,
  mode: isDev ? &#39;development&#39; : &#39;production&#39;,
  entry: {
    dll: [
      &#39;@angular/common&#39;,
      &#39;@angular/core&#39;,
      &#39;@angular/forms&#39;,
      &#39;@angular/platform-browser&#39;,
      &#39;@angular/platform-browser-dynamic&#39;,
      &#39;@angular/router&#39;,
      &#39;@lzwme/asmd-calc&#39;,
      // more...
    ],
  },
  output: {
    path: join(rootDir, &#39;dist/dll&#39;),
    filename: &#39;dll.js&#39;,
    library: &#39;[name]_library&#39;,
  },
  plugins: [
    new webpack.DllPlugin({
      path: join(rootDir, &#39;dist/dll/[name]-manifest.json&#39;),
      name: &#39;[name]_library&#39;,
    }),
    new webpack.IgnorePlugin({
      resourceRegExp: /^\.\/locale$/,
      contextRegExp: /moment$/,
    }),
  ],
  cache: { type: &#39;filesystem&#39; },
};

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 的缓存能力做了许多编译优化,一般情况下开发模式二次构建速度相比之前会有大幅的提升。但是相比 snowpackvite 一类的 esm no bundles 方案仍有较大的差距。其从 Angular 13 开始已经在尝试引入 esbuild,但由于其高度定制化的构建逻辑适配等问题,对一些配置参数的兼容支持相对较为复杂。在 Angular 15 中已经可以进行生产级配置尝试了,有兴趣也可作升级配置与尝试。

更多编程相关知识,请访问:编程教学!!

以上がAngular13+ 開発モードが遅すぎる場合はどうすればよいですか?原因と解決策の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。