【问题标题】:Angular CLI generated app with Web WorkersAngular CLI 使用 Web Workers 生成应用程序
【发布时间】:2017-09-02 17:10:32
【问题描述】:

阅读 Angular 文档,你可以找到几个 references to bootstrap your whole Angular app inside a Web Worker,这样你的 UI 就不会被大量的 JS 使用所阻塞。

但是,目前没有关于如何执行此操作的官方信息,只有 Angular 文档中的信息。是不是这是一个实验性功能。

如何使用这种方法来利用 Angular 中的网络工作者?

【问题讨论】:

    标签: angular web-worker


    【解决方案1】:

    好消息,伙计们,我可以在 Angular 7 中使用它! ???

    要求npm install --save-dev @angular-builders/custom-webpack html-webpack-plugin 如果您只想从下面复制/粘贴代码,请确保您的 env 文件中有 production:true

    第 1 步:按以下方式编辑 angular.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 操作并将其替换为其他内容。我仍在努力解决这部分问题,稍后将编辑我的答案以提供有关此问题的指导。

    如果您不进行野蛮的 DOM 操作,那么您最好使用免费的主线程,并且使用 lighthouse 审核您的应用程序不应再显示Minimize main-thread work,因为您的大多数应用程序除了 UI 加载第二个线程。

    【讨论】:

    • 问题是这样的:在像window['webpackJSONPCallback']这样的行中找不到窗口???你什么都没有。您必须使用 webpack 多个目标来编译它,但是 angular cli 不支持 webpack 配置中的数组。由于这个原因,延迟加载不起作用。
    • 真的吗?即使我使用延迟加载,我也没有这个问题。
    • 那么如何使用配置了 target: 'web' 的 webpack 加载惰性模块?你必须得到一个错误:找不到窗口。不是吗?如果没有,请给我一个例子。我绝对确定这行不通。看到这个:webpack.js.org/concepts/targets
    【解决方案2】:

    对于 Angular 7,请参阅下面的答案。

    我花了很多时间弄清楚怎么做,所以我希望this can help someone

    前提条件

    我假设您有一个使用 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 引导依赖项

    运行npm install --save @angular/platform-webworker @angular/platform-webworker-dynamic

    3。 UI 线程引导的变化

    3.1 app.module.ts 的变化

    将 app.module.ts 文件中的 BrowserModule 替换为 WorkerAppModule。您还需要更新导入语句才能使用@angular/platform-webworker 库。

    //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 的变化

    将引导过程替换为:bootstrapWorkerUI(同时更新导入)。

    您需要将 URL 与定义 Web Worker 的文件一起传递。使用名为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(从 ma​​in.ts 中删除导入)并使用此 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 文件添加一个webworker入口点。如果您查看输出,您会看到它为所有块附加了一个 bundle.js 前缀。这就是为什么在引导步骤中我们使用了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 更加流畅。

    补充说明

    npm start 运行 webpack-dev 服务器,它有一些问题,webworkers 在控制台日志上抛出错误消息。无论如何,网络工作者似乎运行良好。 如果您使用webpack 命令编译应用程序并从任何http 服务器(如simplehttpserver)提供它,错误就会消失;)

    示例代码和演示

    您可以从this repo 获取整个代码(webpack 配置、app.module.ts、...)。

    您也可以在这里观看live demo,了解使用与不使用 Web Workers 的区别

    【讨论】:

    • 很好的答案@Kaik!感谢您为社区提供的所有帮助 :) 出于好奇,您是否注意到性能有所改进?
    • @Maxime 您可以尝试链接中的演示。在用户体验方面有很大的好处,因为即使您在业务逻辑中运行繁重的东西,UI 也能顺利运行。
    • 我之前没有看到演示链接,感谢您指出!太不可思议了……迫不及待想在我的应用程序上尝试一下!再次感谢:)
    • @KaiK 很好的答案!我刚刚尝试在全新安装的 cli v1.0 上运行它,当我运行 npm start 时,页面只是挂在 Loading...
    • @MurhafSousli 如果您使用的是 material2,则无法使用 webworker,因为它会多次调用来操作 DOM。目前 material2 和 webworkers 还没有起步。
    猜你喜欢
    • 2017-12-17
    • 1970-01-01
    • 2018-02-14
    • 2018-11-21
    • 1970-01-01
    • 1970-01-01
    • 2018-05-11
    • 2016-11-26
    • 2017-11-17
    相关资源
    最近更新 更多