@@ -6,8 +6,65 @@ import type Rollup from 'rollup'
6
6
import { ENV_PUBLIC_PATH } from '../constants'
7
7
import path from 'path'
8
8
import { onRollupWarning } from '../build'
9
+ import type { EmittedFile } from 'rollup'
10
+
11
+ interface WorkerCache {
12
+ // save worker bundle emitted files avoid overwrites the same file.
13
+ // <chunk_filename, hash>
14
+ assets : Map < string , string >
15
+ chunks : Map < string , string >
16
+ // worker bundle don't deps on any more worker runtime info an id only had an result.
17
+ // save worker bundled file id to avoid repeated execution of bundles
18
+ // <filename, hash>
19
+ bundle : Map < string , string >
20
+ // nested worker bundle context don't had file what emitted by outside bundle
21
+ // save the hash to id to rewrite truth id.
22
+ // <hash, id>
23
+ emitted : Map < string , string >
24
+ }
9
25
10
26
const WorkerFileId = 'worker_file'
27
+ const workerCache = new WeakMap < ResolvedConfig , WorkerCache > ( )
28
+
29
+ function emitWorkerFile (
30
+ ctx : Rollup . TransformPluginContext ,
31
+ config : ResolvedConfig ,
32
+ asset : EmittedFile ,
33
+ type : 'assets' | 'chunks'
34
+ ) : string {
35
+ const fileName = asset . fileName !
36
+ const workerMap = workerCache . get ( config ) !
37
+
38
+ if ( workerMap [ type ] . has ( fileName ) ) {
39
+ return workerMap [ type ] . get ( fileName ) !
40
+ }
41
+ const hash = ctx . emitFile ( asset )
42
+ workerMap [ type ] . set ( fileName , hash )
43
+ workerMap . emitted . set ( hash , fileName )
44
+ return hash
45
+ }
46
+
47
+ function emitWorkerAssets (
48
+ ctx : Rollup . TransformPluginContext ,
49
+ config : ResolvedConfig ,
50
+ asset : EmittedFile
51
+ ) {
52
+ const { format } = config . worker
53
+ return emitWorkerFile (
54
+ ctx ,
55
+ config ,
56
+ asset ,
57
+ format === 'es' ? 'chunks' : 'assets'
58
+ )
59
+ }
60
+
61
+ function emitWorkerChunks (
62
+ ctx : Rollup . TransformPluginContext ,
63
+ config : ResolvedConfig ,
64
+ asset : EmittedFile
65
+ ) {
66
+ return emitWorkerFile ( ctx , config , asset , 'chunks' )
67
+ }
11
68
12
69
export async function bundleWorkerEntry (
13
70
ctx : Rollup . TransformPluginContext ,
@@ -37,11 +94,13 @@ export async function bundleWorkerEntry(
37
94
code = outputCode . code
38
95
outputChunks . forEach ( ( outputChunk ) => {
39
96
if ( outputChunk . type === 'asset' ) {
40
- ctx . emitFile ( outputChunk )
41
- }
42
- if ( outputChunk . type === 'chunk' ) {
43
- ctx . emitFile ( {
44
- fileName : `${ config . build . assetsDir } /${ outputChunk . fileName } ` ,
97
+ emitWorkerAssets ( ctx , config , outputChunk )
98
+ } else if ( outputChunk . type === 'chunk' ) {
99
+ emitWorkerChunks ( ctx , config , {
100
+ fileName : path . posix . join (
101
+ config . build . assetsDir ,
102
+ outputChunk . fileName
103
+ ) ,
45
104
source : outputChunk . code ,
46
105
type : 'asset'
47
106
} )
@@ -53,12 +112,50 @@ export async function bundleWorkerEntry(
53
112
return Buffer . from ( code )
54
113
}
55
114
115
+ export async function workerFileToUrl (
116
+ ctx : Rollup . TransformPluginContext ,
117
+ config : ResolvedConfig ,
118
+ id : string
119
+ ) : Promise < string > {
120
+ const workerMap = workerCache . get ( config ) !
121
+
122
+ let hash = workerMap . bundle . get ( id )
123
+ if ( hash ) {
124
+ // rewrite truth id, no need to replace by asset plugin
125
+ return config . base + workerMap . emitted . get ( hash ) !
126
+ }
127
+ const code = await bundleWorkerEntry ( ctx , config , id )
128
+ const basename = path . parse ( cleanUrl ( id ) ) . name
129
+ const contentHash = getAssetHash ( code )
130
+ const fileName = path . posix . join (
131
+ config . build . assetsDir ,
132
+ `${ basename } .${ contentHash } .js`
133
+ )
134
+ hash = emitWorkerAssets ( ctx , config , {
135
+ fileName,
136
+ type : 'asset' ,
137
+ source : code
138
+ } )
139
+ workerMap . bundle . set ( id , hash )
140
+ return `__VITE_ASSET__${ hash } __`
141
+ }
142
+
56
143
export function webWorkerPlugin ( config : ResolvedConfig ) : Plugin {
57
144
const isBuild = config . command === 'build'
145
+ const isWorker = config . isWorker
58
146
59
147
return {
60
148
name : 'vite:worker' ,
61
149
150
+ buildStart ( ) {
151
+ workerCache . set ( config , {
152
+ assets : new Map ( ) ,
153
+ chunks : new Map ( ) ,
154
+ bundle : new Map ( ) ,
155
+ emitted : new Map ( )
156
+ } )
157
+ } ,
158
+
62
159
load ( id ) {
63
160
if ( isBuild ) {
64
161
const parsedQuery = parseRequest ( id )
@@ -87,8 +184,8 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
87
184
88
185
let url : string
89
186
if ( isBuild ) {
90
- const code = await bundleWorkerEntry ( this , config , id )
91
187
if ( query . inline != null ) {
188
+ const code = await bundleWorkerEntry ( this , config , id )
92
189
const { format } = config . worker
93
190
const workerOptions = format === 'es' ? '{type: "module"}' : '{}'
94
191
// inline as blob data url
@@ -103,17 +200,7 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
103
200
}
104
201
}`
105
202
} else {
106
- const basename = path . parse ( cleanUrl ( id ) ) . name
107
- const contentHash = getAssetHash ( code )
108
- const fileName = path . posix . join (
109
- config . build . assetsDir ,
110
- `${ basename } .${ contentHash } .js`
111
- )
112
- url = `__VITE_ASSET__${ this . emitFile ( {
113
- fileName,
114
- type : 'asset' ,
115
- source : code
116
- } ) } __`
203
+ url = await workerFileToUrl ( this , config , id )
117
204
}
118
205
} else {
119
206
url = await fileToUrl ( cleanUrl ( id ) , config , this )
@@ -129,6 +216,12 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
129
216
url
130
217
) } , ${ JSON . stringify ( workerOptions , null , 2 ) } )
131
218
}`
219
+ } ,
220
+
221
+ renderChunk ( code ) {
222
+ if ( isWorker && code . includes ( 'import.meta.url' ) ) {
223
+ return code . replace ( 'import.meta.url' , 'self.location.href' )
224
+ }
132
225
}
133
226
}
134
227
}
0 commit comments