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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(build): bundle non-inlined workers with rollup #2494

Merged
merged 4 commits into from Jun 27, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
9 changes: 9 additions & 0 deletions packages/playground/worker/__tests__/worker.spec.ts
Expand Up @@ -51,6 +51,15 @@ if (isBuild) {
expect(files.length).toBe(3)
const index = files.find((f) => f.includes('index'))
const content = fs.readFileSync(path.resolve(assetsDir, index), 'utf-8')
const worker = files.find((f) => f.includes('my-worker'))
const workerContent = fs.readFileSync(
path.resolve(assetsDir, worker),
'utf-8'
)

// worker should have all imports resolved and no exports
expect(workerContent).not.toMatch(`import`)
expect(workerContent).not.toMatch(`export`)
// chunk
expect(content).toMatch(`new Worker("/assets`)
expect(content).toMatch(`new SharedWorker("/assets`)
Expand Down
4 changes: 4 additions & 0 deletions packages/playground/worker/index.html
@@ -1,3 +1,4 @@
<div>Expected values: <span class="mode-true"></span></div>
<button class="ping">Ping</button>
<div>
Response from worker: <span class="pong"></span><span class="mode"></span>
Expand All @@ -16,6 +17,9 @@
import Worker from './my-worker?worker'
import InlineWorker from './my-worker?worker&inline'
import SharedWorker from './my-shared-worker?sharedworker&name=shared'
import { mode } from './workerImport'

document.querySelector('.mode-true').textContent = mode

const worker = new Worker()
worker.addEventListener('message', (e) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/vite/src/node/plugins/asset.ts
Expand Up @@ -254,7 +254,7 @@ async function fileToBuiltUrl(
return url
}

function getAssetHash(content: Buffer) {
export function getAssetHash(content: Buffer): string {
return createHash('sha256').update(content).digest('hex').slice(0, 8)
}

Expand Down
54 changes: 33 additions & 21 deletions packages/vite/src/node/plugins/worker.ts
@@ -1,11 +1,13 @@
import { ResolvedConfig } from '../config'
import { Plugin } from '../plugin'
import { resolvePlugins } from '../plugins'
import { parse as parseUrl } from 'url'
import qs, { ParsedUrlQuery } from 'querystring'
import { fileToUrl } from './asset'
import { fileToUrl, getAssetHash } from './asset'
import { cleanUrl, injectQuery } from '../utils'
import Rollup from 'rollup'
import { ENV_PUBLIC_PATH } from '../constants'
import path from 'path'

function parseWorkerRequest(id: string): ParsedUrlQuery | null {
const { search } = parseUrl(id)
Expand Down Expand Up @@ -51,21 +53,28 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {

let url: string
if (isBuild) {
if (query.inline != null) {
// bundle the file as entry to support imports and inline as blob
// data url
const rollup = require('rollup') as typeof Rollup
const bundle = await rollup.rollup({
input: cleanUrl(id),
plugins: config.plugins as Plugin[]
// bundle the file as entry to support imports
const rollup = require('rollup') as typeof Rollup
const bundle = await rollup.rollup({
input: cleanUrl(id),
plugins: await resolvePlugins({ ...config }, [], [], [])
})
let code: string
try {
const { output } = await bundle.generate({
format: 'iife',
antfu marked this conversation as resolved.
Show resolved Hide resolved
sourcemap: config.build.sourcemap
})
try {
const { output } = await bundle.generate({
format: 'es',
sourcemap: config.build.sourcemap
})

return `const blob = new Blob([atob(\"${Buffer.from(output[0].code).toString('base64')}\")], { type: 'text/javascript;charset=utf-8' });
code = output[0].code
} finally {
await bundle.close()
}
const content = Buffer.from(code)
if (query.inline != null) {
// inline as blob data url
return `const blob = new Blob([atob(\"${content.toString(
'base64'
)}\")], { type: 'text/javascript;charset=utf-8' });
export default function WorkerWrapper() {
const objURL = (window.URL || window.webkitURL).createObjectURL(blob);
try {
Expand All @@ -74,14 +83,17 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
(window.URL || window.webkitURL).revokeObjectURL(objURL);
}
}`
} finally {
await bundle.close()
}
} else {
// emit as separate chunk
const basename = path.parse(cleanUrl(id)).name
const contentHash = getAssetHash(content)
const fileName = path.posix.join(
config.build.assetsDir,
`${basename}.${contentHash}.js`
)
url = `__VITE_ASSET__${this.emitFile({
type: 'chunk',
id: cleanUrl(id)
fileName,
type: 'asset',
source: code
})}__`
}
} else {
Expand Down