diff --git a/README.md b/README.md index 42d786cc..4993ca6e 100644 --- a/README.md +++ b/README.md @@ -253,6 +253,29 @@ This can be customized by passing the command line argument `--css-modules "[nam | true | import './my-file.css'; | :white_check_mark: | | true | import './my-file.module.css'; | :white_check_mark: | +### Building web workers as inline blobs + +Through the [rollup-plugin-web-worker-loader](https://github.com/darionco/rollup-plugin-web-worker-loader), microbundle can be instructed to create inlined JavaScript source blobs which contain all dependencies to run within a WebWorker execution context. Consider the following minimal example: + +```js +// main.js +import MyWorker from 'worker-loader:./my-worker'; +const myWorker = new MyWorker(); +myWorker.postMessage(3.14159); + +// my-worker.js +import { longRunningJob } from 'heavy-calculations'; // Imports will be inlined +self.onmessage = message => self.postMessage(longRunningJob(message.data)); +``` + +And build it like this: + +```bash +microbundle --worker-loader +``` + +**Note** For usage in TypeScript projects, have a look at the [rollup-typescript-webworkers](https://github.com/darionco/rollup-typescript-webworkers) example by the rollup-plugin-web-worker-loader maintainers. + ### Mangling Properties To achieve the smallest possible bundle size, libraries often wish to rename internal object properties or class members to smaller names - transforming `this._internalIdValue` to `this._i`. Microbundle doesn't do this by default, however it can be enabled by creating a `mangle.json` file (or a `"mangle"` property in your package.json). Within that file, you can specify a regular expression pattern to control which properties should be mangled. For example: to mangle all property names beginning an underscore: @@ -316,6 +339,7 @@ Options --generateTypes Whether or not to generate types, if `types` or `typings` is set in `package.json` then it will default to be `true` --css Where to output CSS: "inline" or "external" (default: "external") --css-modules Configures .css to be treated as modules (default: null) + --worker-loader Generate inline worker blobs (default false) -h, --help Displays this message Examples diff --git a/package-lock.json b/package-lock.json index b554eb0e..588f83f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,12 @@ { "name": "microbundle", - "version": "0.13.1", + "version": "0.13.3", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "0.13.1", + "name": "microbundle", + "version": "0.13.3", "license": "MIT", "dependencies": { "@babel/core": "^7.12.10", @@ -43,6 +44,7 @@ "rollup-plugin-postcss": "^4.0.0", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-typescript2": "^0.29.0", + "rollup-plugin-web-worker-loader": "^1.6.1", "sade": "^1.7.4", "terser": "^5.7.0", "tiny-glob": "^0.2.8", @@ -15306,6 +15308,14 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz", "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==" }, + "node_modules/rollup-plugin-web-worker-loader": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-web-worker-loader/-/rollup-plugin-web-worker-loader-1.6.1.tgz", + "integrity": "sha512-4QywQSz1NXFHKdyiou16mH3ijpcfLtLGOrAqvAqu1Gx+P8+zj+3gwC2BSL/VW1d+LW4nIHC8F7d7OXhs9UdR2A==", + "peerDependencies": { + "rollup": "^1.9.2 || ^2.0.0" + } + }, "node_modules/rollup-pluginutils": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", @@ -29979,6 +29989,12 @@ } } }, + "rollup-plugin-web-worker-loader": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-web-worker-loader/-/rollup-plugin-web-worker-loader-1.6.1.tgz", + "integrity": "sha512-4QywQSz1NXFHKdyiou16mH3ijpcfLtLGOrAqvAqu1Gx+P8+zj+3gwC2BSL/VW1d+LW4nIHC8F7d7OXhs9UdR2A==", + "requires": {} + }, "rollup-pluginutils": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", diff --git a/package.json b/package.json index 95a55247..488ebcdc 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,7 @@ "rollup-plugin-postcss": "^4.0.0", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-typescript2": "^0.29.0", + "rollup-plugin-web-worker-loader": "^1.6.1", "sade": "^1.7.4", "terser": "^5.7.0", "tiny-glob": "^0.2.8", diff --git a/src/index.js b/src/index.js index 47448a08..d71053c5 100644 --- a/src/index.js +++ b/src/index.js @@ -17,6 +17,7 @@ import { terser } from 'rollup-plugin-terser'; import alias from '@rollup/plugin-alias'; import postcss from 'rollup-plugin-postcss'; import typescript from 'rollup-plugin-typescript2'; +import webWorkerLoader from 'rollup-plugin-web-worker-loader'; import json from '@rollup/plugin-json'; import logError from './log-error'; import { isDir, isFile, stdout, isTruthy, removeScope } from './utils'; @@ -385,6 +386,7 @@ function createConfig(options, entry, format, writeMeta) { : () => resolve(options.cwd, 'mangle.json'); const useTypescript = extname(entry) === '.ts' || extname(entry) === '.tsx'; + const useWorkerLoader = options['worker-loader'] !== false; const emitDeclaration = options.generateTypes == null ? !!(pkg.types || pkg.typings) @@ -418,7 +420,7 @@ function createConfig(options, entry, format, writeMeta) { /** @type {false | import('rollup').RollupCache} */ let cache; - if (modern) cache = false; + if (modern || useWorkerLoader) cache = false; const absMain = resolve(options.cwd, getMain({ options, entry, format })); const outputDir = dirname(absMain); @@ -427,7 +429,7 @@ function createConfig(options, entry, format, writeMeta) { let config = { /** @type {import('rollup').InputOptions} */ inputOptions: { - // disable Rollup's cache for the modern build to prevent re-use of legacy transpiled modules: + // disable Rollup's cache for modern and worker-loader builds to prevent re-use of legacy transpiled modules: cache, input: entry, external: id => { @@ -616,6 +618,13 @@ function createConfig(options, entry, format, writeMeta) { }, }, ], + useWorkerLoader && + webWorkerLoader({ + extensions: ['.js'].concat(useTypescript ? '.ts' : []), + external: [], + pattern: /worker-loader:(.+)/, + sourcemap: options.compress === false && options.sourcemap, + }), /** @type {import('rollup').Plugin} */ ({ name: 'postprocessing', diff --git a/src/prog.js b/src/prog.js index 10fd9b8d..9d5b939f 100644 --- a/src/prog.js +++ b/src/prog.js @@ -57,6 +57,7 @@ export default handler => { .option('--cwd', 'Use an alternative working directory', '.') .option('--sourcemap', 'Generate source map') .option('--css', 'Where to output CSS: "inline" or "external"', 'external') + .option('--worker-loader', 'Generate inline worker blobs', false) .option( '--css-modules', 'Turns on css-modules for all .css imports. Passing a string will override the scopeName. eg --css-modules="_[hash]"', diff --git a/test/__snapshots__/index.test.js.snap b/test/__snapshots__/index.test.js.snap index e70c9176..8512b89d 100644 --- a/test/__snapshots__/index.test.js.snap +++ b/test/__snapshots__/index.test.js.snap @@ -3016,3 +3016,73 @@ exports[`fixtures build ts-module with microbundle 7`] = ` //# sourceMappingURL=ts-module.umd.js.map " `; + +exports[`fixtures build worker-loader with microbundle 1`] = ` +"Used script: microbundle --worker-loader + +Directory tree: + +worker-loader + dist + bar.d.ts + index.d.ts + worker-loader.esm.js + worker-loader.esm.js.map + worker-loader.js + worker-loader.js.map + worker-loader.umd.js + worker-loader.umd.js.map + worker.d.ts + node_modules + package.json + src + bar.ts + index.ts + worker.ts + workers.d.ts + tsconfig.json + + +Build \\"workerLoader\\" to dist: +592 B: worker-loader.js.gz +528 B: worker-loader.js.br +592 B: worker-loader.esm.js.gz +528 B: worker-loader.esm.js.br +618 B: worker-loader.umd.js.gz +538 B: worker-loader.umd.js.br" +`; + +exports[`fixtures build worker-loader with microbundle 2`] = `9`; + +exports[`fixtures build worker-loader with microbundle 3`] = ` +"export declare function bar(): string; +" +`; + +exports[`fixtures build worker-loader with microbundle 4`] = ` +"export {}; +" +`; + +exports[`fixtures build worker-loader with microbundle 5`] = ` +"var e=null;try{var o=\\"undefined\\"!=typeof module&&\\"function\\"==typeof module.require&&module.require(\\"worker_threads\\")||\\"function\\"==typeof __non_webpack_require__&&__non_webpack_require__(\\"worker_threads\\")||\\"function\\"==typeof require&&require(\\"worker_threads\\");e=o.Worker}catch(e){}var r,n,t,c,i=new(\\"[object process]\\"===Object.prototype.toString.call(\\"undefined\\"!=typeof process?process:0)?(t=(n=Buffer.from(\\"Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwohZnVuY3Rpb24oKXsidXNlIHN0cmljdCI7c2VsZi5vbm1lc3NhZ2U9ZnVuY3Rpb24ocyl7cmV0dXJuIHNlbGYucG9zdE1lc3NhZ2Uocy5kYXRhKyJiYXIiKX19KCk7Cgo=\\",\\"base64\\").toString(\\"utf8\\")).indexOf(\\"\\\\n\\",10)+1,c=n.substring(t)+\\"\\",function(o){return new e(c,Object.assign({},o,{eval:!0}))}):function(e){return r=r||function(e,o,r){var n=atob(\\"Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwohZnVuY3Rpb24oKXsidXNlIHN0cmljdCI7c2VsZi5vbm1lc3NhZ2U9ZnVuY3Rpb24ocyl7cmV0dXJuIHNlbGYucG9zdE1lc3NhZ2Uocy5kYXRhKyJiYXIiKX19KCk7Cgo=\\"),t=n.indexOf(\\"\\\\n\\",10)+1,c=n.substring(t)+\\"\\",i=new Blob([c],{type:\\"application/javascript\\"});return URL.createObjectURL(i)}(),new Worker(r,e)});i.onmessage=function(e){return\\"foobar\\"===e.data},i.postMessage(\\"foo\\"); +//# sourceMappingURL=worker-loader.esm.js.map +" +`; + +exports[`fixtures build worker-loader with microbundle 6`] = ` +"var e=null;try{var o=\\"undefined\\"!=typeof module&&\\"function\\"==typeof module.require&&module.require(\\"worker_threads\\")||\\"function\\"==typeof __non_webpack_require__&&__non_webpack_require__(\\"worker_threads\\")||\\"function\\"==typeof require&&require(\\"worker_threads\\");e=o.Worker}catch(e){}var r,n,t,c,i=new(\\"[object process]\\"===Object.prototype.toString.call(\\"undefined\\"!=typeof process?process:0)?(t=(n=Buffer.from(\\"Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwohZnVuY3Rpb24oKXsidXNlIHN0cmljdCI7c2VsZi5vbm1lc3NhZ2U9ZnVuY3Rpb24ocyl7cmV0dXJuIHNlbGYucG9zdE1lc3NhZ2Uocy5kYXRhKyJiYXIiKX19KCk7Cgo=\\",\\"base64\\").toString(\\"utf8\\")).indexOf(\\"\\\\n\\",10)+1,c=n.substring(t)+\\"\\",function(o){return new e(c,Object.assign({},o,{eval:!0}))}):function(e){return r=r||function(e,o,r){var n=atob(\\"Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwohZnVuY3Rpb24oKXsidXNlIHN0cmljdCI7c2VsZi5vbm1lc3NhZ2U9ZnVuY3Rpb24ocyl7cmV0dXJuIHNlbGYucG9zdE1lc3NhZ2Uocy5kYXRhKyJiYXIiKX19KCk7Cgo=\\"),t=n.indexOf(\\"\\\\n\\",10)+1,c=n.substring(t)+\\"\\",i=new Blob([c],{type:\\"application/javascript\\"});return URL.createObjectURL(i)}(),new Worker(r,e)});i.onmessage=function(e){return\\"foobar\\"===e.data},i.postMessage(\\"foo\\"); +//# sourceMappingURL=worker-loader.js.map +" +`; + +exports[`fixtures build worker-loader with microbundle 7`] = ` +"!function(e){\\"function\\"==typeof define&&define.amd?define(e):e()}(function(){var e=null;try{var o=\\"undefined\\"!=typeof module&&\\"function\\"==typeof module.require&&module.require(\\"worker_threads\\")||\\"function\\"==typeof __non_webpack_require__&&__non_webpack_require__(\\"worker_threads\\")||\\"function\\"==typeof require&&require(\\"worker_threads\\");e=o.Worker}catch(e){}var n,r,t,c,i=new(\\"[object process]\\"===Object.prototype.toString.call(\\"undefined\\"!=typeof process?process:0)?(t=(r=Buffer.from(\\"Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwohZnVuY3Rpb24oKXsidXNlIHN0cmljdCI7c2VsZi5vbm1lc3NhZ2U9ZnVuY3Rpb24ocyl7cmV0dXJuIHNlbGYucG9zdE1lc3NhZ2Uocy5kYXRhKyJiYXIiKX19KCk7Cgo=\\",\\"base64\\").toString(\\"utf8\\")).indexOf(\\"\\\\n\\",10)+1,c=r.substring(t)+\\"\\",function(o){return new e(c,Object.assign({},o,{eval:!0}))}):function(e){return n=n||function(e,o,n){var r=atob(\\"Lyogcm9sbHVwLXBsdWdpbi13ZWItd29ya2VyLWxvYWRlciAqLwohZnVuY3Rpb24oKXsidXNlIHN0cmljdCI7c2VsZi5vbm1lc3NhZ2U9ZnVuY3Rpb24ocyl7cmV0dXJuIHNlbGYucG9zdE1lc3NhZ2Uocy5kYXRhKyJiYXIiKX19KCk7Cgo=\\"),t=r.indexOf(\\"\\\\n\\",10)+1,c=r.substring(t)+\\"\\",i=new Blob([c],{type:\\"application/javascript\\"});return URL.createObjectURL(i)}(),new Worker(n,e)});i.onmessage=function(e){return\\"foobar\\"===e.data},i.postMessage(\\"foo\\")}); +//# sourceMappingURL=worker-loader.umd.js.map +" +`; + +exports[`fixtures build worker-loader with microbundle 8`] = ` +"export {}; +" +`; diff --git a/test/fixtures/worker-loader/package.json b/test/fixtures/worker-loader/package.json new file mode 100644 index 00000000..f3c1f717 --- /dev/null +++ b/test/fixtures/worker-loader/package.json @@ -0,0 +1,6 @@ +{ + "name": "worker-loader", + "scripts": { + "build": "microbundle --worker-loader" + } +} diff --git a/test/fixtures/worker-loader/src/bar.ts b/test/fixtures/worker-loader/src/bar.ts new file mode 100644 index 00000000..808dbfe1 --- /dev/null +++ b/test/fixtures/worker-loader/src/bar.ts @@ -0,0 +1,3 @@ +export function bar() { + return 'bar'; +} diff --git a/test/fixtures/worker-loader/src/index.ts b/test/fixtures/worker-loader/src/index.ts new file mode 100644 index 00000000..4a8e08b7 --- /dev/null +++ b/test/fixtures/worker-loader/src/index.ts @@ -0,0 +1,6 @@ +import WebWorker from 'worker-loader:./worker'; + +const webWorker = new WebWorker(); + +webWorker.onmessage = message => message.data === 'foobar'; +webWorker.postMessage('foo'); diff --git a/test/fixtures/worker-loader/src/worker.ts b/test/fixtures/worker-loader/src/worker.ts new file mode 100644 index 00000000..dc890d1a --- /dev/null +++ b/test/fixtures/worker-loader/src/worker.ts @@ -0,0 +1,5 @@ +import { bar } from './bar'; + +declare const self: Worker; + +self.onmessage = message => self.postMessage(message.data + bar()); diff --git a/test/fixtures/worker-loader/src/workers.d.ts b/test/fixtures/worker-loader/src/workers.d.ts new file mode 100644 index 00000000..596a8e87 --- /dev/null +++ b/test/fixtures/worker-loader/src/workers.d.ts @@ -0,0 +1,4 @@ +declare module 'worker-loader:*' { + const WorkerFactory: new () => Worker; + export default WorkerFactory; +} diff --git a/test/fixtures/worker-loader/tsconfig.json b/test/fixtures/worker-loader/tsconfig.json new file mode 100644 index 00000000..bd269556 --- /dev/null +++ b/test/fixtures/worker-loader/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "baseUrl": "." + }, + "files": ["src/index.ts"], + "include": ["src/workers.d.ts"] +}