web-dev-qa-db-ja.com

Angular Web Workersを使用してCLIで生成されたアプリ

Angularドキュメントを読むと、いくつかの 参照bootstrapあなたの全体Angularアプリ内のWeb Worker ので、JSが頻繁に使用されてもUIはブロックされません。

ただし、現時点ではその方法に関する公式情報はなく、Angular Doc。の唯一の情報は、これが実験的な機能であることです。

この方法を使用してAngularのWebワーカーを活用するにはどうすればよいですか?

28
Enrique Oriol

Angular 7については、以下の回答を参照してください。

私はそれを行う方法を見つけるために多くの時間を費やしたので、私は これが誰かを助けることができる を願っています。

前提条件

Angular CLI 1.0以降で生成されたAngularプロジェクト(バージョン2または4)があると仮定しています。

この手順に従うためにCLIでプロジェクトを生成することは必須ではありませんが、webpackファイルに関連して説明する手順は、CLI webpack構成に基づいています。

手順

1. webpackファイルを抽出します

Angular CLI v1.0以降、「取り出し」機能があり、webpack構成ファイルを抽出して、必要に応じて操作できます。

  • ng ejectを実行して、Angular CLIがwebpack.config.jsファイルを生成します。

  • npm installを実行して、CLIによって生成された新しい依存関係が満たされるようにします

2. webworker bootstrap依存関係をインストールします

npm install --save @angular/platform-webworker @angular/platform-webworker-dynamicを実行します

3. UIスレッドブートストラップの変更

3.1 app.module.tsの変更

App.module.tsファイルのBrowserModuleWorkerAppModuleに置き換えます。 @angular/platform-webworkerライブラリを使用するには、importステートメントを更新する必要もあります。

//src/app/app.module.ts

import { WorkerAppModule } from '@angular/platform-webworker';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
//...other imports...

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    WorkerAppModule,
    //...other modules...
  ],
  providers: [/*...providers...*/],
  bootstrap: [AppComponent]
})
export class AppModule { }

3.2 src/main.tsの変更

bootstrapプロセスをbootstrapWorkerUIに置き換えます(インポートも更新します)。

ウェブワーカーが定義されているファイルにURLを渡す必要があります。 webworker.bundle.jsというファイルを使用してください。心配しないでください。このファイルはすぐに作成されます。

//main.ts

import { enableProdMode } from '@angular/core';
import { bootstrapWorkerUi } from '@angular/platform-webworker';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

bootstrapWorkerUi('webworker.bundle.js');

3.3 workerLoader.tsファイルを作成する

  • 新しいファイルsrc/workerLoader.tsを作成します。
  • Web Workerは必要なものをすべて含む単一のファイルになるため、polyfills.ts@angular/core、および@angular/commonパッケージを含める必要があります。次のステップで、Webpackを更新して、結果を含むバンドルをトランスパイルおよびビルドします。
  • インポートplatformWorkerAppDynamic
  • AppModuleをインポートします(main.tsからインポートを削除します)およびbootstrapを使用して、このplatformWorkerAppDynamicプラットフォーム。
// workerLoader.ts

import 'polyfills.ts';
import '@angular/core';
import '@angular/common';

import { platformWorkerAppDynamic } from '@angular/platform-webworker-dynamic';
import { AppModule } from './app/app.module';

platformWorkerAppDynamic().bootstrapModule(AppModule);

4. webpackを更新してWebworkerをビルドします

自動生成されるwebpackの構成ファイルは非常に長いですが、次のことに注意を集中する必要があります。

  • workerLoader.tsファイルにwebworkerentry pointを追加します。出力を見ると、すべてのチャンクにbundle.jsプレフィックスが付加されていることがわかります。 bootstrapステップでwebworker.bundle.jsを使用したのはそのためです

  • HtmlWebpackPluginに移動し、webworkerエントリポイントを除外するため、生成されたWeb Workerファイルはindex.htmlファイルに含まれません。

  • CommonChunksPluginに移動し、inline共通​​チャンクに対して、webworkerが含まれないようにエントリチャンクを明示的に設定します。 。

  • AotPluginに移動し、entryModuleを明示的に設定します。

// webpack.config.js

//...some stuff...
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CommonsChunkPlugin } = require('webpack').optimize;
const { AotPlugin } = require('@ngtools/webpack');
//...some stuff...

module.exports = {
  //...some stuff...
  "entry": {
    "main": [
      "./src/main.ts"
    ],
    "polyfills": [
      "./src/polyfills.ts"
    ],
    "styles": [
      "./src/styles.css"
    ],
    "webworker": [
      "./src/workerLoader.ts"
    ]
  },
  "output": {
    "path": path.join(process.cwd(), "dist"),
    "filename": "[name].bundle.js",
    "chunkFilename": "[id].chunk.js"
  },
  "module": { /*...a lot of stuff...*/ },
  "plugins": [
    //...some stuff...
    new HtmlWebpackPlugin({
      //...some stuff...
      "excludeChunks": [
        "webworker"
      ],
      //...some more stuff...
    }),
    new BaseHrefWebpackPlugin({}),
    new CommonsChunkPlugin({
      "name": "inline",
      "minChunks": null,
      "chunks": [
        "main",
        "polyfills",
        "styles"
      ]
    }),
    //...some stuff...
    new AotPlugin({
      "mainPath": "main.ts",
      "entryModule": "app/app.module#AppModule",
      //...some stuff...
    })
  ],
  //...some more stuff...
};

準備ができた

前の手順を正しく実行したら、コードをコンパイルして結果を試すだけで済みます。

npm startを実行します

AngularアプリのすべてのロジックがWebWorker内で実行されている必要があり、UIがより流toになります。

フルターノート

npm startwebpack-dev serverを実行しますが、Webworkerがコンソールログにエラーメッセージを投げるという問題があります。とにかく、ウェブワーカーは正常に動作しているようです。 webpackコマンドを使用してアプリをコンパイルし、 simplehttpserver などのhttpサーバーから提供すると、エラーはなくなります;)

サンプルコードとデモ

this repo からコード全体(webpack config、app.module.ts、...)を取得できます。

また、ここで live demo を見て、Web Workersを使用するかどうかの違いを確認することもできます。

72
Enrique Oriol

良いニュースだ、私はこれをAngular 7!????????????

要件npm install --save-dev @angular-builders/custom-webpack html-webpack-plugin単にしたい場合は、envファイルにproduction:trueがあることを確認してください以下からコードをコピー/貼り付けます。

ステップ1:次の方法で、angle.jsonファイルを編集します。

"architect": {
        "build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "customWebpackConfig": {
                "path": "./webpack.client.config.js",
                "replaceDuplicatePlugins": true
             },
            ...
          }

開発サーバーではワーカー全体を実際に必要としないため、build部分のみを編集しています。

ステップ2:プロジェクトのルートにwebpack.client.config.jsファイルを作成します。 SSRを使用していない場合は、exclude: ['./server.ts'],を削除できます

const path = require('path');
const webpack = require('webpack');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { AngularCompilerPlugin } = require('@ngtools/webpack');

module.exports = {
  entry: {
    webworker: [
      "./src/workerLoader.ts"
    ],
    main: [
      "./src/main.ts"
    ],
    polyfills: [
      "./src/polyfills.ts"
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      excludeChunks: [
        "webworker"
      ],
      chunksSortMode: "none"
    }),
    new AngularCompilerPlugin({
      mainPath: "./src/main.ts",
      entryModule: './src/app/app.module#AppModule',
      tsConfigPath: "src/tsconfig.app.json",
      exclude: ['./server.ts'],
      sourceMap: true,
      platform: 0
    }),
  ],
  optimization: {
    splitChunks: {
      name: "inline"
    }
  }
}

ステップ3:AppModuleを編集します:

import { BrowserModule } from '@angular/platform-browser'
import { WorkerAppModule } from '@angular/platform-webworker'
const AppBootstrap =
            environment.production
            ? WorkerAppModule
            : BrowserModule.withServerTransition({ appId: 'myApp' })
    imports: [
        ...
        AppBootstrap,
        ...
    ]

ステップ4:main.tsファイルを編集します。

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { bootstrapWorkerUi } from '@angular/platform-webworker';

import {AppModule} from './app/app.module';
import {environment} from './environments/environment';

if (environment.production) {
  enableProdMode();
  bootstrapWorkerUi('webworker.bundle.js');
}

else {
  document.addEventListener('DOMContentLoaded', () => {
    platformBrowserDynamic().bootstrapModule(AppModule);
  });
}

ステップ5:正常にコンパイルされますが、アプリのDOM操作が原因で実行時の問題が発生する可能性があります。この時点で、DOM操作をすべて削除し、別のものに置き換えるだけで済みます。私はまだこの部分を理解することに取り組んでおり、この問題に関する指示を与えるために後で私の答えを編集します。

野avなDOM操作を行っていない場合は、無料のメインスレッドを使用して、lighthouseを使用したアプリの監査でMinimize main-thread workが表示されないようにすることをお勧めします。糸。

2