├── .babelrc ├── .circleci └── config.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .jestrc ├── CHANGELOG.md ├── LICENSE ├── LICENSE_ORIGINAL ├── README.md ├── package-lock.json ├── package.json ├── src ├── Error.js ├── cjs.js ├── index.js ├── options.json └── worklets │ ├── InlineWorklet.js │ └── index.js └── test ├── Errors.test.js ├── __snapshots__ └── Errors.test.js.snap ├── fixtures ├── inline-fallbacks │ ├── entry.js │ ├── w1.js │ └── w2.js ├── inline-options │ ├── entry.js │ ├── w1.js │ └── w2.js ├── inline-query │ ├── entry.js │ └── worker.js ├── name-options │ ├── entry.js │ ├── w1.js │ └── w2.js ├── name-query │ ├── entry.js │ └── worker.js ├── no-fallbacks │ ├── entry.js │ ├── w1.js │ └── w2.js ├── nodejs-core-modules │ ├── entry.js │ └── worker.js ├── public-path-override │ ├── entry.js │ └── worker.js └── worker │ ├── entry.js │ └── worker.js ├── helpers └── compiler.js └── loader.test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": "6.9.0" 8 | } 9 | } 10 | ], 11 | ], 12 | "env": { 13 | "test": { 14 | "presets": [ 15 | "@babel/preset-env", 16 | ], 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | unit_tests: &unit_tests 2 | steps: 3 | - checkout 4 | - setup_remote_docker 5 | - restore_cache: 6 | key: dependency-cache-{{ checksum "package-lock.json" }} 7 | - run: 8 | name: NPM Rebuild 9 | command: npm install 10 | - run: 11 | name: Run unit tests. 12 | command: npm run ci:test 13 | # canary_tests: &canary_tests 14 | # steps: 15 | # - checkout 16 | # - setup_remote_docker 17 | # - restore_cache: 18 | # key: dependency-cache-{{ checksum "package-lock.json" }} 19 | # - run: 20 | # name: NPM Rebuild 21 | # command: npm install 22 | # - run: 23 | # name: Install Webpack Canary 24 | # command: npm i --no-save webpack@next 25 | # - run: 26 | # name: Run unit tests. 27 | # command: npm run ci:test 28 | 29 | version: 2 30 | jobs: 31 | dependency_cache: 32 | docker: 33 | - image: webpackcontrib/circleci-node-base:latest 34 | steps: 35 | - checkout 36 | - setup_remote_docker 37 | - restore_cache: 38 | key: dependency-cache-{{ checksum "package-lock.json" }} 39 | - run: 40 | name: Install Dependencies 41 | command: npm install 42 | - save_cache: 43 | key: dependency-cache-{{ checksum "package-lock.json" }} 44 | paths: 45 | - ./node_modules 46 | 47 | node8-latest: 48 | docker: 49 | - image: webpackcontrib/circleci-node8:latest 50 | steps: 51 | - checkout 52 | - setup_remote_docker 53 | - restore_cache: 54 | key: dependency-cache-{{ checksum "package-lock.json" }} 55 | - run: 56 | name: NPM Rebuild 57 | command: npm install 58 | - run: 59 | name: Run unit tests. 60 | command: npm run ci:coverage 61 | - run: 62 | name: Submit coverage data to codecov. 63 | command: bash <(curl -s https://codecov.io/bash) 64 | when: on_success 65 | node6-latest: 66 | docker: 67 | - image: webpackcontrib/circleci-node6:latest 68 | <<: *unit_tests 69 | node9-latest: 70 | docker: 71 | - image: webpackcontrib/circleci-node9:latest 72 | <<: *unit_tests 73 | # node8-canary: 74 | # docker: 75 | # - image: webpackcontrib/circleci-node8:latest 76 | # <<: *canary_tests 77 | analysis: 78 | docker: 79 | - image: webpackcontrib/circleci-node-base:latest 80 | steps: 81 | - checkout 82 | - setup_remote_docker 83 | - restore_cache: 84 | key: dependency-cache-{{ checksum "package-lock.json" }} 85 | - run: 86 | name: NPM Rebuild 87 | command: npm install 88 | - run: 89 | name: Run linting. 90 | command: npm run lint 91 | - run: 92 | name: Run NSP Security Check. 93 | command: npm run security 94 | # - run: 95 | # name: Validate Commit Messages 96 | # command: npm run ci:lint:commits 97 | publish: 98 | docker: 99 | - image: webpackcontrib/circleci-node-base:latest 100 | steps: 101 | - checkout 102 | - setup_remote_docker 103 | - restore_cache: 104 | key: dependency-cache-{{ checksum "package-lock.json" }} 105 | - run: 106 | name: NPM Rebuild 107 | command: npm install 108 | - run: 109 | name: Validate Commit Messages 110 | command: npm run release:validate 111 | - run: 112 | name: Publish to NPM 113 | command: printf "noop running conventional-github-releaser" 114 | 115 | version: 2.0 116 | workflows: 117 | version: 2 118 | validate-publish: 119 | jobs: 120 | - dependency_cache 121 | - node6-latest: 122 | requires: 123 | - dependency_cache 124 | filters: 125 | tags: 126 | only: /.*/ 127 | - analysis: 128 | requires: 129 | - dependency_cache 130 | filters: 131 | tags: 132 | only: /.*/ 133 | - node8-latest: 134 | requires: 135 | - analysis 136 | - node6-latest 137 | filters: 138 | tags: 139 | only: /.*/ 140 | - node9-latest: 141 | requires: 142 | - analysis 143 | - node6-latest 144 | filters: 145 | tags: 146 | only: /.*/ 147 | # - node8-canary: 148 | # requires: 149 | # - analysis 150 | # - node6-latest 151 | filters: 152 | tags: 153 | only: /.*/ 154 | - publish: 155 | requires: 156 | - node8-latest 157 | - node9-latest 158 | filters: 159 | branches: 160 | only: 161 | - master 162 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [.md] 12 | insert_final_newline = false 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | test/fixtures 2 | test/__expected__ 3 | 4 | src/worklets/InlineWorklet.js 5 | 6 | /node_modules 7 | /dist 8 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "webpack" 3 | } 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | package-lock.json -diff 2 | * text=auto 3 | bin/* eol=lf -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | *.log 3 | npm-debug.log* 4 | .eslintcache 5 | /coverage 6 | /dist 7 | /local 8 | /reports 9 | /node_modules 10 | /test/__expected__ 11 | .DS_Store 12 | Thumbs.db 13 | .idea 14 | .vscode 15 | *.sublime-project 16 | *.sublime-workspace 17 | -------------------------------------------------------------------------------- /.jestrc: -------------------------------------------------------------------------------- 1 | { 2 | "testEnvironment": "node" 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | 6 | ## [1.1.1](https://github.com/webpack-contrib/worker-loader/compare/v1.1.0...v1.1.1) (2018-02-25) 7 | 8 | 9 | ### Bug Fixes 10 | 11 | * **index:** add `webpack >= v4.0.0` support ([#128](https://github.com/webpack-contrib/worker-loader/issues/128)) ([d1a7a94](https://github.com/webpack-contrib/worker-loader/commit/d1a7a94)) 12 | 13 | 14 | 15 | 16 | # [1.1.0](https://github.com/webpack-contrib/worker-loader/compare/v1.0.0...v1.1.0) (2017-10-24) 17 | 18 | 19 | ### Features 20 | 21 | * add `publicPath` support (`options.publicPath`) ([#31](https://github.com/webpack-contrib/worker-loader/issues/31)) ([96c6144](https://github.com/webpack-contrib/worker-loader/commit/96c6144)) 22 | 23 | 24 | 25 | 26 | ## [1.0.0](https://github.com/webpack-contrib/worker-loader/compare/v0.8.0...v1.0.0) (2017-09-25) 27 | 28 | 29 | ### Features 30 | 31 | * add `options` validation (`schema-utils`) ([#78](https://github.com/webpack-contrib/worker-loader/issues/78)) ([5e2f5e6](https://github.com/webpack-contrib/worker-loader/commit/5e2f5e6)) 32 | * support loading node core modules ([#76](https://github.com/webpack-contrib/worker-loader/issues/76)) ([edcda35](https://github.com/webpack-contrib/worker-loader/commit/edcda35)) 33 | 34 | 35 | ### BREAKING CHANGES 36 | 37 | * loader-utils upgrade to > 1.0 is not backwards 38 | compatible with previous versions 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Additions and modifications to `worker-loader` copyright (c) 2018 Walker Henderson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | 'Software'), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /LICENSE_ORIGINAL: -------------------------------------------------------------------------------- 1 | Copyright JS Foundation and other contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | 'Software'), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Worklet Loader 2 | This loader loads imported scripts as a URL pointing to (or containing) a compiled module. That URL can be used to add worklet modules. 3 | 4 | **NOTE! At the moment, this is basically just a fork of [`worker-loader`](https://github.com/webpack-contrib/worker-loader) and *probably shouldn't be used*. It's possible that, at some point, `worker-loader` will support worklets and this loader will be obsolete. It's also possible that there are worker-specific things that this package does that breaks worklets for one reason or another. So be careful!** 5 | 6 | ## Install 7 | 8 | ```bash 9 | npm i -D worklet-loader 10 | ``` 11 | 12 | ## [Usage](https://webpack.js.org/concepts/loaders) 13 | 14 | ### `Inlined` 15 | 16 | **App.js** 17 | ```js 18 | import workletUrl from 'worklet-loader!./Worklet.js'; 19 | ``` 20 | 21 | ### `Config` 22 | 23 | **webpack.config.js** 24 | ```js 25 | { 26 | module: { 27 | rules: [ 28 | { 29 | test: /\.worklet\.js$/, 30 | use: { loader: 'worklet-loader' } 31 | } 32 | ] 33 | } 34 | } 35 | ``` 36 | 37 | **App.js** 38 | ```js 39 | import workletUrl from './file.worklet.js'; 40 | 41 | const audioCtx = new AudioContext(); 42 | 43 | audioCtx.audioWorklet.addModule(workletUrl).then(() => { 44 | // Do stuff with the now-registered processor 45 | }); 46 | ``` 47 | 48 | ## Options 49 | 50 | |Name|Type|Default|Description| 51 | |:--:|:--:|:-----:|:----------| 52 | |[**`name`**](#name)|`{String}`|`[hash].worklet.js`|Set a custom name for the output script| 53 | |[**`inline`**](#inline)|`{Boolean}`|`false`|Inline the worklet as a Blob| 54 | |[**`publicPath`**](#publicPath)|`{String}`|`null`|Override the path from which worklet scripts are downloaded| 55 | 56 | ### `name` 57 | 58 | To set a custom name for the output script, use the `name` parameter. The name may contain the string `[hash]`, which will be replaced with a content dependent hash for caching purposes. When using `name` alone `[hash]` is omitted. 59 | 60 | *webpack.config.js** 61 | ```js 62 | { 63 | loader: 'worklet-loader', 64 | options: { name: 'WorkerName.[hash].js' } 65 | } 66 | ``` 67 | 68 | ### `inline` 69 | 70 | Inline the worklet as a `Blob` with the `inline` parameter 71 | 72 | **webpack.config.js** 73 | ```js 74 | { 75 | loader: 'worklet-loader', 76 | options: { inline: true } 77 | } 78 | ``` 79 | 80 | ### `publicPath` 81 | 82 | Overrides the path from which worklet scripts are downloaded. If not specified, the same public path used for other 83 | webpack assets is used 84 | 85 | **webpack.config.js** 86 | ```js 87 | { 88 | loader: 'worklet-loader' 89 | options: { publicPath: '/scripts/worklets/' } 90 | } 91 | ``` 92 | 93 | ## Examples 94 | 95 | ### Integrating with TypeScript 96 | 97 | You will need to define a custom module for the exports of your worklet files 98 | 99 | **typings/custom.d.ts** 100 | ```typescript 101 | declare module "*.worklet.ts" { 102 | const exportString: string; 103 | export default exportString; 104 | } 105 | ``` 106 | 107 | **App.ts** 108 | ```typescript 109 | import fooBarWorkletUrl from 'worlet-loader!./fooBar.worklet.ts' 110 | 111 | const audioCtx = new AudioContext(); 112 | 113 | // @ts-ignore: AudioContext.audioWorklet is not available as a type yet 114 | audioCtx.audioWorklet.addModule(fooBarWorkletUrl).then(() => { 115 | // Do stuff with the now-registered processor 116 | }); 117 | ``` 118 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "worklet-loader", 3 | "version": "2.0.0", 4 | "author": "Walker Henderson", 5 | "description": "worklet loader module for webpack", 6 | "repository": "https://github.com/reklawnos/worklet-loader.git", 7 | "bugs": "https://github.com/reklawnos/worklet-loader/issues", 8 | "homepage": "https://github.com/reklawnos/worklet-loader", 9 | "license": "MIT", 10 | "main": "dist/cjs.js", 11 | "files": [ 12 | "dist" 13 | ], 14 | "scripts": { 15 | "start": "npm run build -- -w", 16 | "build": "cross-env NODE_ENV=production babel src -d dist --ignore 'src/**/*.test.js' --copy-files", 17 | "clean": "del-cli dist", 18 | "lint": "eslint --cache src test", 19 | "lint-staged": "lint-staged", 20 | "prebuild": "npm run clean", 21 | "prepare": "npm run build", 22 | "release": "standard-version", 23 | "security": "nsp check", 24 | "test": "jest", 25 | "test:watch": "jest --watch", 26 | "test:coverage": "jest --collectCoverageFrom='src/**/*.js' --coverage", 27 | "ci:lint": "npm run lint && npm run security", 28 | "ci:test": "npm run test -- --runInBand", 29 | "ci:coverage": "npm run test:coverage -- --runInBand", 30 | "defaults": "webpack-defaults", 31 | "webpack-defaults": "webpack-defaults" 32 | }, 33 | "dependencies": { 34 | "hoek": "^4.2.1", 35 | "loader-utils": "^1.0.0", 36 | "schema-utils": "^0.4.0" 37 | }, 38 | "devDependencies": { 39 | "@babel/cli": "^7.14.5", 40 | "@babel/core": "^7.14.6", 41 | "@babel/preset-env": "^7.14.7", 42 | "babel-jest": "^27.0.6", 43 | "cross-env": "^5.0.0", 44 | "del": "^3.0.0", 45 | "del-cli": "^1.0.0", 46 | "eslint": "^4.0.0", 47 | "eslint-config-webpack": "^1.0.0", 48 | "eslint-plugin-import": "^2.2.0", 49 | "jest": "^27.0.6", 50 | "lint-staged": "^4.0.0", 51 | "nsp": "^2.6.0", 52 | "pre-commit": "^1.0.0", 53 | "standard-version": "^4.0.0", 54 | "webpack": "^3.0.0", 55 | "webpack-defaults": "^1.6.0" 56 | }, 57 | "peerDependencies": { 58 | "webpack": "^3.0.0 || ^4.0.0-alpha.0 || ^4.0.0" 59 | }, 60 | "engines": { 61 | "node": ">= 6.9.0 || >= 8.9.0" 62 | }, 63 | "pre-commit": "lint-staged", 64 | "lint-staged": { 65 | "*.js": [ 66 | "eslint --fix", 67 | "git add" 68 | ] 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Error.js: -------------------------------------------------------------------------------- 1 | class LoaderError extends Error { 2 | constructor(err) { 3 | super(err); 4 | 5 | this.name = err.name || 'Loader Error'; 6 | this.message = `${err.name}\n\n${err.message}\n`; 7 | this.stack = false; 8 | } 9 | } 10 | 11 | export default LoaderError; 12 | -------------------------------------------------------------------------------- /src/cjs.js: -------------------------------------------------------------------------------- 1 | const loader = require('./index'); 2 | 3 | module.exports = loader.default; 4 | module.exports.pitch = loader.pitch; 5 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable 2 | import/first, 3 | import/order, 4 | comma-dangle, 5 | linebreak-style, 6 | no-param-reassign, 7 | no-underscore-dangle, 8 | prefer-destructuring 9 | */ 10 | import schema from './options.json'; 11 | import loaderUtils from 'loader-utils'; 12 | import validateOptions from 'schema-utils'; 13 | 14 | import NodeTargetPlugin from 'webpack/lib/node/NodeTargetPlugin'; 15 | import SingleEntryPlugin from 'webpack/lib/SingleEntryPlugin'; 16 | 17 | import getWorker from './worklets/'; 18 | import LoaderError from './Error'; 19 | 20 | export default function loader() {} 21 | 22 | export function pitch(request) { 23 | const options = loaderUtils.getOptions(this) || {}; 24 | 25 | validateOptions(schema, options, 'Worklet Loader'); 26 | 27 | if (!this.webpack) { 28 | throw new LoaderError({ 29 | name: 'Worklet Loader', 30 | message: 'This loader is only usable with webpack' 31 | }); 32 | } 33 | 34 | this.cacheable(false); 35 | 36 | const cb = this.async(); 37 | 38 | const filename = loaderUtils.interpolateName(this, options.name || '[hash].worklet.js', { 39 | context: options.context || this.rootContext || this.options.context, 40 | regExp: options.regExp, 41 | }); 42 | 43 | const worker = {}; 44 | 45 | worker.options = { 46 | filename, 47 | chunkFilename: `[id].${filename}`, 48 | namedChunkFilename: null, 49 | }; 50 | 51 | worker.compiler = this._compilation 52 | .createChildCompiler('worker', worker.options); 53 | 54 | // Tapable.apply is deprecated in tapable@1.0.0-x. 55 | // The plugins should now call apply themselves. 56 | // new WebWorkerTemplatePlugin(worker.options).apply(worker.compiler); 57 | 58 | if (this.target !== 'webworker' && this.target !== 'web') { 59 | new NodeTargetPlugin().apply(worker.compiler); 60 | } 61 | 62 | new SingleEntryPlugin(this.context, `!!${request}`, 'main').apply(worker.compiler); 63 | 64 | const subCache = `subcache ${__dirname} ${request}`; 65 | 66 | worker.compilation = (compilation) => { 67 | if (compilation.cache) { 68 | if (!compilation.cache[subCache]) { 69 | compilation.cache[subCache] = {}; 70 | } 71 | 72 | compilation.cache = compilation.cache[subCache]; 73 | } 74 | }; 75 | 76 | if (worker.compiler.hooks) { 77 | const plugin = { name: 'WorkletLoader' }; 78 | 79 | worker.compiler.hooks.compilation.tap(plugin, worker.compilation); 80 | } else { 81 | worker.compiler.plugin('compilation', worker.compilation); 82 | } 83 | 84 | worker.compiler.runAsChild((err, entries, compilation) => { 85 | if (err) return cb(err); 86 | 87 | if (entries[0]) { 88 | worker.file = entries[0].files[0]; 89 | 90 | worker.factory = getWorker( 91 | worker.file, 92 | compilation.assets[worker.file].source(), 93 | options 94 | ); 95 | 96 | if (options.inline) { 97 | delete this._compilation.assets[worker.file]; 98 | } 99 | 100 | return cb(null, `module.exports = ${worker.factory};`); 101 | } 102 | 103 | return cb(null, null); 104 | }); 105 | } 106 | -------------------------------------------------------------------------------- /src/options.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "object", 3 | "properties": { 4 | "name": { 5 | "type": "string" 6 | }, 7 | "inline": { 8 | "type": "boolean" 9 | }, 10 | "publicPath": { 11 | "type": "string" 12 | } 13 | }, 14 | "additionalProperties": false 15 | } 16 | -------------------------------------------------------------------------------- /src/worklets/InlineWorklet.js: -------------------------------------------------------------------------------- 1 | // http://stackoverflow.com/questions/10343913/how-to-create-a-web-worker-from-a-string 2 | 3 | var URL = window.URL || window.webkitURL; 4 | 5 | module.exports = function (content) { 6 | try { 7 | var blob; 8 | 9 | try { 10 | // BlobBuilder = Deprecated, but widely implemented 11 | var BlobBuilder = window.BlobBuilder || 12 | window.WebKitBlobBuilder || 13 | window.MozBlobBuilder || 14 | window.MSBlobBuilder; 15 | 16 | blob = new BlobBuilder(); 17 | 18 | blob.append(content); 19 | 20 | blob = blob.getBlob('application/javascript; charset=utf-8'); 21 | } catch (e) { 22 | // The proposed API 23 | blob = new Blob([content], { type: 'application/javascript; charset=utf-8' }); 24 | } 25 | 26 | return URL.createObjectURL(blob); 27 | } catch (e) { 28 | return 'data:application/javascript,' + encodeURIComponent(content); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/worklets/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable multiline-ternary */ 2 | import path from 'path'; 3 | 4 | const getWorklet = (file, content, options) => { 5 | const publicPath = options.publicPath 6 | ? JSON.stringify(options.publicPath) 7 | : '__webpack_public_path__'; 8 | 9 | const publicWorkletPath = `${publicPath} + ${JSON.stringify(file)}`; 10 | 11 | if (options.inline) { 12 | const InlineWorkletPath = JSON.stringify(`!!${ 13 | path.join(__dirname, 'InlineWorklet.js') 14 | }`); 15 | 16 | return `require(${InlineWorkletPath})(${JSON.stringify(content)})`; 17 | } 18 | 19 | return publicWorkletPath; 20 | }; 21 | 22 | export default getWorklet; 23 | -------------------------------------------------------------------------------- /test/Errors.test.js: -------------------------------------------------------------------------------- 1 | import { pitch } from '../src'; 2 | 3 | describe('Errors', () => { 4 | test('Loader Error', () => { 5 | const error = () => pitch.call({ webpack: false, query: {} }); 6 | 7 | expect(error).toThrow(); 8 | expect(error).toThrowErrorMatchingSnapshot(); 9 | }); 10 | 11 | test('Validation Error', () => { 12 | const error = () => pitch.call({ query: { name: 1 } }); 13 | 14 | expect(error).toThrow(); 15 | expect(error).toThrowErrorMatchingSnapshot(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/__snapshots__/Errors.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Errors Loader Error 1`] = ` 4 | "Worklet Loader 5 | 6 | This loader is only usable with webpack 7 | " 8 | `; 9 | 10 | exports[`Errors Validation Error 1`] = ` 11 | "Worklet Loader Invalid Options 12 | 13 | options.name should be string 14 | " 15 | `; 16 | -------------------------------------------------------------------------------- /test/fixtures/inline-fallbacks/entry.js: -------------------------------------------------------------------------------- 1 | const w1 = require('./w1.js'); 2 | const w2 = require('./w2.js'); -------------------------------------------------------------------------------- /test/fixtures/inline-fallbacks/w1.js: -------------------------------------------------------------------------------- 1 | // w1 inlined with fallback -------------------------------------------------------------------------------- /test/fixtures/inline-fallbacks/w2.js: -------------------------------------------------------------------------------- 1 | // w2 inlined with fallback -------------------------------------------------------------------------------- /test/fixtures/inline-options/entry.js: -------------------------------------------------------------------------------- 1 | const w1 = require('./w1.js'); 2 | const w2 = require('./w2.js'); -------------------------------------------------------------------------------- /test/fixtures/inline-options/w1.js: -------------------------------------------------------------------------------- 1 | // w1 inlined via options -------------------------------------------------------------------------------- /test/fixtures/inline-options/w2.js: -------------------------------------------------------------------------------- 1 | // w2 inlined via options -------------------------------------------------------------------------------- /test/fixtures/inline-query/entry.js: -------------------------------------------------------------------------------- 1 | const Worker = require('!../../../src?inline!./worker.js'); 2 | -------------------------------------------------------------------------------- /test/fixtures/inline-query/worker.js: -------------------------------------------------------------------------------- 1 | // inlined worker test mark 2 | -------------------------------------------------------------------------------- /test/fixtures/name-options/entry.js: -------------------------------------------------------------------------------- 1 | const w1 = require('./w1.js'); 2 | const w2 = require('./w2.js'); 3 | -------------------------------------------------------------------------------- /test/fixtures/name-options/w1.js: -------------------------------------------------------------------------------- 1 | // w1 via worker options -------------------------------------------------------------------------------- /test/fixtures/name-options/w2.js: -------------------------------------------------------------------------------- 1 | // w2 via worker options -------------------------------------------------------------------------------- /test/fixtures/name-query/entry.js: -------------------------------------------------------------------------------- 1 | const Worker = require('!../../../src?name=namedWorker.js!./worker.js'); 2 | -------------------------------------------------------------------------------- /test/fixtures/name-query/worker.js: -------------------------------------------------------------------------------- 1 | // named worker test mark 2 | -------------------------------------------------------------------------------- /test/fixtures/no-fallbacks/entry.js: -------------------------------------------------------------------------------- 1 | const w1 = require('./w1.js'); 2 | const w2 = require('./w2.js'); -------------------------------------------------------------------------------- /test/fixtures/no-fallbacks/w1.js: -------------------------------------------------------------------------------- 1 | // w1 inlined without fallback -------------------------------------------------------------------------------- /test/fixtures/no-fallbacks/w2.js: -------------------------------------------------------------------------------- 1 | // w2 inlined without fallback -------------------------------------------------------------------------------- /test/fixtures/nodejs-core-modules/entry.js: -------------------------------------------------------------------------------- 1 | const Worker = require('./worker.js'); 2 | -------------------------------------------------------------------------------- /test/fixtures/nodejs-core-modules/worker.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | -------------------------------------------------------------------------------- /test/fixtures/public-path-override/entry.js: -------------------------------------------------------------------------------- 1 | const Worker = require('./worker.js'); 2 | -------------------------------------------------------------------------------- /test/fixtures/public-path-override/worker.js: -------------------------------------------------------------------------------- 1 | // named worker test mark 2 | -------------------------------------------------------------------------------- /test/fixtures/worker/entry.js: -------------------------------------------------------------------------------- 1 | const Worker = require('./worker.js'); 2 | -------------------------------------------------------------------------------- /test/fixtures/worker/worker.js: -------------------------------------------------------------------------------- 1 | // worker test mark 2 | -------------------------------------------------------------------------------- /test/helpers/compiler.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable 2 | import/order, 3 | comma-dangle, 4 | arrow-parens, 5 | multiline-ternary, 6 | no-param-reassign 7 | */ 8 | import del from 'del'; 9 | import path from 'path'; 10 | import webpack from 'webpack'; 11 | 12 | export default function (name, config = {}) { 13 | return del(path.resolve(__dirname, `../__expected__/${name}`)).then(() => { 14 | config = { 15 | target: config.target || 'web', 16 | context: path.resolve(__dirname, '../fixtures'), 17 | entry: `./${name}/entry.js`, 18 | output: { 19 | path: path.resolve(__dirname, `../__expected__/${name}`), 20 | filename: 'bundle.js', 21 | }, 22 | module: { 23 | rules: [ 24 | { 25 | test: config.loader ? config.loader.test : /worker\.js$/, 26 | use: { 27 | loader: '../../src', 28 | options: config.loader ? config.loader.options : {} 29 | } 30 | } 31 | ] 32 | } 33 | }; 34 | 35 | const compiler = webpack(config); 36 | 37 | return new Promise((resolve, reject) => { 38 | compiler.run((err, stats) => { 39 | if (err) reject(err); 40 | 41 | resolve(stats); 42 | }); 43 | }); 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /test/loader.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable 2 | import/order, 3 | comma-dangle, 4 | arrow-parens, 5 | linebreak-style, 6 | prefer-destructuring, 7 | no-underscore-dangle, 8 | array-bracket-spacing, 9 | */ 10 | import fs from 'fs'; 11 | import assert from 'assert'; 12 | import webpack from './helpers/compiler'; 13 | 14 | process.chdir(__dirname); 15 | 16 | const readFile = file => fs.readFileSync(file, 'utf-8'); 17 | 18 | test('should create chunk with worker', () => 19 | webpack('worker').then((stats) => { 20 | const files = stats.toJson().children 21 | .map(item => item.chunks) 22 | .reduce((acc, item) => acc.concat(item), []) 23 | .map(item => item.files) 24 | .map(item => `__expected__/worker/${item}`); 25 | 26 | assert.equal(files.length, 1); 27 | 28 | assert.notEqual(readFile(files[0]).indexOf('// worker test mark'), -1); 29 | }) 30 | ); 31 | 32 | test('should create chunk with specified name in query', () => 33 | webpack('name-query').then((stats) => { 34 | const files = stats.toJson().children 35 | .map(item => item.chunks) 36 | .reduce((acc, item) => acc.concat(item), []) 37 | .map(item => item.files) 38 | .map(item => `__expected__/name-query/${item}`); 39 | 40 | assert.equal(files[0], '__expected__/name-query/namedWorker.js'); 41 | 42 | assert.notEqual(readFile(files[0]).indexOf('// named worker test mark'), -1); 43 | }) 44 | ); 45 | 46 | test('should create named chunks with workers via options', () => 47 | webpack('name-options', { 48 | loader: { 49 | test: /(w1|w2)\.js$/, 50 | options: { 51 | name: '[name].js', 52 | }, 53 | } 54 | }).then((stats) => { 55 | const files = stats.toJson().children 56 | .map(item => item.chunks) 57 | .reduce((acc, item) => acc.concat(item), []) 58 | .map(item => item.files) 59 | .map(item => `__expected__/name-options/${item}`) 60 | .sort(); 61 | 62 | assert.equal(files.length, 2); 63 | assert.equal(files[0], '__expected__/name-options/w1.js'); 64 | assert.equal(files[1], '__expected__/name-options/w2.js'); 65 | 66 | assert.notEqual(readFile(files[0]).indexOf('// w1 via worker options'), -1); 67 | assert.notEqual(readFile(files[1]).indexOf('// w2 via worker options'), -1); 68 | }) 69 | ); 70 | 71 | test('should inline worker with inline option in query', () => 72 | webpack('inline-query').then((stats) => { 73 | const files = stats.toJson().chunks 74 | .map(item => item.files) 75 | .reduce((acc, item) => acc.concat(item), []) 76 | .map(item => `__expected__/inline-query/${item}`); 77 | 78 | assert.equal(files.length, 1); 79 | 80 | assert.notEqual(readFile(files[0]).indexOf('// inlined worker test mark'), -1); 81 | }) 82 | ); 83 | 84 | test('should inline worker with inline in options', () => 85 | webpack('inline-options', { 86 | loader: { 87 | test: /(w1|w2)\.js$/, 88 | options: { 89 | inline: true, 90 | }, 91 | } 92 | }).then((stats) => { 93 | const files = stats.toJson().chunks 94 | .map(item => item.files) 95 | .reduce((acc, item) => acc.concat(item), []) 96 | .map(item => `__expected__/inline-options/${item}`); 97 | 98 | assert.equal(files.length, 1); 99 | 100 | assert.notEqual(readFile(files[0]).indexOf('// w1 inlined via options'), -1); 101 | assert.notEqual(readFile(files[0]).indexOf('// w2 inlined via options'), -1); 102 | }) 103 | ); 104 | 105 | test('should not add fallback chunks with inline', () => 106 | webpack('no-fallbacks', { 107 | loader: { 108 | test: /(w1|w2)\.js$/, 109 | options: { 110 | inline: true, 111 | } 112 | } 113 | }).then((stats) => { 114 | const [ file ] = stats.toJson().chunks 115 | .map(item => item.files) 116 | .reduce((acc, item) => acc.concat(item), []) 117 | .map(item => `__expected__/no-fallbacks/${item}`); 118 | 119 | assert(file); 120 | 121 | assert.equal(fs.readdirSync('__expected__/no-fallbacks').length, 1); 122 | 123 | assert.notEqual(readFile(file).indexOf('// w1 inlined without fallback'), -1); 124 | assert.notEqual(readFile(file).indexOf('// w2 inlined without fallback'), -1); 125 | }) 126 | ); 127 | 128 | test('should use the publicPath option as the base URL if specified', () => 129 | webpack('public-path-override', { 130 | loader: { 131 | options: { 132 | publicPath: '/some/proxy/', 133 | } 134 | } 135 | }).then((stats) => { 136 | const assets = stats.compilation.assets; 137 | 138 | const bundle = assets['bundle.js']; 139 | const worker = Object.keys(assets)[1]; 140 | 141 | expect(bundle.source()).toContain(`"/some/proxy/" + "${worker}"`); 142 | }) 143 | ); 144 | --------------------------------------------------------------------------------