Webpack worker-loader fails to compile typescript worker
Asked Answered
B

2

13

I am configuring my project as described in worker-loader documentation and I was able to get TS code intel working using the correct d.ts.

However, during webpack build it throws an error and I don't understand why.

 ERROR in ./src/test.worker.ts
Module parse failed: Unexpected token (1:9)
You may need an appropriate loader to handle this file type.
| const ctx: Worker = self as any;
| ctx.addEventListener('message', event => {
|   console.log(event);

My worker file content test.worker.ts:

const ctx: Worker = self as any;
ctx.addEventListener('message', event => {
  console.log(event);
  setTimeout(() => ctx.postMessage({
    foo: 'boo'
  }), 5000);
});

Application entry index.ts

import TestWorker from './test.worker.ts';

const test = new TestWorker();
test.postMessage({});

And finally here is my webpack.config.js

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const DIR_SOURCE = path.resolve(__dirname, 'src');
const DIR_BUILD = path.resolve(__dirname, 'build');

module.exports = {

  entry: `${DIR_SOURCE}/index.tsx`,

  output: {
    path: DIR_BUILD,
    filename: 'project.bundle.js'
  },

  devtool: "source-map",

  resolve: {
    // Add '.ts' and '.tsx' as resolvable extensions.
    extensions: [".ts", ".tsx", ".js", ".json"]
  },

  module: {
    rules: [
      {test: /\.tsx?$/, loader: "ts-loader" },
      {test: /\.worker\.ts$/, use: ['ts-loader', 'worker-loader'] },
      {test: [/\.vert$/, /\.frag$/], use: 'raw-loader'},
      {test: /\.(png|jpg|gif|svg)$/, use: {loader: 'file-loader', options: {}} },
      {test: /.*\.sass/, use: ['style-loader', 'css-loader', 'sass-loader'] },
    ]
  },

  plugins: [
    new webpack.DefinePlugin({
      'CANVAS_RENDERER': JSON.stringify(true),
      'WEBGL_RENDERER': JSON.stringify(true)
    }),
    new HtmlWebpackPlugin({
      template: 'src/index.ejs'
    }),
  ]
};

Any help is much appreciated.

Thank you :)

Buskus answered 7/5, 2018 at 8:55 Comment(0)
B
26

Ok I figured it out.

First I needed to move worker loader before the ts-loader and did not need to specify array in worker use property and just keep it as described in documentation of worker-loader.

module: {
    rules: [
      {test: /\.worker\.ts$/, loader: 'worker-loader'},
      {test: /\.tsx?$/, loader: "ts-loader" },
      {test: [/\.vert$/, /\.frag$/], use: 'raw-loader'},
      {test: /\.(png|jpg|gif|svg)$/, use: {loader: 'file-loader', options: {}} },
      {test: /.*\.sass/, use: ['style-loader', 'css-loader', 'sass-loader'] },
    ]
  },

Then in my worker I also needed to export anything otherwise typescript (2.8.3) would complain that it can't find a module and I export default null as any to avoid confusing ts even further.

worker.js

const ctx: Worker = self as any;
ctx.addEventListener('message', event => {
  console.log(event);
  setTimeout(() => ctx.postMessage({
    foo: 'boo'
  }), 5000);
});
export default null as any;

index.js

import TestWorker from './test.worker.ts';
const test = new TestWorker('');
test.postMessage({});
Buskus answered 7/5, 2018 at 9:52 Comment(3)
This is not working for me. I end up with JS compiled as var test_worker_1 = __webpack_require__('./src/test.worker.ts'); var worker = new test_worker_1.default();. It should compile to ... new test_worker_1();Prelusive
ts need a module for compiling. To avoid this null issue, we just need add a dummy class declaration to replace this "export default null as any". export default class WebpackWorker extends Worker { constructor() { super(""); } } Milled
export default null happy and sad at the same time that this line had to save my sanity. Thank you!Remarkable
R
5

Thanks Dmitry, you helped me get much further along in getting worker-loader to build my Typescript project.

Even so I had three more issues I needed to solve in order to get it to work:

  • The build would hang when I added worker-loader above ts-loader/awesome-typescript-loader. I fixed this by making the import paths be much more specific for types that were imported/exported from the web worker module. I found out by trying to comment out the content of the web worker entry file, and then uncomment one line at a time, to see what would and wouldn't build.

  • The second thing I did wrong was that I added worker-loader both as a rule my webpack config, and in the import statement. I was basically running worker-loader twice on the web worker module. Doh. So either add worker-loader to your webpack config or add 'worker-loader!' to the import/require statement. I added worker-loader to my webpack config and the just imported like this: import MyWorker = require('./my-worker');

  • I got a typeerror MyWorker is not a constructor when I tried to do new MyWorker(), and had to cast MyWorker to any for the Typescript type checker to swallow it: new (MyWorker as any)();

Hope this helps somebody.

Rhyne answered 23/11, 2018 at 12:32 Comment(3)
yep I solved last problem by exporting as any from worker too export default null as any; Buskus
I got the some_worker.default is not a constructor error during runtime, not during build. Did you come across something like that too?Illona
@VickyLeong I had the same problem now, it turns out Webpack was giving me lambda function, not a constructor, so I had to call it, not creating new instance.Encarnacion

© 2022 - 2024 — McMap. All rights reserved.