Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: import url worker two times #7468

Merged
merged 9 commits into from Mar 29, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -57,7 +57,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 @@ -68,6 +70,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')
inlineWorker.postMessage('ping')
})

Expand Down
93 changes: 77 additions & 16 deletions packages/vite/src/node/plugins/worker.ts
Expand Up @@ -6,9 +6,55 @@ import type Rollup from 'rollup'
import { ENV_PUBLIC_PATH } from '../constants'
import path from 'path'
import { onRollupWarning } from '../build'
import type { EmittedFile } from 'rollup'

const WorkerFileId = 'worker_file'

// save worker bundle emitted files avoid overwrites the same file.
// <chunk_filename, hash>
const workerEmittedAssets = new Map<string, string>()
const workerEmittedChunk = new 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>
const workerBundled = new 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>
const workerEmittedFile = new Map<string, string>()
poyoho marked this conversation as resolved.
Show resolved Hide resolved

function emitWorkerFile(
ctx: Rollup.TransformPluginContext,
asset: EmittedFile,
map: Map<string, string>
): string {
const fileName = asset.fileName!

if (map.has(fileName)) {
return map.get(fileName)!
}
const hash = ctx.emitFile(asset)
map.set(fileName, hash)
workerEmittedFile.set(hash, fileName)
return hash
}

function emitWorkerAssets(
ctx: Rollup.TransformPluginContext,
asset: EmittedFile
): string {
return emitWorkerFile(ctx, asset, workerEmittedAssets)
}

function emitWorkerChunks(
ctx: Rollup.TransformPluginContext,
asset: EmittedFile
): string {
return emitWorkerFile(ctx, asset, workerEmittedChunk)
}

export async function bundleWorkerEntry(
ctx: Rollup.TransformPluginContext,
config: ResolvedConfig,
Expand Down Expand Up @@ -37,10 +83,9 @@ export async function bundleWorkerEntry(
code = outputCode.code
outputChunks.forEach((outputChunk) => {
if (outputChunk.type === 'asset') {
ctx.emitFile(outputChunk)
}
if (outputChunk.type === 'chunk') {
ctx.emitFile({
emitWorkerAssets(ctx, outputChunk)
} else if (outputChunk.type === 'chunk') {
emitWorkerChunks(ctx, {
fileName: `${config.build.assetsDir}/${outputChunk.fileName}`,
source: outputChunk.code,
type: 'asset'
Expand All @@ -53,6 +98,32 @@ export async function bundleWorkerEntry(
return Buffer.from(code)
}

export async function workerFileToUrl(
ctx: Rollup.TransformPluginContext,
config: ResolvedConfig,
id: string
): Promise<string> {
let hash = workerBundled.get(id)
if (hash) {
// rewrite truth id, no need to replace by asset plugin
return config.base + workerEmittedFile.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 = emitWorkerChunks(ctx, {
fileName,
type: 'asset',
source: code
})
workerBundled.set(id, hash)
return `__VITE_ASSET__${hash}__`
}

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

Expand Down Expand Up @@ -87,8 +158,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 +174,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 Down
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 @@ -10,7 +10,7 @@ import {
singlelineCommentsRE
} 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 @@ -152,18 +152,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