Skip to content
This repository has been archived by the owner on Sep 9, 2021. It is now read-only.

(TypeScript) my_worker_1.default is not a constructor #190

Closed
nalbion opened this issue Feb 28, 2019 · 6 comments
Closed

(TypeScript) my_worker_1.default is not a constructor #190

nalbion opened this issue Feb 28, 2019 · 6 comments

Comments

@nalbion
Copy link

nalbion commented Feb 28, 2019

"typescript": "3.1.6",
"webpack": "4.29.1",
"worker-loader": "2.0.0"

The typescript below compiles to

var my_worker_1 = __webpack_require__('./src/my.worker.ts'); 
var worker = new my_worker_1.default();

When the app runs, my_worker_1 evaluates to:

ƒ () {
  return new Worker(__webpack_require__.p + "ca60d2657d7fa455bc31.worker.js");
}

An error is therefore thrown: my_worker_1.default is not a constructor
The code should compile to the following, without reference to .default

var my_worker_1 = __webpack_require__('./src/my.worker.ts'); 
var worker = new my_worker_1();  // Note: no ".default"

my.worker.ts

const ctx: Worker = self as any;
ctx.addEventListener('message', (event) => {
   // do stuff
});

export default null as any;

app.ts

import MyWorker from './my.worker'
// this didn't make any difference: import MyWorker from 'worker-loader!./my.worker';

var worker = new MyWorker();

webpack.config.js

rules: [
      {
        test: /\.worker\.ts$/,
        use: { loader: 'worker-loader' } // does not make any difference: , options: {inline: true} }
      },
      {
        test: /\.tsx?$/,
        use: [
          {loader: 'awesome-typescript-loader'}
        ]
      },
      {
        exclude: [
          //...
          /\.worker\.ts$/
        ],
        loader: 'file-loader',
        options: {
          name: 'static/media/[name].[hash:8].[ext]',
        },
      },
@nalbion
Copy link
Author

nalbion commented Feb 28, 2019

I can avoid the my_worker_1.default is not a constructor error if I use

import * as MyWorker from 'worker-loader!./my.worker';

but then I get:

bootstrap:1 Uncaught ReferenceError: window is not defined
    at bootstrap:1
    at bootstrap:788

var parentHotUpdateCallback = window["webpackHotUpdate"];
...
// Load entry module and return exports
 	return hotCreateRequire("./node_modules/string-replace-loader/index.js?!" + 
                                                "./node_modules/awesome-typescript-loader/dist/entry.js!" + 
                                                "./src/my.worker.ts")
                                               (__webpack_require__.s = 
                                                 "./node_modules/string-replace-loader/index.js?!" + 
                                                 "./node_modules/awesome-typescript-loader/dist/entry.js!" + 
                                                 "./src/my.worker.ts");

The fix for this problem is to add globalObject: 'this' to the webpack config as mentioned in #142

...but with the worker-loader! prefix in app.ts the worker code doesn't actually run and there are no errors logged to the console. The fix - drop the prefix:

import * as MyWorker from './my.worker';

...but even then TypeScript complains about the type of MyWorker:

Cannot use 'new' with an expression whose type lacks a call or construct signature

Solution:

const worker = new (MyWorker as any)();

@bfricka
Copy link

bfricka commented May 1, 2019

In tsconfig.json add:

{
  "compilerOptions": {
    "esModuleInterop": true
  }
}

In *.worker.ts:

// Trickery to fix TypeScript since this will be done by "worker-loader"
export default {} as typeof Worker & (new () => Worker);

Now you can use your worker as a normal default import:

import MyWorker from './my.worker.ts';

TypeScript now sees MyWorker as type Worker and you no longer need to import from 'worker-loader!./my.worker.ts';. Instead, set up worker-loader in your webpack config. E.g. in my case this is a drop in for an ejected CRA in the oneOf list where TS_LOADER is defined (basically '@ts-tools/webpack-loader' for me):

{
  test: /\.worker.ts$/,
  use: [
    {
      loader: require.resolve('worker-loader'),
      options: {
        name: 'static/js/[name].js',
        publicPath,
      },
    },
    TS_LOADER,
  ],
},
{
  test: /\.tsx?$/,
  ...TS_LOADER,
},

@steida
Copy link

steida commented May 7, 2019

@bfricka Thank you. It works. Except I don't need esModuleInterop in my tsconfig.json

@bfricka
Copy link

bfricka commented May 8, 2019

@steida Yeah, that was an oversight. It's fine since it's a default export. Oops!

@alexander-akait
Copy link
Member

Here two problems:

  1. bad typescript documentation
  2. compatibility with webpack-dev-server

So close in favor #253 and #174

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants