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.
Steps to reproduce the behavior, please provide code snippets or a repository:
yarn install && yarn build && yarn startGET http://localhost:3000/_next/webpack/7759d1859ec567640742.worker.js 404 (Not Found)
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
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.
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.mapbut 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?
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);
}
}
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 馃檹馃徎馃檶馃徎