使用WebPack在Web Worker中运行Angular 2应用程序

12

我正在尝试将整个Angular 2应用程序的执行移动到Web Worker中,但我发现目前所有可用的示例都使用System.js,而我正在尝试使用基于WebPack的项目(使用angular-cli构建)进行操作。

是否有人已经完成了这个过程或者对如何在WebPack中实现有所了解?

以下是我的main.ts引导文件:

import './polyfills.ts';


import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';


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

import {bootstrapWorkerUi} from '@angular/platform-webworker';
bootstrapWorkerUi('/app/loader.js');

我的loader.js看起来是这样的:

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

platformWorkerAppDynamic().bootstrapModule(AppModule);

我的app.module.ts这样声明了@NgModule

import { NgModule } from '@angular/core';
import {WorkerAppModule} from '@angular/platform-webworker';


import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    WorkerAppModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
 export class AppModule { }

然而,当我运行它时,我遇到了错误 Uncaught SyntaxError: Unexpected token import in loader.js:1。

问题似乎与webpack有关,在webworker端缺少@angular库的一些导入,正如Tamas Gegedus和MathMate所建议的那样,因此下一步是修改webpack配置文件,以便为webworker提供所有所需的库。我会处理这个问题。

----------- 更新 -----------

由于angular-cli没有提供对webpack.config.js文件的访问,因此我引入了自己的文件,在代码中进行了一些小改动,使其能够工作。我在webpack配置文件中创建了第二个入口点,并出现了错误 VM33:106 Uncaught ReferenceError: window is not defined

Webpack配置文件如下:

var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var helpers = require('./config/helpers');


module.exports = {
  entry: {
    'app': ['./src/polyfills.ts', './src/vendor.ts', './src/main.ts'],
    'webworker': ['./src/workerLoader.ts']
  },

  resolve: {
    extensions: ['', '.ts', '.js']
  },

  output: {
    path: helpers.root('dist'),
    publicPath: 'http://localhost:8080/',
    filename: '[name].js'
  },

  devtool: 'cheap-module-eval-source-map',

  module: {
    loaders: [
      {
        test: /\.ts$/,
        loaders: ['awesome-typescript-loader?tsconfig=./src/tsconfig.json', 'angular2-template-loader']
      },
      {
        test: /\.html$/,
        loader: 'html'
      },
      {
        test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
        loader: 'file?name=assets/[name].[hash].[ext]'
      },
      {
        test: /\.css$/,
        exclude: helpers.root('src', 'app'),
        loader: ExtractTextPlugin.extract('style', 'css?sourceMap')
      },
      {
        test: /\.css$/,
        include: helpers.root('src', 'app'),
        loader: 'raw'
      }
    ]
  },

  plugins: [
    new HtmlWebpackPlugin({
      template: 'src/index.html',
      excludeChunks: ['webworker']
    }),

    new ExtractTextPlugin('[name].css')
  ]
};

其中polyfills.ts和vendor.ts分别包含polyfills和Angular库。

我创建了两个入口点,生成了两个输出(app.js和webworker.js)。

使用HtmlWebpackPlugin时,第一个输出将被包括在index.html文件中,但第二个不会。

当index.html被包含时,main.ts(包含在app.js中)将被调用,并尝试使用webpack的第二个输出(webworker.js)来引导Web Worker

import {bootstrapWorkerUi} from '@angular/platform-webworker';
bootstrapWorkerUi('../webworker.js');

webworker.js是通过使用workerLoader.ts入口由Webpack生成的,类似于先前的loader.js,但包含一些导入。

WorkerLoader.ts文件看起来像这样:

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

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

platformWorkerAppDynamic().bootstrapModule(AppModule);

我知道Web Worker已经被生成,如下图所示,但是如图所示,我遇到了错误VM33: 106 Uncaught ReferenceError:window未定义,除了index.html中的加载消息外,没有显示任何内容。 web worker instance 另一方面,我认为webpack配置是正确的,因为如果在无 WebWorker 模式下运行应用程序,则可以正常工作。
现在我认为这个问题与WebWorker引导有关,但我在这里卡住了。
任何帮助都将不胜感激 ;)

这意味着你在HTML中没有引用Webpack编译后的捆绑包,而是使用了原始的ES6文件。 - Tamas Hegedus
当应用作为单线程设置时(使用典型的引导程序和已经使用Webpack),应用程序运行得很好,但是当我在代码中引入更改以便在WebWorker内运行它时,问题就出现了。 - Enrique Oriol
我成功构建了一个项目并重现了你的问题:到目前为止,我理解的是有一个对ie-shim的引用,它向window对象添加了一些内容,从而破坏了运行时。 - user2363245
好的,现在正在工作。使用angular/angular2-seed作为基线和https://github.com/angular/angular/blob/master/modules/playground/src/web_workers/router/index.ts来配置主要和加载程序。我会尽快发布存储库URL。 - user2363245
太棒了!需要看看你是怎么做的,请。我在这方面很苦恼。 - user3087827
显示剩余5条评论
2个回答

9

我终于解决了这个问题 :)

注意: 如果您使用 Angular CLI 1.0 或更高版本生成项目,则现在可以使用它们自己的 webpack 配置文件,这简化了整个过程。在这种情况下,请查看此答案

在使用我的自定义 webpack 配置运行代码后,我意识到错误 VM33:106 Uncaught ReferenceError: window is not defined 是由 webpack-dev-server 导致的

我通过以下方式解决了它:

1 - 进行独立的 webpack 构建

$: webpack --watch #this creates the bundes at myProject/dist

并且

2- 使用其他开发服务器工具进行运行,例如simplehttpserver

$: npm install simplehttpserver -g
$: simplehttpserver -p 8080 dist/ #as my webpack bundle is included in index.html using that port by default

看,错误已经消失了,它只是工作了!

 

对Angular-CLI项目应用的更改:Webpack配置

让我总结一下有关原始Angular-CLI项目的webpack更改。

由于angular-cli不提供访问webpack.config.js文件并且自定义webpack是使用Web Workers的关键,因此我已经包含了我的文件,并对代码进行了少量更改。

Webpack配置文件如下:

var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var helpers = require('./config/helpers');


module.exports = {
  entry: {
    'app': ['./src/polyfills.ts', './src/vendor.ts', './src/main.ts'],
    'webworker': ['./src/workerLoader.ts']
  },

  resolve: {
    extensions: ['', '.ts', '.js']
  },

  output: {
    path: helpers.root('dist'),
    publicPath: 'http://localhost:8080/',
    filename: '[name].js'
  },

  devtool: 'cheap-module-eval-source-map',

  module: {
    loaders: [
      {
        test: /\.ts$/,
        loaders: ['awesome-typescript-loader?tsconfig=./src/tsconfig.json', 'angular2-template-loader']
      },
      {
        test: /\.html$/,
        loader: 'html'
      },
      {
        test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
        loader: 'file?name=assets/[name].[hash].[ext]'
      },
      {
        test: /\.css$/,
        exclude: helpers.root('src', 'app'),
        loader: ExtractTextPlugin.extract('style', 'css?sourceMap')
      },
      {
        test: /\.css$/,
        include: helpers.root('src', 'app'),
        loader: 'raw'
      }
    ]
  },

  plugins: [
    new HtmlWebpackPlugin({
      template: 'src/index.html',
      excludeChunks: ['webworker']
    }),

    new ExtractTextPlugin('[name].css')
  ]
};

polyfills.ts和vendor.ts分别包含了polyfills和Angular库。

我创建了两个入口点,生成了两个输出文件(app.js和webworker.js)。

使用HtmlWebpackPlugin时,第一个文件被包含在index.html文件中,但第二个文件没有被包含。

当index.html被包含时,main.ts(包含在app.js中)被调用,并且这样启动webworker

import {bootstrapWorkerUi} from '@angular/platform-webworker';
bootstrapWorkerUi('../webworker.js');

"webworker.js"是使用"workerLoader.ts"作为入口点由webpack生成的代码。
"workerLoader.ts"文件如下:

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

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

platformWorkerAppDynamic().bootstrapModule(AppModule);

而 AppModule 看起来像这样:

import { NgModule } from '@angular/core';
import {WorkerAppModule} from '@angular/platform-webworker';


import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    WorkerAppModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
 export class AppModule { }

代码示例

为了更容易地理解差异,我创建了一个项目,展示如何将常规的angular 2项目转换为基于Web Workers的项目。请查看此存储库:https://github.com/kaikcreator/webWorkerFactorialExample

您将在主分支中看到“单线程”代码,在webWorkers分支中,可以看到使用Web Workers运行代码的更改。


1
我尝试了你的解决方案,但在 worker 中仍然出现了“window 未定义”的错误。问题似乎是在 webworker.js 打包文件中,webpack 引用了与 UI 线程绑定的 window 对象。你能帮我解决这个问题吗? - NewtonCode
@Ced 这个在移动设备上应该运行得更快:https://medium.com/@areai51/the-4-stages-of-perf-tuning-for-your-angular2-app-922ce5c1b294#.tkquhoy3h - Tomer Almog
Angular CLI 允许从 1.0.0-beta.38 开始通过调用 ng eject 来弹出 Webpack 配置:https://github.com/angular/angular-cli/issues/2047 - christianliebel
1
@chliebel 我已经创建了一个新的SO,针对使用CLI 1.0+的情况提供了答案,这样你就可以利用从ng eject创建的webpack配置文件。在这里查看:https://dev59.com/01gQ5IYBdhLWcg3wIASb#43276045 - Enrique Oriol
如果插件是用 Angular 构建的并且设计良好,它们不会直接访问 DOM,而是具有渲染无关性,因此在这种情况下没有问题。否则...我认为你不能使用它们 :( - Enrique Oriol
显示剩余3条评论

1
如Tamas Hegedus在评论中已经提到的那样,很可能你的webpack捆绑包仍然引用了loader.js的es6文件。
你需要创建一个单独的捆绑包,入口点为loader脚本。
如果您分享您的webpack配置,那么更容易告诉哪里可能出了问题。
此外,您的加载器脚本需要具有所需的polyfills。您可以添加
import 'core-js/es7/reflect'; import 'zone.js/dist/zone';

好的,我已经认为问题是在这个方向上了,但是你的评论让它更加清晰明了。问题是angular-cli内部使用webpack,但没有任何webpack.config.js文件。我会找出如何使用配置文件,并如何定义新的入口点,以便在此留下解决方案。 - Enrique Oriol
我尝试使用加载器脚本的第二个入口点,但现在我在Web工作程序中遇到了错误“VM33:106 Uncaught ReferenceError:window未定义”。我已更新问题以分享所有细节。 - Enrique Oriol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接