Angular 使用 Web Worker 生成的 CLI 应用程序
Angular CLI generated app with Web Workers
阅读 Angular 文档,您可以找到几个 references to bootstrap your whole Angular app inside a Web Worker,因此您的 UI 不会因大量使用 JS 而受阻。
然而,目前还没有关于如何做到这一点的官方信息,而且只有 Angular 文档中的信息。这是一个实验性功能。
如何使用这种方法来利用 Angular 中的网络工作者?
对于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 bootstrap 依赖项
运行 npm install --save @angular/platform-webworker @angular/platform-webworker-dynamic
3。 UI 线程中的更改 bootstrap
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
中的变化
将 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
- 使用此
platformWorkerAppDynamic
平台导入 AppModule
(从 main.ts 中删除导入)和 bootstrap 它。
// 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 前缀。这就是为什么在 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 更加流畅。
进一步说明
npm start
运行s webpack-dev 服务器,它有一些问题,网络工作者在控制台日志上抛出错误消息。无论如何,网络工作者似乎 运行 没问题。
如果您使用 webpack
命令编译应用程序并从任何像 simplehttpserver 这样的 http 服务器提供它,错误就会消失 ;)
示例代码和演示
您可以从 this repo.
获取完整代码(webpack 配置,app.module.ts,...)
您也可以在这里观看 live demo,了解是否使用 Web Workers 的区别
伙计们好消息,我得到了这个与 Angular 7 一起工作!
要求:npm install --save-dev @angular-builders/custom-webpack html-webpack-plugin
如果您只想从下面 copy/past 代码,请确保您的 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 操作,那么您最好使用免费的主线程,并且使用灯塔审核您的应用程序不应再显示 Minimize main-thread work
,因为大多数除了 UI 在第二个线程中加载之外的应用程序。
阅读 Angular 文档,您可以找到几个 references to bootstrap your whole Angular app inside a Web Worker,因此您的 UI 不会因大量使用 JS 而受阻。
然而,目前还没有关于如何做到这一点的官方信息,而且只有 Angular 文档中的信息。这是一个实验性功能。
如何使用这种方法来利用 Angular 中的网络工作者?
对于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 bootstrap 依赖项
运行 npm install --save @angular/platform-webworker @angular/platform-webworker-dynamic
3。 UI 线程中的更改 bootstrap
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
中的变化将 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
- 使用此
platformWorkerAppDynamic
平台导入AppModule
(从 main.ts 中删除导入)和 bootstrap 它。
// 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 前缀。这就是为什么在 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 更加流畅。
进一步说明
npm start
运行s webpack-dev 服务器,它有一些问题,网络工作者在控制台日志上抛出错误消息。无论如何,网络工作者似乎 运行 没问题。
如果您使用 webpack
命令编译应用程序并从任何像 simplehttpserver 这样的 http 服务器提供它,错误就会消失 ;)
示例代码和演示
您可以从 this repo.
获取完整代码(webpack 配置,app.module.ts,...)您也可以在这里观看 live demo,了解是否使用 Web Workers 的区别
伙计们好消息,我得到了这个与 Angular 7 一起工作!
要求:npm install --save-dev @angular-builders/custom-webpack html-webpack-plugin
如果您只想从下面 copy/past 代码,请确保您的 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 操作,那么您最好使用免费的主线程,并且使用灯塔审核您的应用程序不应再显示 Minimize main-thread work
,因为大多数除了 UI 在第二个线程中加载之外的应用程序。