Skip to content

Commit

Permalink
feat: 🎸 worker filterable
Browse files Browse the repository at this point in the history
  • Loading branch information
IWANABETHATGUY committed Sep 13, 2024
1 parent f3ffc27 commit bbcc0c8
Showing 1 changed file with 100 additions and 85 deletions.
185 changes: 100 additions & 85 deletions packages/vite/src/node/plugins/worker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from 'node:path'
import MagicString from 'magic-string'
import type { OutputChunk } from 'rolldown'
import type { OutputChunk, RolldownPlugin } from 'rolldown'
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import type { ViteDevServer } from '../server'
Expand Down Expand Up @@ -209,14 +209,15 @@ export function webWorkerPostPlugin(): Plugin {
}
}

export function webWorkerPlugin(config: ResolvedConfig): Plugin {
export function webWorkerPlugin(config: ResolvedConfig): RolldownPlugin {
const isBuild = config.command === 'build'
let server: ViteDevServer
const isWorker = config.isWorker

return {
name: 'vite:worker',

// @ts-expect-error TODO: compatible with Vite Plugin
configureServer(_server) {
server = _server
},
Expand All @@ -232,10 +233,17 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
})
},

load(id) {
if (isBuild && workerOrSharedWorkerRE.test(id)) {
return ''
}
load: {
filter: {
id: {
include: [workerOrSharedWorkerRE],
},
},
handler(id) {
if (isBuild && workerOrSharedWorkerRE.test(id)) {
return ''
}
},
},

// TODO @underfin it's not unsupported yet
Expand All @@ -245,74 +253,80 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
// }
// },

async transform(raw, id) {
const workerFileMatch = workerFileRE.exec(id)
if (workerFileMatch) {
// if import worker by worker constructor will have query.type
// other type will be import worker by esm
const workerType = workerFileMatch[1] as WorkerType
let injectEnv = ''

const scriptPath = JSON.stringify(
path.posix.join(config.base, ENV_PUBLIC_PATH),
)
transform: {
filter: {
id: {
include: [workerOrSharedWorkerRE, workerFileRE],
},
},
async handler(raw, id) {
const workerFileMatch = workerFileRE.exec(id)
if (workerFileMatch) {
// if import worker by worker constructor will have query.type
// other type will be import worker by esm
const workerType = workerFileMatch[1] as WorkerType
let injectEnv = ''

const scriptPath = JSON.stringify(
path.posix.join(config.base, ENV_PUBLIC_PATH),
)

if (workerType === 'classic') {
injectEnv = `importScripts(${scriptPath})\n`
} else if (workerType === 'module') {
injectEnv = `import ${scriptPath}\n`
} else if (workerType === 'ignore') {
if (isBuild) {
injectEnv = ''
} else if (server) {
// dynamic worker type we can't know how import the env
// so we copy /@vite/env code of server transform result into file header
const { moduleGraph } = server
const module = moduleGraph.getModuleById(ENV_ENTRY)
injectEnv = module?.transformResult?.code || ''
if (workerType === 'classic') {
injectEnv = `importScripts(${scriptPath})\n`
} else if (workerType === 'module') {
injectEnv = `import ${scriptPath}\n`
} else if (workerType === 'ignore') {
if (isBuild) {
injectEnv = ''
} else if (server) {
// dynamic worker type we can't know how import the env
// so we copy /@vite/env code of server transform result into file header
const { moduleGraph } = server
const module = moduleGraph.getModuleById(ENV_ENTRY)
injectEnv = module?.transformResult?.code || ''
}
}
}
if (injectEnv) {
const s = new MagicString(raw)
s.prepend(injectEnv + ';\n')
return {
code: s.toString(),
map: s.generateMap({ hires: 'boundary' }),
if (injectEnv) {
const s = new MagicString(raw)
s.prepend(injectEnv + ';\n')
return {
code: s.toString(),
map: s.generateMap({ hires: 'boundary' }),
}
}
return
}
return
}

const workerMatch = workerOrSharedWorkerRE.exec(id)
if (!workerMatch) return

const { format } = config.worker
const workerConstructor =
workerMatch[1] === 'sharedworker' ? 'SharedWorker' : 'Worker'
const workerType = isBuild
? format === 'es'
? 'module'
: 'classic'
: 'module'
const workerTypeOption = `{
const workerMatch = workerOrSharedWorkerRE.exec(id)
if (!workerMatch) return

const { format } = config.worker
const workerConstructor =
workerMatch[1] === 'sharedworker' ? 'SharedWorker' : 'Worker'
const workerType = isBuild
? format === 'es'
? 'module'
: 'classic'
: 'module'
const workerTypeOption = `{
${workerType === 'module' ? `type: "module",` : ''}
name: options?.name
}`

let urlCode: string
if (isBuild) {
if (isWorker && config.bundleChain.at(-1) === cleanUrl(id)) {
urlCode = 'self.location.href'
} else if (inlineRE.test(id)) {
const chunk = await bundleWorkerEntry(config, id)
const encodedJs = `const encodedJs = "${Buffer.from(
chunk.code,
).toString('base64')}";`

const code =
// Using blob URL for SharedWorker results in multiple instances of a same worker
workerConstructor === 'Worker'
? `${encodedJs}
let urlCode: string
if (isBuild) {
if (isWorker && config.bundleChain.at(-1) === cleanUrl(id)) {
urlCode = 'self.location.href'
} else if (inlineRE.test(id)) {
const chunk = await bundleWorkerEntry(config, id)
const encodedJs = `const encodedJs = "${Buffer.from(
chunk.code,
).toString('base64')}";`

const code =
// Using blob URL for SharedWorker results in multiple instances of a same worker
workerConstructor === 'Worker'
? `${encodedJs}
const decodeBase64 = (base64) => Uint8Array.from(atob(base64), c => c.charCodeAt(0));
const blob = typeof self !== "undefined" && self.Blob && new Blob([${
workerType === 'classic'
Expand Down Expand Up @@ -345,7 +359,7 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
: ''
}
}`
: `${encodedJs}
: `${encodedJs}
export default function WorkerWrapper(options) {
return new ${workerConstructor}(
"data:text/javascript;base64," + encodedJs,
Expand All @@ -354,36 +368,37 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
}
`

return {
code,
// Empty sourcemap to suppress Rollup warning
map: { mappings: '' },
return {
code,
// Empty sourcemap to suppress Rollup warning
map: { mappings: '' },
}
} else {
urlCode = JSON.stringify(await workerFileToUrl(config, id))
}
} else {
urlCode = JSON.stringify(await workerFileToUrl(config, id))
let url = await fileToUrl(cleanUrl(id), config, this)
url = injectQuery(url, `${WORKER_FILE_ID}&type=${workerType}`)
urlCode = JSON.stringify(url)
}
} else {
let url = await fileToUrl(cleanUrl(id), config, this)
url = injectQuery(url, `${WORKER_FILE_ID}&type=${workerType}`)
urlCode = JSON.stringify(url)
}

if (urlRE.test(id)) {
return {
code: `export default ${urlCode}`,
map: { mappings: '' }, // Empty sourcemap to suppress Rollup warning
if (urlRE.test(id)) {
return {
code: `export default ${urlCode}`,
map: { mappings: '' }, // Empty sourcemap to suppress Rollup warning
}
}
}

return {
code: `export default function WorkerWrapper(options) {
return {
code: `export default function WorkerWrapper(options) {
return new ${workerConstructor}(
${urlCode},
${workerTypeOption}
);
}`,
map: { mappings: '' }, // Empty sourcemap to suppress Rollup warning
}
map: { mappings: '' }, // Empty sourcemap to suppress Rollup warning
}
},
},

renderChunk(code, chunk, outputOptions) {
Expand Down

0 comments on commit bbcc0c8

Please sign in to comment.