Next.js: Clientside Web Workers aren't served

Created on 11 Jul 2018  路  11Comments  路  Source: vercel/next.js

Bug report

Describe the bug

When attempting to load web workers using webpack and worker-loader in a production app the worker chunk is built into .next/{BUILD_ID}.worker.js and .next/server/{BUILD_ID}.worker.js, but the client tries to load it from /_next/webpack/{BUILD_ID}.worker.js which isn't served.

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Clone https://github.com/bendman/nextjs-worker-example
  2. Install and run the built site with yarn install && yarn build && yarn start
  3. Navigate to the site. The logs will show a 404 error along the lines of:

GET http://localhost:3000/_next/webpack/7759d1859ec567640742.worker.js 404 (Not Found)

Expected behavior

The worker should load in its own chunk, and the page should show the following logs:

index.js:14 Host received: from Worker
worker.js:1 Worker received: from Host

System information

  • OS: macOS
  • Browser: Chrome
  • Version of Next.js: 6.1.1

Additional context

I've already tried solutions to a different chunk issue (https://github.com/zeit/next.js/issues/4642) with no positive results.

Also, this works fine in dev mode, just not when starting the built app.

Most helpful comment

I鈥檇 be up for having an official plugin in next-plugins for this, could you create it in github.com/zeit/next-plugins? That鈥檇 be super nice for future users 馃檹馃徎馃檶馃徎

All 11 comments

I'm guessing you'll have to provide

name: 'static/[hash].worker.js' (https://github.com/webpack-contrib/worker-loader#name)

And publicPath:

publicPath: '/_next/static/' (https://github.com/webpack-contrib/worker-loader#publicpath)

This will output the worker files to .next/static which Next.js will automatically serve under /_next/static/

Ah, that got me on the right track, thanks. Here is the fix below in a Next config, or you can see the updated repo with a working example. Your fix was close, I just had to remove the static/ from the publicPath to prevent it from looking at /_next/static/static/.

// next.config.js
module.exports = {
  webpack(config, options) {
    config.module.rules.push({
      test: /\.worker\.js$/,
      loader: 'worker-loader',
      // options: { inline: true }, // also works
      options: {
        name: 'static/[hash].worker.js',
        publicPath: '/_next/',
      },
    });
    return config
  }
}

I鈥檇 be up for having an official plugin in next-plugins for this, could you create it in github.com/zeit/next-plugins? That鈥檇 be super nice for future users 馃檹馃徎馃檶馃徎

Hi, I was trying to find a solution to a problem I got regarding web workers.
I'd like to reuse a web worker but I can't get it from the cache, instead it download it again with a 304 and I can't save few precious ms.
Basically how can I endup having the same behavior as in this sample and cache it in some way? : https://www.w3schools.com/html/tryit.asp?filename=tryhtml5_webworker (you'll trigger a worker fetch request by pressing start and stop worker multiple times)
Many thanks!

Ok after searching a bit I just discovered that in 'dev' max-age is 0.
All good then!

Hi, I'm trying to use this solution (+typescript) but I'm always getting 404, and it doesn't matter which workerLoaderOptions I pass, it always tries to load the worker from the same location.

This is my next.config.js file:

// next.config.js
const withTypeScript = require('@zeit/next-typescript');
const withWebWorkers = require('@zeit/next-workers');

let config = {
  webpack: config => Object.assign(config, {
    target: 'electron-renderer',
  }),

  exportPathMap: async function () {
    return {
      '/home': { page: '/home' },
      '/about': { page: '/about' },
    };
  },

  workerLoaderOptions: {
    name: 'static/[hash].worker.js',
    publicPath: '/_next/static/',
  },
};

config = withTypeScript(config);
config = withWebWorkers(config);

module.exports = config;

As you can see, I tried changing the workerLoaderOptions.publicPath because the error is

GET http://localhost:8888/_next/b60848351c7f50d8f1a8.worker.js 404 (Not Found)

but even that, it doesn't change the location.

Generated files are

  • .next/b60848351c7f50d8f1a8.worker.js
  • .next/b60848351c7f50d8f1a8.worker.js.map

but nothing in .next/static

I even tried changing it to:

workerLoaderOptions: {
  name: 'static/WORKER.js', // the name here should be fixed instead of using the hash
  publicPath: '/_next/static/',
},

but again, the generated files and the loaded files are the same (is like it's not using the name and publicPath options?)

Any idea/advice?

System info:

OS: macOS
Electron version: 4.0.4
Version of Next.js: 8.0.1

@danikaze did you determine the issue? I have a very similar setup to yours and am experiencing the same thing. All pages show 404.

@danikaze @zachariahtimothy same issue on my end. Keep getting 404's and seem to be unable to get webpack to read/write worker files to .next/static/. Running into this on both the custom config above and the next.js workers plugin. Any ideas?

@joncursi I was able to get mine working using .js for worker. I tried using custom .ts config with webpack but got 404's no matter what. Note there is wonkiness with HMR causing a manual refresh when worker file changes. I believe this is a browser issue and not too big a deal.

Anyone find a fix for this? Getting same 404.
Maybe can add this one to https://issuehunt.io/ lol

I succeeded!

but I don't know if it's correct.

i just hope that help you. good luck!

OS:window 10
"dependencies": {
"next": "^8.1.0"
"react": "^16.8.6"
"react-dom": "^16.8.6"
"worker-loader": "^2.0.0"
}

"devDependencies": {
"@zeit/next-typescript": "^1.1.1",
"ts-node": "^8.1.0",
"typescript": "^3.4.5"
}

// next.config.js
const withTypescript = require('@zeit/next-typescript');
module.exports = withTypescript({
  webpack(config, options) {
    // Begin: Web Worker 鞝侅毄
    config.module.rules.push({
      test: /\.worker\.js$/,
      loader: 'worker-loader',
      options: {
        inline: true,
        name: 'static/[hash].worker.js',
        publicPath: '/_next/'
      }
    });
    // End: Web Worker 鞝侅毄

    // Overcome webpack referencing `window` in chunks
    config.output.globalObject = `(typeof self !== 'undefined' ? self : this)`;

    return config;
  }
});
// src/webworker/types/index.d.ts
declare module 'worker-loader?name=static/[hash].worker.js!*' {
  class WebpackWorker extends Worker {
    constructor();
  }

  export default WebpackWorker;
}
// src/webworker/example.worker.ts
const ctx: Worker = self as any;

ctx.addEventListener('message', async (event) => {
  console.log('example.worker received 1:', event);
  ctx.postMessage({msgCode: 'S', msg: ''});
});
// src/components/MenuList.tsx
import MyWorker from 'worker-loader?name=static/[hash].worker.js!../webworker/example.worker';

class MenuList extends Component {
  render() {
    return <div onClick={this.goReady} >test!!</div>
  }

  goReady = (strId: string) => () => {
    const worker = new MyWorker();
    worker.postMessage({aaa: 'aaaaa'});
    worker.addEventListener('message', this.onWorkerMessage );
  }

  onWorkerMessage = (event: any) => {
    console.log('onWorkerMessage', event);
  }
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

formula349 picture formula349  路  3Comments

ghost picture ghost  路  3Comments

kenji4569 picture kenji4569  路  3Comments

wagerfield picture wagerfield  路  3Comments

knipferrc picture knipferrc  路  3Comments