阅读Angular文档,您可以找到几个references to bootstrap your whole Angular app inside a Web Worker,因此您的UI不会被大量的JS使用阻止。
然而,目前还没有关于如何做到这一点的官方信息,以及Angular Doc中的唯一信息。这是一个实验性功能。
如何使用此方法来利用Angular中的Web工作者?
答案 0 :(得分:70)
对于Angular 7,请参阅下面的答案。
我花了很多时间来弄明白该怎么做,所以我希望this can help someone。
我假设你有一个使用Angular CLI 1.0或更高版本生成的Angular项目(版本2或4)。
使用CLI生成项目并不是必须遵循此步骤,但我将提供与webpack文件相关的说明,它们基于CLI webpack配置。
从Angular CLI v1.0开始,就有“弹出”功能,它允许你提取webpack配置文件并按照你的意愿操作它。
运行ng eject
以便Angular CLI生成 webpack.config.js 文件。
运行npm install
以满足CLI生成的新依赖关系
运行npm install --save @angular/platform-webworker @angular/platform-webworker-dynamic
将BrowserModule
替换为app.module.ts文件中的WorkerAppModule
。您还需要更新import语句才能使用@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 { }

将引导程序替换为: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');

polyfills.ts
,@angular/core
和@angular/common
个包。在接下来的步骤中,您将更新Webpack以便转换并构建包含结果的包。platformWorkerAppDynamic
AppModule
(从 main.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);

webpack自动生成的配置文件很长,但您只需要将注意力集中在以下方面:
为webworker
文件添加workerLoader.ts
入口点。如果查看输出,您会看到它将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服务器,并且在网络工作者在控制台日志上抛出错误消息时遇到了某种问题。无论如何,网络工作者似乎运行良好。
如果您使用webpack
命令编译应用程序并从任何http服务器(如simplehttpserver)提供,则错误消失;)
您可以从this repo获取整个代码(webpack config,app.module.ts,...)。
您还可以在此处观看live demo,以查看使用Web Workers之间的差异
答案 1 :(得分:2)
好消息,我让它可以与Angular 7一起使用!
要求:npm install --save-dev @angular-builders/custom-webpack html-webpack-plugin
如果您只想从下面复制/粘贴代码,请确保您的环境文件中包含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加载之外,您的大多数应用程序在第二个线程中。