How to use a web worker that needs to import node module?

I´d like to use the following npm package in my meteor application: https://github.com/Yoast/javascript/tree/develop/packages/yoastseo

In the Usage section it describes to create a web worker, which needs to import the following:

import { AnalysisWebWorker } from "yoastseo";

In meteor you can put the web worker script in the public folder, then it will be accessible to the client but it wont be able to import the node module.

Is there any way to do that with meteor?

My research has been hopeless so far.

Any help is greatly appreciated!

You should make this worker file available as a dynamic import. To do so, add import(‘your-npm-module/workerfile.js’) somewhere in your code where it doesn’t get executed, for example if (false) {…}. Meteor build system will detect that you may want to use it dynamically and will package it separately.

Maybe try to go this way: Web workers: Why and how we use them • Yoast Developer Blog

Write your script where you import the library and then const worker = new Worker( ‘/path/to/worker-script.js’ ) in your client startup.
Alternatively, if you find a CDN version of the library, you can import it in a public/sw.js with importScripts('https://......')

I just tried, but how do I get to know the url for the seperate worker package? Is that even possible?

You need to provide the full url, as per documentation:

// `url` needs to be the full URL to the script for the browser to know where to load the worker script from.
// This should be the script created by the previous code-snippet.
const url = "https://my-site-url.com/path-to-webworker-script.js"

const worker = new AnalysisWorkerWrapper( createWorker( url ) );

I tried looking in chrome devtools sources after implementing the dynamic import, but cant find the script.

I wish there would be a CDN version, but I couldnt find any, probably because it has a lot of dependencies:

  "dependencies": {
    "@wordpress/autop": "^2.0.2",
    "@yoast/feature-flag": "^0.5.2",
    "htmlparser2": "^3.9.2",
    "jed": "^1.1.0",
    "lodash-es": "^4.17.10",
    "loglevel": "^1.6.1",
    "parse5": "^5.1.0",
    "sassdash": "0.9.0",
    "tokenizer2": "^2.0.1"
  },

Maybe it would be possible to manually put all required node modules in the public folder? But that would seem quite hacky and not right…

I found this post

Which suggests to bundle the yoast js script into a bundle using webpack. I tried (without any knowledge in webpack) to do that, but more or less with trial and error. I am not able to find any kind of guid for this sort of thing. Anyone might be able to point me in the right direction?

I am also noticing right now, I probably should head to the yoast repository and ask the question there, it doesnt really seem to have much to do with meteor.

Finally figured it out, I used webpack cli to bundle this file:

import { AnalysisWebWorker } from "yoastseo";

const worker = new AnalysisWebWorker( self );
worker.register();

Then I put the bundle in the public directory and voila now it works.

In case anyone faces the same problem, here the Webpack CLI command:

npx webpack-cli ./yoast-worker.js -o worke-bundle --config=webpack.config.js

webpack.config.js:

const webpack = require("webpack")

module.exports = {

    //...

    resolve: {

        preferRelative: true,

        fallback: {

            util: require.resolve("util"),

            buffer: require.resolve("buffer"),

        },

    },

    plugins: [

        new webpack.DefinePlugin({

            "process.env.NODE_DEBUG": false,

        }),

    ],

}
1 Like