Skip to content

Commit

Permalink
feat: worker support query url (#7914)
Browse files Browse the repository at this point in the history
  • Loading branch information
poyoho committed May 21, 2022
1 parent 49478ae commit 95297dd
Show file tree
Hide file tree
Showing 11 changed files with 79 additions and 46 deletions.
47 changes: 41 additions & 6 deletions packages/vite/src/node/plugins/worker.ts
Expand Up @@ -3,14 +3,15 @@ import MagicString from 'magic-string'
import type { EmittedAsset, OutputChunk, TransformPluginContext } from 'rollup'
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import type { ViteDevServer } from '../server'
import { ENV_ENTRY, ENV_PUBLIC_PATH } from '../constants'
import {
cleanUrl,
getHash,
injectQuery,
isRelativeBase,
parseRequest
} from '../utils'
import { ENV_PUBLIC_PATH } from '../constants'
import { onRollupWarning } from '../build'
import { fileToUrl } from './asset'

Expand All @@ -27,7 +28,9 @@ interface WorkerCache {
fileNameHash: Map<string, string>
}

const WorkerFileId = 'worker_file'
export type WorkerType = 'classic' | 'module' | 'ignore'

export const WORKER_FILE_ID = 'worker_file'
const workerCache = new WeakMap<ResolvedConfig, WorkerCache>()

function saveEmitWorkerAsset(
Expand Down Expand Up @@ -188,10 +191,16 @@ export async function workerFileToUrl(

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

return {
name: 'vite:worker',

configureServer(_server) {
server = _server
},

buildStart() {
if (isWorker) {
return
Expand All @@ -215,11 +224,30 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
}
},

async transform(_, id) {
async transform(raw, id) {
const query = parseRequest(id)
if (query && query[WorkerFileId] != null) {
if (query && query[WORKER_FILE_ID] != null && query['type'] != null) {
const workerType = query['type'] as WorkerType
let injectEnv = ''

if (workerType === 'classic') {
injectEnv = `importScripts('${ENV_PUBLIC_PATH}')\n`
} else if (workerType === 'module') {
injectEnv = `import '${ENV_PUBLIC_PATH}'\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 || ''
}
}

return {
code: `import '${ENV_PUBLIC_PATH}'\n` + _
code: injectEnv + raw
}
}
if (
Expand Down Expand Up @@ -259,7 +287,14 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
}
} else {
url = await fileToUrl(cleanUrl(id), config, this)
url = injectQuery(url, WorkerFileId)
url = injectQuery(url, WORKER_FILE_ID)
}

if (query.url != null) {
return {
code: `export default ${JSON.stringify(url)}`,
map: { mappings: '' } // Empty sourcemap to suppress Rollup warning
}
}

const workerConstructor =
Expand Down
37 changes: 2 additions & 35 deletions packages/vite/src/node/plugins/workerImportMetaUrl.ts
Expand Up @@ -6,16 +6,12 @@ import { stripLiteral } from 'strip-literal'
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import { cleanUrl, injectQuery, normalizePath, parseRequest } from '../utils'
import { ENV_ENTRY, ENV_PUBLIC_PATH } from '../constants'
import type { ViteDevServer } from '..'
import { workerFileToUrl } from './worker'
import type { WorkerType } from './worker'
import { WORKER_FILE_ID, workerFileToUrl } from './worker'
import { fileToUrl } from './asset'

type WorkerType = 'classic' | 'module' | 'ignore'
const ignoreFlagRE = /\/\*\s*@vite-ignore\s*\*\//

const WORKER_FILE_ID = 'worker_url_file'

function getWorkerType(raw: string, clean: string, i: number): WorkerType {
function err(e: string, pos: number) {
const error = new Error(e) as RollupError
Expand Down Expand Up @@ -68,41 +64,12 @@ function getWorkerType(raw: string, clean: string, i: number): WorkerType {

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

return {
name: 'vite:worker-import-meta-url',

configureServer(_server) {
server = _server
},

async transform(code, id, options) {
const query = parseRequest(id)
if (query && query[WORKER_FILE_ID] != null && query['type'] != null) {
const workerType = query['type'] as WorkerType
let injectEnv = ''

if (workerType === 'classic') {
injectEnv = `importScripts('${ENV_PUBLIC_PATH}')\n`
} else if (workerType === 'module') {
injectEnv = `import '${ENV_PUBLIC_PATH}'\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 || ''
}
}

return {
code: injectEnv + code
}
}
let s: MagicString | undefined
if (
(code.includes('new Worker') || code.includes('new SharedWorker')) &&
Expand Down
8 changes: 7 additions & 1 deletion playground/worker/__tests__/es/es-worker.spec.ts
Expand Up @@ -66,7 +66,7 @@ describe.runIf(isBuild)('build', () => {
test('inlined code generation', async () => {
const assetsDir = path.resolve(testDir, 'dist/es/assets')
const files = fs.readdirSync(assetsDir)
expect(files.length).toBe(25)
expect(files.length).toBe(27)
const index = files.find((f) => f.includes('main-module'))
const content = fs.readFileSync(path.resolve(assetsDir, index), 'utf-8')
const worker = files.find((f) => f.includes('my-worker'))
Expand Down Expand Up @@ -116,6 +116,12 @@ test('emit chunk', async () => {
)
})

test('url query worker', async () => {
expect(await page.textContent('.simple-worker-url')).toMatch(
'Hello from simple worker!'
)
})

test('import.meta.glob in worker', async () => {
expect(await page.textContent('.importMetaGlob-worker')).toMatch('["')
})
Expand Down
8 changes: 7 additions & 1 deletion playground/worker/__tests__/iife/worker.spec.ts
Expand Up @@ -65,7 +65,7 @@ describe.runIf(isBuild)('build', () => {
test('inlined code generation', async () => {
const assetsDir = path.resolve(testDir, 'dist/iife/assets')
const files = fs.readdirSync(assetsDir)
expect(files.length).toBe(13)
expect(files.length).toBe(15)
const index = files.find((f) => f.includes('main-module'))
const content = fs.readFileSync(path.resolve(assetsDir, index), 'utf-8')
const worker = files.find((f) => f.includes('my-worker'))
Expand Down Expand Up @@ -106,6 +106,12 @@ test('classic worker', async () => {
expect(await page.textContent('.classic-shared-worker')).toMatch('A classic')
})

test('url query worker', async () => {
expect(await page.textContent('.simple-worker-url')).toMatch(
'Hello from simple worker!'
)
})

test('import.meta.glob eager in worker', async () => {
expect(await page.textContent('.importMetaGlobEager-worker')).toMatch('["')
})
Expand Up @@ -9,7 +9,7 @@ describe.runIf(isBuild)('build', () => {

const files = fs.readdirSync(assetsDir)
// should have 2 worker chunk
expect(files.length).toBe(26)
expect(files.length).toBe(30)
const index = files.find((f) => f.includes('main-module'))
const content = fs.readFileSync(path.resolve(assetsDir, index), 'utf-8')
const indexSourcemap = getSourceMapUrl(content)
Expand Down
Expand Up @@ -9,7 +9,7 @@ describe.runIf(isBuild)('build', () => {

const files = fs.readdirSync(assetsDir)
// should have 2 worker chunk
expect(files.length).toBe(13)
expect(files.length).toBe(15)
const index = files.find((f) => f.includes('main-module'))
const content = fs.readFileSync(path.resolve(assetsDir, index), 'utf-8')
const indexSourcemap = getSourceMapUrl(content)
Expand Down
Expand Up @@ -8,7 +8,7 @@ describe.runIf(isBuild)('build', () => {
const assetsDir = path.resolve(testDir, 'dist/iife-sourcemap/assets')
const files = fs.readdirSync(assetsDir)
// should have 2 worker chunk
expect(files.length).toBe(26)
expect(files.length).toBe(30)
const index = files.find((f) => f.includes('main-module'))
const content = fs.readFileSync(path.resolve(assetsDir, index), 'utf-8')
const indexSourcemap = getSourceMapUrl(content)
Expand Down
6 changes: 6 additions & 0 deletions playground/worker/index.html
Expand Up @@ -72,6 +72,12 @@ <h2 class="format-iife">format iife:</h2>
</p>
<code class="classic-shared-worker"></code>

<p>
new Worker(new URL('../simple-worker.js', import.meta.url).href)
<span class="classname">.simple-worker-url</span>
</p>
<code class="simple-worker-url"></code>

<p>
use import.meta.glob with eager in iife worker
<span class="classname">.importMetaGlobEager-worker</span>
Expand Down
1 change: 1 addition & 0 deletions playground/worker/simple-worker.js
@@ -0,0 +1 @@
self.postMessage('Hello from simple worker!')
11 changes: 11 additions & 0 deletions playground/worker/worker/main-url.js
@@ -0,0 +1,11 @@
import workerUrl from '../simple-worker?worker&url'

function text(el, text) {
document.querySelector(el).textContent = text
}

const worker = new Worker(workerUrl, { type: 'classic' })

worker.addEventListener('message', (ev) => {
text('.simple-worker-url', JSON.stringify(ev.data))
})
1 change: 1 addition & 0 deletions playground/worker/worker/main.js
@@ -1,3 +1,4 @@
/* flag: will replace in vite config import("./format-es.js") */
import('./main-module')
import('./main-classic')
import('./main-url')

0 comments on commit 95297dd

Please sign in to comment.