Skip to content

Commit

Permalink
Turbopack: support module workers (vercel#72614)
Browse files Browse the repository at this point in the history
- Also process `new Worker()` if there are options
- Then remove the `type: module` from the options at runtime (as Webpack
also does apparently). The alternative would be to keep the `type:
module` and ESM imports instead in the worker.
  • Loading branch information
mischnic authored Dec 11, 2024
1 parent b1cf6f7 commit 0f27308
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export default function Home() {
<div>
<button
onClick={() => {
const worker = new Worker(new URL('./worker', import.meta.url))
const worker = new Worker(new URL('../worker', import.meta.url))
worker.addEventListener('message', (event) => {
setState(event.data)
})
Expand Down
24 changes: 24 additions & 0 deletions test/e2e/app-dir/worker/app/module/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use client'
import { useState } from 'react'

export default function Home() {
const [state, setState] = useState('default')
return (
<div>
<button
onClick={() => {
const worker = new Worker(new URL('../worker', import.meta.url), {
type: 'module',
})
worker.addEventListener('message', (event) => {
setState(event.data)
})
}}
>
Get web worker data
</button>
<p>Worker state: </p>
<p id="worker-state">{state}</p>
</div>
)
}
14 changes: 13 additions & 1 deletion test/e2e/app-dir/worker/worker.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,19 @@ describe('app dir - workers', () => {
}

it('should support web workers with dynamic imports', async () => {
const browser = await next.browser('/')
const browser = await next.browser('/classic')
expect(await browser.elementByCss('#worker-state').text()).toBe('default')

await browser.elementByCss('button').click()

await check(
async () => browser.elementByCss('#worker-state').text(),
'worker.ts:worker-dep'
)
})

it('should support module web workers with dynamic imports', async () => {
const browser = await next.browser('/module')
expect(await browser.elementByCss('#worker-state').text()).toBe('default')

await browser.elementByCss('button').click()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ function resolveAbsolutePath(modulePath?: string): string {
}

function getWorkerBlobURL(chunks: ChunkPath[]): string {
let bootstrap = `TURBOPACK_WORKER_LOCATION = ${JSON.stringify(location.origin)};importScripts(${chunks.map(c => (`TURBOPACK_WORKER_LOCATION + ${JSON.stringify(getChunkRelativeUrl(c))}`)).join(", ")});`;
let bootstrap = `self.TURBOPACK_WORKER_LOCATION = ${JSON.stringify(location.origin)};importScripts(${chunks.map(c => (`self.TURBOPACK_WORKER_LOCATION + ${JSON.stringify(getChunkRelativeUrl(c))}`)).join(", ")});`;
let blob = new Blob([bootstrap], { type: "text/javascript" });
return URL.createObjectURL(blob);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1407,7 +1407,7 @@ async fn handle_call<G: Fn(Vec<Effect>) + Send + Sync>(
}
JsValue::WellKnownFunction(WellKnownFunctionKind::WorkerConstructor) => {
let args = linked_args(args).await?;
if let [url @ JsValue::Url(_, JsValueUrlKind::Relative)] = &args[..] {
if let Some(url @ JsValue::Url(_, JsValueUrlKind::Relative)) = args.first() {
let pat = js_value_to_pattern(url);
if !pat.has_constant_parts() {
let (args, hints) = explain_args(&args);
Expand Down
15 changes: 13 additions & 2 deletions turbopack/crates/turbopack-ecmascript/src/references/worker.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use anyhow::{bail, Result};
use swc_core::{
common::util::take::Take,
ecma::ast::{Expr, ExprOrSpread, Lit, NewExpr},
quote_expr,
};
Expand Down Expand Up @@ -65,7 +66,7 @@ impl WorkerAssetReference {
);

let Some(module) = *module.first_module().await? else {
bail!("Expected worker to resolve to a module");
return Ok(None);
};
let Some(chunkable) = ResolvedVc::try_downcast::<Box<dyn ChunkableModule>>(module).await?
else {
Expand Down Expand Up @@ -133,13 +134,23 @@ impl CodeGenerateable for WorkerAssetReference {
let visitor = create_visitor!(path, visit_mut_expr(expr: &mut Expr) {
let message = if let Expr::New(NewExpr { args, ..}) = expr {
if let Some(args) = args {
match args.iter_mut().next() {
match args.first_mut() {
Some(ExprOrSpread { spread: None, expr }) => {
let item_id = Expr::Lit(Lit::Str(item_id.to_string().into()));
*expr = quote_expr!(
"__turbopack_require__($item_id)",
item_id: Expr = item_id
);

if let Some(opts) = args.get_mut(1) {
if opts.spread.is_none(){
*opts.expr = *quote_expr!(
"{...$opts, type: undefined}",
opts: Expr = (*opts.expr).take()
);
}

}
return;
}
// These are SWC bugs: https://github.com/swc-project/swc/issues/5394
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

0 comments on commit 0f27308

Please sign in to comment.