/
workerImportMetaUrl.ts
103 lines (94 loc) · 3.32 KB
/
workerImportMetaUrl.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import { getAssetHash, fileToUrl } from './asset'
import {
cleanUrl,
injectQuery,
multilineCommentsRE,
singlelineCommentsRE
} from '../utils'
import path from 'path'
import { bundleWorkerEntry, emitSourcemapForWorkerEntry } from './worker'
import { parseRequest } from '../utils'
import { ENV_PUBLIC_PATH } from '../constants'
import MagicString from 'magic-string'
const WORKER_FILE_ID = 'worker_url_file'
export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
const isBuild = config.command === 'build'
return {
name: 'vite:worker-import-meta-url',
async transform(code, id, options) {
const query = parseRequest(id)
if (query && query[WORKER_FILE_ID] != null) {
return {
code: `import '${ENV_PUBLIC_PATH}'\n` + code
}
}
if (
(code.includes('new Worker') || code.includes('new ShareWorker')) &&
code.includes('new URL') &&
code.includes(`import.meta.url`)
) {
const importMetaUrlRE =
/\bnew\s+(Worker|SharedWorker)\s*\(\s*(new\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*\))/g
const noCommentsCode = code
.replace(multilineCommentsRE, (m) => ' '.repeat(m.length))
.replace(singlelineCommentsRE, (m) => ' '.repeat(m.length))
let match: RegExpExecArray | null
let s: MagicString | null = null
while ((match = importMetaUrlRE.exec(noCommentsCode))) {
const { 0: allExp, 2: exp, 3: rawUrl, index } = match
const urlIndex = allExp.indexOf(exp) + index
if (options?.ssr) {
this.error(
`\`new URL(url, import.meta.url)\` is not supported in SSR.`,
urlIndex
)
}
// potential dynamic template string
if (rawUrl[0] === '`' && /\$\{/.test(rawUrl)) {
this.error(
`\`new URL(url, import.meta.url)\` is not supported in dynamic template string.`,
urlIndex
)
}
s ||= new MagicString(code)
const file = path.resolve(path.dirname(id), rawUrl.slice(1, -1))
let url: string
if (isBuild) {
const bundle = await bundleWorkerEntry(config, file)
const { code: content } = emitSourcemapForWorkerEntry(
this,
config,
file,
query,
bundle
)
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
})}__`
} else {
url = await fileToUrl(cleanUrl(file), config, this)
url = injectQuery(url, WORKER_FILE_ID)
}
s.overwrite(urlIndex, urlIndex + exp.length, JSON.stringify(url))
}
if (s) {
return {
code: s.toString(),
map: config.build.sourcemap ? s.generateMap({ hires: true }) : null
}
}
return null
}
}
}
}