Skip to content

Commit

Permalink
fix: import url worker two times (#7468)
Browse files Browse the repository at this point in the history
  • Loading branch information
poyoho committed Mar 29, 2022
1 parent b16b896 commit f05a813
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 50 deletions.
4 changes: 2 additions & 2 deletions packages/playground/worker/__tests__/es/es-worker.spec.ts
Expand Up @@ -60,7 +60,7 @@ if (isBuild) {
// assert correct files
test('inlined code generation', async () => {
const files = fs.readdirSync(assetsDir)
expect(files.length).toBe(20)
expect(files.length).toBe(22)
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 @@ -94,7 +94,7 @@ test('classic worker', async () => {

test('emit chunk', async () => {
expect(await page.textContent('.emti-chunk-worker')).toMatch(
'{"msg1":"module1","msg2":"module2","msg3":"module3"}'
'["A string",{"type":"emit-chunk-sub-worker","data":"A string"},{"type":"module-and-worker:worker","data":"A string"},{"type":"module-and-worker:module","data":"module and worker"},{"type":"emit-chunk-sub-worker","data":{"module":"module and worker","msg1":"module1","msg2":"module2","msg3":"module3"}}]'
)
expect(await page.textContent('.emti-chunk-dynamic-import-worker')).toMatch(
'"A string/es/"'
Expand Down
25 changes: 23 additions & 2 deletions packages/playground/worker/emit-chunk-nested-worker.js
@@ -1,7 +1,28 @@
import SubWorker from './emit-chunk-sub-worker?worker'

const subWorker = new SubWorker()

subWorker.onmessage = (event) => {
self.postMessage(event.data)
self.postMessage({
type: 'emit-chunk-sub-worker',
data: event.data
})
}

const moduleWorker = new Worker(
new URL('./module-and-worker.js', import.meta.url),
{ type: 'module' }
)

moduleWorker.onmessage = (event) => {
self.postMessage({
type: 'module-and-worker:worker',
data: event.data
})
}

import('./module-and-worker').then((res) => {
self.postMessage({
type: 'module-and-worker:module',
data: res.module
})
})
14 changes: 8 additions & 6 deletions packages/playground/worker/emit-chunk-sub-worker.js
@@ -1,6 +1,8 @@
Promise.all([import('./modules/module2'), import('./modules/module3')]).then(
(data) => {
const _data = { ...data[0], ...data[1] }
self.postMessage(_data)
}
)
Promise.all([
import('./module-and-worker'),
import('./modules/module2'),
import('./modules/module3')
]).then((data) => {
const _data = { ...data[0], ...data[1], ...data[2] }
self.postMessage(_data)
})
10 changes: 9 additions & 1 deletion packages/playground/worker/index.html
Expand Up @@ -62,7 +62,9 @@ <h2 class="format-iife">format iife:</h2>
<h2 class="format-es"></h2>

<p>
worker emit chunk
worker emit chunk <br />
module and worker:worker in worker file <br />
module and worker:module in worker file <br />
<span class="classname">.emti-chunk-worker</span>
</p>
<code class="emti-chunk-worker"></code>
Expand All @@ -73,6 +75,12 @@ <h2 class="format-es"></h2>
</p>
<code class="emti-chunk-dynamic-import-worker"></code>

<p>
module and worker:worker in simple file
<span class="classname">.module-and-worker-worker</span>
</p>
<code class="module-and-worker-worker"></code>

<style>
p {
background: rgba(0, 0, 0, 0.1);
Expand Down
5 changes: 5 additions & 0 deletions packages/playground/worker/module-and-worker.js
@@ -0,0 +1,5 @@
import constant from './modules/module'

self.postMessage(constant)

export const module = 'module and worker'
20 changes: 19 additions & 1 deletion packages/playground/worker/worker/main-format-es.js
Expand Up @@ -8,8 +8,17 @@ function text(el, text) {
text('.format-es', 'format es:')

const nestedWorker = new NestedWorker()
const dataList = []
nestedWorker.addEventListener('message', (ev) => {
text('.emti-chunk-worker', JSON.stringify(ev.data))
dataList.push(ev.data)
text(
'.emti-chunk-worker',
JSON.stringify(
dataList.sort(
(a, b) => JSON.stringify(a).length - JSON.stringify(b).length
)
)
)
})

const dynamicImportWorker = new Worker(
Expand All @@ -21,3 +30,12 @@ const dynamicImportWorker = new Worker(
dynamicImportWorker.addEventListener('message', (ev) => {
text('.emti-chunk-dynamic-import-worker', JSON.stringify(ev.data))
})

const moduleWorker = new Worker(
new URL('../module-and-worker.js', import.meta.url),
{ type: 'module' }
)

moduleWorker.addEventListener('message', (ev) => {
text('.module-and-worker-worker', JSON.stringify(ev.data))
})
1 change: 1 addition & 0 deletions packages/playground/worker/worker/main-module.js
Expand Up @@ -28,6 +28,7 @@ inlineWorker.addEventListener('message', (e) => {
})

document.querySelector('.ping-inline').addEventListener('click', () => {
console.log('111')

This comment has been minimized.

Copy link
@GreenMashimaro

GreenMashimaro Mar 30, 2022

Hello, the code here is redundant~

inlineWorker.postMessage('ping')
})

Expand Down
8 changes: 1 addition & 7 deletions packages/vite/src/node/plugins/define.ts
Expand Up @@ -10,7 +10,6 @@ const isNonJsRequest = (request: string): boolean => nonJsRe.test(request)

export function definePlugin(config: ResolvedConfig): Plugin {
const isBuild = config.command === 'build'
const isWorker = config.isWorker

const processNodeEnv: Record<string, string> = {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || config.mode),
Expand Down Expand Up @@ -41,12 +40,7 @@ export function definePlugin(config: ResolvedConfig): Plugin {
Object.assign(importMetaKeys, {
'import.meta.env.': `({}).`,
'import.meta.env': JSON.stringify(config.env),
'import.meta.hot': `false`,
...(isWorker
? {
'import.meta.url': 'self.location.href'
}
: {})
'import.meta.hot': `false`
})
}

Expand Down
127 changes: 110 additions & 17 deletions packages/vite/src/node/plugins/worker.ts
Expand Up @@ -6,8 +6,65 @@ import type Rollup from 'rollup'
import { ENV_PUBLIC_PATH } from '../constants'
import path from 'path'
import { onRollupWarning } from '../build'
import type { EmittedFile } from 'rollup'

interface WorkerCache {
// save worker bundle emitted files avoid overwrites the same file.
// <chunk_filename, hash>
assets: Map<string, string>
chunks: Map<string, string>
// worker bundle don't deps on any more worker runtime info an id only had an result.
// save worker bundled file id to avoid repeated execution of bundles
// <filename, hash>
bundle: Map<string, string>
// nested worker bundle context don't had file what emitted by outside bundle
// save the hash to id to rewrite truth id.
// <hash, id>
emitted: Map<string, string>
}

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

function emitWorkerFile(
ctx: Rollup.TransformPluginContext,
config: ResolvedConfig,
asset: EmittedFile,
type: 'assets' | 'chunks'
): string {
const fileName = asset.fileName!
const workerMap = workerCache.get(config)!

if (workerMap[type].has(fileName)) {
return workerMap[type].get(fileName)!
}
const hash = ctx.emitFile(asset)
workerMap[type].set(fileName, hash)
workerMap.emitted.set(hash, fileName)
return hash
}

function emitWorkerAssets(
ctx: Rollup.TransformPluginContext,
config: ResolvedConfig,
asset: EmittedFile
) {
const { format } = config.worker
return emitWorkerFile(
ctx,
config,
asset,
format === 'es' ? 'chunks' : 'assets'
)
}

function emitWorkerChunks(
ctx: Rollup.TransformPluginContext,
config: ResolvedConfig,
asset: EmittedFile
) {
return emitWorkerFile(ctx, config, asset, 'chunks')
}

export async function bundleWorkerEntry(
ctx: Rollup.TransformPluginContext,
Expand Down Expand Up @@ -37,11 +94,13 @@ export async function bundleWorkerEntry(
code = outputCode.code
outputChunks.forEach((outputChunk) => {
if (outputChunk.type === 'asset') {
ctx.emitFile(outputChunk)
}
if (outputChunk.type === 'chunk') {
ctx.emitFile({
fileName: `${config.build.assetsDir}/${outputChunk.fileName}`,
emitWorkerAssets(ctx, config, outputChunk)
} else if (outputChunk.type === 'chunk') {
emitWorkerChunks(ctx, config, {
fileName: path.posix.join(
config.build.assetsDir,
outputChunk.fileName
),
source: outputChunk.code,
type: 'asset'
})
Expand All @@ -53,12 +112,50 @@ export async function bundleWorkerEntry(
return Buffer.from(code)
}

export async function workerFileToUrl(
ctx: Rollup.TransformPluginContext,
config: ResolvedConfig,
id: string
): Promise<string> {
const workerMap = workerCache.get(config)!

let hash = workerMap.bundle.get(id)
if (hash) {
// rewrite truth id, no need to replace by asset plugin
return config.base + workerMap.emitted.get(hash)!
}
const code = await bundleWorkerEntry(ctx, config, id)
const basename = path.parse(cleanUrl(id)).name
const contentHash = getAssetHash(code)
const fileName = path.posix.join(
config.build.assetsDir,
`${basename}.${contentHash}.js`
)
hash = emitWorkerAssets(ctx, config, {
fileName,
type: 'asset',
source: code
})
workerMap.bundle.set(id, hash)
return `__VITE_ASSET__${hash}__`
}

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

return {
name: 'vite:worker',

buildStart() {
workerCache.set(config, {
assets: new Map(),
chunks: new Map(),
bundle: new Map(),
emitted: new Map()
})
},

load(id) {
if (isBuild) {
const parsedQuery = parseRequest(id)
Expand Down Expand Up @@ -87,8 +184,8 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {

let url: string
if (isBuild) {
const code = await bundleWorkerEntry(this, config, id)
if (query.inline != null) {
const code = await bundleWorkerEntry(this, config, id)
const { format } = config.worker
const workerOptions = format === 'es' ? '{type: "module"}' : '{}'
// inline as blob data url
Expand All @@ -103,17 +200,7 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
}
}`
} else {
const basename = path.parse(cleanUrl(id)).name
const contentHash = getAssetHash(code)
const fileName = path.posix.join(
config.build.assetsDir,
`${basename}.${contentHash}.js`
)
url = `__VITE_ASSET__${this.emitFile({
fileName,
type: 'asset',
source: code
})}__`
url = await workerFileToUrl(this, config, id)
}
} else {
url = await fileToUrl(cleanUrl(id), config, this)
Expand All @@ -129,6 +216,12 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
url
)}, ${JSON.stringify(workerOptions, null, 2)})
}`
},

renderChunk(code) {
if (isWorker && code.includes('import.meta.url')) {
return code.replace('import.meta.url', 'self.location.href')
}
}
}
}
17 changes: 3 additions & 14 deletions packages/vite/src/node/plugins/workerImportMetaUrl.ts
@@ -1,7 +1,7 @@
import JSON5 from 'json5'
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import { getAssetHash, fileToUrl } from './asset'
import { fileToUrl } from './asset'
import {
blankReplacer,
cleanUrl,
Expand All @@ -11,7 +11,7 @@ import {
stringsRE
} from '../utils'
import path from 'path'
import { bundleWorkerEntry } from './worker'
import { workerFileToUrl } from './worker'
import { parseRequest } from '../utils'
import { ENV_ENTRY, ENV_PUBLIC_PATH } from '../constants'
import MagicString from 'magic-string'
Expand Down Expand Up @@ -162,18 +162,7 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
const file = path.resolve(path.dirname(id), rawUrl.slice(1, -1))
let url: string
if (isBuild) {
const content = await bundleWorkerEntry(this, config, file)
const basename = path.parse(cleanUrl(file)).name
const contentHash = getAssetHash(content)
const fileName = path.posix.join(
config.build.assetsDir,
`${basename}.${contentHash}.js`
)
url = `__VITE_ASSET__${this.emitFile({
fileName,
type: 'asset',
source: content
})}__`
url = await workerFileToUrl(this, config, file)
} else {
url = await fileToUrl(cleanUrl(file), config, this)
url = injectQuery(url, WORKER_FILE_ID)
Expand Down

0 comments on commit f05a813

Please sign in to comment.