-
-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #827 from preactjs/worker
- Loading branch information
Showing
29 changed files
with
462 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'wmr': minor | ||
--- | ||
|
||
Add built-in support for [Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) based on browser APIs. Example on how to use Web Workers with WMR: https://wmr.dev/docs/web-workers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,5 +8,6 @@ collections: | |
- configuration | ||
- plugins | ||
- prerendering | ||
- web-workers | ||
- { heading: 'API' } | ||
- plugin-api |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
--- | ||
nav: Web Workers | ||
title: 'Web Workers' | ||
--- | ||
|
||
[Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) are a way to do threading in JavaScript. It is a simple mean to run work in the background to keep the main thread responsive for UI work. | ||
|
||
To use web workers with WMR you can use the [Web Workers API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers#web_workers_api) directly. | ||
|
||
```js | ||
// index.js | ||
const worker = new Worker(new URL('./my.worker.js', import.meta.url)); | ||
|
||
// Subscribe to messages coming from the worker | ||
worker.addEventListener('message', e => console.log(e.data)); | ||
|
||
// Ping worker | ||
worker.postMessage("Let's go"); | ||
``` | ||
WMR relies on the filename to detect workers. That's why it must have the `.worker` suffix in the filename. | ||
```js | ||
// my.worker.js | ||
addEventListener('message', () => { | ||
// Always answer with "hello" | ||
postMessage('hello'); | ||
}); | ||
``` | ||
> We highly recommend using [comlink](https://github.com/GoogleChromeLabs/comlink) for working with web workers. It abstracts away the manual message passing that's required to communicate workers. | ||
## ESM Support in Web Workers | ||
Support for module mode so that you can use `import` and `export` statements can be turned on by passing `{ format: 'module' }` to the `Worker` constructor. | ||
```js | ||
const workerUrl = new URL('./my.worker.js', import.meta.url); | ||
const worker = new Worker(workerUrl, { type: 'module' }); | ||
``` | ||
> Be cautious: ESM is not yet supported in every mainstream browser. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
import MagicString from 'magic-string'; | ||
import * as rollup from 'rollup'; | ||
import path from 'path'; | ||
import { getPlugins } from '../lib/plugins.js'; | ||
import * as kl from 'kolorist'; | ||
|
||
/** | ||
* @param {import("wmr").Options} options | ||
* @returns {import('rollup').Plugin} | ||
*/ | ||
export function workerPlugin(options) { | ||
const plugins = getPlugins({ ...options, runtimeEnv: 'worker' }); | ||
|
||
/** @type {Map<string, number>} */ | ||
const moduleWorkers = new Map(); | ||
let didWarnESM = false; | ||
|
||
return { | ||
name: 'worker', | ||
async transform(code, id) { | ||
// Transpile worker file if we're dealing with a worker | ||
if (/\.worker\.(?:[tj]sx?|mjs)$/.test(id)) { | ||
const resolved = await this.resolve(id); | ||
const resolvedId = resolved ? resolved.id : id; | ||
|
||
if (moduleWorkers.has(resolvedId)) { | ||
if (!didWarnESM) { | ||
const relativeId = path.relative(options.root, resolvedId); | ||
this.warn( | ||
kl.yellow( | ||
`Warning: Module workers are not widely supported yet. Use at your own risk. This warning occurs, because file ` | ||
) + | ||
kl.cyan(relativeId) + | ||
kl.yellow(` was loaded as a Web Worker with type "module"`) | ||
); | ||
didWarnESM = true; | ||
} | ||
|
||
// ..but not in module mode | ||
return; | ||
} | ||
|
||
// TODO: Add support for HMR inside a worker. | ||
|
||
// Firefox doesn't support modules inside web workers. They're | ||
// the only main browser left to implement that feature. Until | ||
// that's resolved we need to pre-bundle the worker code as a | ||
// single script with no dependencies. Once they support that | ||
// we can drop the bundling part and have nested workers work | ||
// out of the box. | ||
// See: https://bugzilla.mozilla.org/show_bug.cgi?id=1247687 | ||
const bundle = await rollup.rollup({ | ||
input: id, | ||
plugins: [ | ||
{ | ||
name: 'worker-meta', | ||
resolveImportMeta(property) { | ||
// `import.meta.url` is only available in ESM environments | ||
if (property === 'url') { | ||
return 'location.href'; | ||
} | ||
} | ||
}, | ||
...plugins | ||
], | ||
// Inline all dependencies | ||
external: () => false | ||
}); | ||
|
||
const res = await bundle.generate({ | ||
format: 'iife', | ||
|
||
sourcemap: options.sourcemap, | ||
inlineDynamicImports: true | ||
}); | ||
|
||
await bundle.close(); | ||
|
||
return { | ||
code: res.output[0].code, | ||
map: res.output[0].map || null | ||
}; | ||
} | ||
// Check if a worker is referenced anywhere in the file | ||
else if (/\.(?:[tj]sx?|mjs|cjs)$/.test(id)) { | ||
const WORKER_REG = /new URL\(\s*['"]([\w.-/:~]+)['"],\s*import\.meta\.url\s*\)(,\s*{.*?["']module["'].*?})?/gm; | ||
|
||
if (WORKER_REG.test(code)) { | ||
const s = new MagicString(code, { | ||
filename: id, | ||
// @ts-ignore | ||
indentExclusionRanges: undefined | ||
}); | ||
|
||
let match; | ||
WORKER_REG.lastIndex = 0; | ||
while ((match = WORKER_REG.exec(code))) { | ||
const spec = match[1]; | ||
|
||
// Worker URLs must be relative to properly work with chunks | ||
if (/^https?:/.test(spec) || !/^\.\.?\//.test(spec)) { | ||
throw new Error(`Worker import specifier must be relative. Got "${spec}" instead.`); | ||
} | ||
|
||
const ref = this.emitFile({ | ||
type: 'chunk', | ||
id: spec | ||
}); | ||
|
||
const resolved = await this.resolve(spec, id); | ||
const resolvedId = resolved ? resolved.id : spec; | ||
|
||
let usageCount = moduleWorkers.get(resolvedId) || 0; | ||
if (match[2]) { | ||
moduleWorkers.set(resolvedId, usageCount + 1); | ||
} else if (usageCount === 0) { | ||
moduleWorkers.delete(resolvedId); | ||
} | ||
|
||
const start = match.index + match[0].indexOf(spec); | ||
// Account for quoting characters and force URL to be | ||
// relative. | ||
s.overwrite(start - 1, start + spec.length + 1, `'.' + import.meta.ROLLUP_FILE_URL_${ref}`); | ||
} | ||
|
||
return { | ||
code: s.toString(), | ||
map: options.sourcemap | ||
? s.generateMap({ source: id, file: path.posix.basename(id), includeContent: true }) | ||
: null | ||
}; | ||
} | ||
} | ||
} | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { value } from './dep-b'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export const value = 'it works'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { value } from './dep-a'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { value } from './dep-b'; | ||
|
||
addEventListener('message', () => { | ||
postMessage(value); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<h1>it doesn't work</h1> | ||
<h2>it doesn't work</h2> | ||
<script src="./index.js" type="module"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { value as value2 } from './entry-1'; | ||
|
||
document.querySelector('h2').textContent = value2; | ||
|
||
const worker = new Worker(new URL('./foo.worker.js', import.meta.url), { type: 'module' }); | ||
|
||
worker.addEventListener('message', e => { | ||
document.querySelector('h1').textContent = e.data; | ||
}); | ||
|
||
worker.postMessage('hello'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
addEventListener('message', () => { | ||
postMessage('it works'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
addEventListener('message', () => { | ||
postMessage('it works'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<h1>it doesn't work</h1> | ||
<h2>it doesn't work</h2> | ||
<script src="./index.js" type="module"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
const foo = new Worker(new URL('./foo.worker.js', import.meta.url)); | ||
const bar = new Worker(new URL('./foo.worker.js', import.meta.url)); | ||
|
||
foo.addEventListener('message', e => { | ||
document.querySelector('h1').textContent = e.data; | ||
}); | ||
bar.addEventListener('message', e => { | ||
document.querySelector('h2').textContent = e.data; | ||
}); | ||
|
||
foo.postMessage('hello'); | ||
bar.postMessage('hello'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
addEventListener('message', () => { | ||
postMessage('it works'); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
const worker = new Worker(new URL('./foo.worker.js', import.meta.url)); | ||
|
||
worker.addEventListener('message', e => { | ||
document.querySelector('h1').textContent = e.data; | ||
}); | ||
|
||
worker.postMessage('hello'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
<h1>it doesn't work</h1> | ||
<script src="./index.js" type="module"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
import './foo/index.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { value } from './dep-b'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export const value = 'it works'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { value } from './dep-a'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { value } from './dep-b'; | ||
|
||
addEventListener('message', () => { | ||
postMessage(value); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<h1>it doesn't work</h1> | ||
<h2>it doesn't work</h2> | ||
<script src="./index.js" type="module"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { value as value2 } from './entry-1'; | ||
|
||
document.querySelector('h2').textContent = value2; | ||
|
||
const worker = new Worker(new URL('./foo.worker.js', import.meta.url)); | ||
|
||
worker.addEventListener('message', e => { | ||
document.querySelector('h1').textContent = e.data; | ||
}); | ||
|
||
worker.postMessage('hello'); |
Oops, something went wrong.