How to create an npm package that includes a webworker

dannadori
4 min readJun 22, 2020

Note:
New related post have been published.
How to bundle WebWorker in npm package

I recently created an npm package for Virtual Background. This was the first time in my history to make an npm package.
This time, I’ll try to package the barcode detection part (SemanticSegmentation) of the multi-barcode reader that I created before.

I had made this barcode detection part with webworker. I don’t know how to make a npm package which uses webworker even if I search a lot. I made it by trial and error and I could make it works for the time being. The following is a reminder of that content.

I’m not sure if this is the official way, because I made it work after trial and error. If you find something wrong, please let me know.

What we’re going to package is a semantic segmentation of a large image by dividing into small pieces. By parameterizing the number of pieces, it allows for a trade-off between accuracy and speed. I’m thinking it would be more effective if used on a device with limited performance, such as a smartphone.

The behavior is like this. If you split the screen, the accuracy of Segmentation goes up, but the speed goes down.

Premise

  • Make a npm account.
  • Create a github account and repository.
  • Clone your git repository and move to that directory.

Workflow

First, let’s configure and log in to npm.

$ npm set init.author.name "xxxxxx"
$ npm set init.author.email "xxxx@xxxx.co.jp"
$ npm set init.author.url "https://qiita.com/wok"
$ npm adduser

Now, let’s initialize project and install the packages and webpack needed for project.

npm init -y
npm install --save-dev webpack webpack-cli
npm install --save-dev typescript ts-loader
npm install -D tsconfig-paths
npm install -D rimraf npm-run-all

Initialize tsconfig.json and set the necessary items.
In this case, we enable type declaration and source map generation. We also set the output to . /dist.
If you don’t need to generate a source map, don’t create it.

npx tsc --init

$cat tsconfig.json
<snip>
"declaration": true,
"sourceMap": true,
"outDir": "./dist",

Next, set the webpack.

Here we use the same name for (1) entry and (2) filename as the package name. This is one of the results of trial and error.

I created a webworker using the worker-plugin this time, but I couldn’t figure out how to put the webworker into main script file. As a result, I created the webworker script as a separate file and have it manually placed directly under public. (Installation scripts are provided.)

If you create a webworker using the worker-plugin, the filename of webworker inherits the main script name. For example “0.scalable-semantic-segmentation.worker.js” To make sure that the name of the file is not the same as the name of existing file in the public, we use package name for the filename.

$ cat > webpack.config.js
const path = require('path');

module.exports = {
mode: 'development',
entry: './src/scalable-semantic-segmentation.ts', // <-- (1)
resolve: {
extensions: [".ts", ".js"],
},
module: {
rules: [
{ test: /\.ts$/, loader: 'ts-loader' },
],
},
output: {
filename: 'scalable-semantic-segmentation.js', // <-- (2)
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'umd',
globalObject: 'typeof self !== \'undefined\' ? self : this'
},
};

You need to change the main package.json file according to the webpack settings. Also, we need to set up the script.

"main": "dist/scalable-semantic-segmentation.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"webpack": "npx webpack --config webpack.config.js",
"clean": "rimraf dist/*",
"build": "npm-run-all clean webpack"
},

Next, install the worker-plugin.

npm install -D worker-plugin

Edit webpack.config.js to enable worker-plugin.
Add parts (1) and (2).

const path = require('path');
const WorkerPlugin = require('worker-plugin'); // <--- (1)
module.exports = {
mode: 'development',
entry: './src/scalable-semantic-segmentation.ts',
resolve: {
extensions: [".ts", ".js"],
},
module: {
rules: [
{ test: /\.ts$/, loader: 'ts-loader' },
],
},
output: {
filename: 'scalable-semantic-segmentation.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'umd',
globalObject: 'typeof self !== \'undefined\' ? self : this'
},
plugins: [ // <--- (2)
new WorkerPlugin()
]
};

As mentioned above, this time we have created the webworker as a separate script from the main script. You need to copy this to a public dirctory (under the root of the web). Create a script that does this and place it in the bin directory.

const fs = require('fs');
const path = require('path');
const package_name = 'scalable-semantic-segmentation-js'
const src = path.join('node_modules', package_name, 'dist', '0.scalable-semantic-segmentation.worker.js')
const dst = path.join(process.argv[2], '0.scalable-semantic-segmentation.worker.js')

try {
fs.copyFileSync(src, dst, fs.constants.COPYFILE_EXCL);
console.log('file is copied');
} catch (error) {
console.log(error);
}

Now we need to create a “.gitignore” and a “.npmignore”.

$ cat > .gitignore
*~
*#
node_modules
dist

$ cat > .npmignore
*~
*#
node_modules
demo
src

All that’s left is to create the source code, build it, publish and you’re done.

npm publish

Output

I am very thirsty!!

Sign up to discover human stories that deepen your understanding of the world.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

dannadori
dannadori

Written by dannadori

Software researcher and engineer

No responses yet

Write a response