@@ -2,7 +2,7 @@ import path from 'node:path'
2
2
import MagicString from 'magic-string'
3
3
import { stripLiteral } from 'strip-literal'
4
4
import { parseAst } from 'rollup/parseAst'
5
- import type { Plugin } from '../plugin '
5
+ import type { RolldownPlugin } from 'rolldown '
6
6
import type { ResolvedConfig } from '../config'
7
7
import { injectQuery , isParentDirectory , transformStableResult } from '../utils'
8
8
import { CLIENT_ENTRY } from '../constants'
@@ -25,7 +25,9 @@ import { hasViteIgnoreRE } from './importAnalysis'
25
25
* import.meta.glob('./dir/**.png', { eager: true, import: 'default' })[`./dir/${name}.png`]
26
26
* ```
27
27
*/
28
- export function assetImportMetaUrlPlugin ( config : ResolvedConfig ) : Plugin {
28
+ export function assetImportMetaUrlPlugin (
29
+ config : ResolvedConfig ,
30
+ ) : RolldownPlugin {
29
31
const { publicDir } = config
30
32
let assetResolver : ResolveIdFn
31
33
@@ -40,121 +42,128 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin {
40
42
41
43
return {
42
44
name : 'vite:asset-import-meta-url' ,
43
- async transform ( code , id ) {
44
- const { environment } = this
45
- if (
46
- environment . config . consumer === 'client' &&
47
- id !== preloadHelperId &&
48
- id !== CLIENT_ENTRY &&
49
- code . includes ( 'new URL' ) &&
50
- code . includes ( `import.meta.url` )
51
- ) {
52
- let s : MagicString | undefined
53
- const assetImportMetaUrlRE =
54
- / \b n e w \s + U R L \s * \( \s * ( ' [ ^ ' ] + ' | " [ ^ " ] + " | ` [ ^ ` ] + ` ) \s * , \s * i m p o r t \. m e t a \. u r l \s * (?: , \s * ) ? \) / dg
55
- const cleanString = stripLiteral ( code )
45
+ transform : {
46
+ filter : {
47
+ code : {
48
+ include : [ 'new URL' , 'import.meta.url' ] ,
49
+ } ,
50
+ } ,
51
+ async handler ( code , id ) {
52
+ const { environment } = this
53
+ if (
54
+ environment . config . consumer === 'client' &&
55
+ id !== preloadHelperId &&
56
+ id !== CLIENT_ENTRY &&
57
+ code . includes ( 'new URL' ) &&
58
+ code . includes ( `import.meta.url` )
59
+ ) {
60
+ let s : MagicString | undefined
61
+ const assetImportMetaUrlRE =
62
+ / \b n e w \s + U R L \s * \( \s * ( ' [ ^ ' ] + ' | " [ ^ " ] + " | ` [ ^ ` ] + ` ) \s * , \s * i m p o r t \. m e t a \. u r l \s * (?: , \s * ) ? \) / dg
63
+ const cleanString = stripLiteral ( code )
56
64
57
- let match : RegExpExecArray | null
58
- while ( ( match = assetImportMetaUrlRE . exec ( cleanString ) ) ) {
59
- const [ [ startIndex , endIndex ] , [ urlStart , urlEnd ] ] = match . indices !
60
- if ( hasViteIgnoreRE . test ( code . slice ( startIndex , urlStart ) ) ) continue
65
+ let match : RegExpExecArray | null
66
+ while ( ( match = assetImportMetaUrlRE . exec ( cleanString ) ) ) {
67
+ const [ [ startIndex , endIndex ] , [ urlStart , urlEnd ] ] = match . indices !
68
+ if ( hasViteIgnoreRE . test ( code . slice ( startIndex , urlStart ) ) ) continue
61
69
62
- const rawUrl = code . slice ( urlStart , urlEnd )
70
+ const rawUrl = code . slice ( urlStart , urlEnd )
63
71
64
- if ( ! s ) s = new MagicString ( code )
72
+ if ( ! s ) s = new MagicString ( code )
65
73
66
- // potential dynamic template string
67
- if ( rawUrl [ 0 ] === '`' && rawUrl . includes ( '${' ) ) {
68
- const queryDelimiterIndex = getQueryDelimiterIndex ( rawUrl )
69
- const hasQueryDelimiter = queryDelimiterIndex !== - 1
70
- const pureUrl = hasQueryDelimiter
71
- ? rawUrl . slice ( 0 , queryDelimiterIndex ) + '`'
72
- : rawUrl
73
- const queryString = hasQueryDelimiter
74
- ? rawUrl . slice ( queryDelimiterIndex , - 1 )
75
- : ''
76
- const ast = parseAst ( pureUrl )
77
- const templateLiteral = ( ast as any ) . body [ 0 ] . expression
78
- if ( templateLiteral . expressions . length ) {
79
- const pattern = buildGlobPattern ( templateLiteral )
80
- if ( pattern . startsWith ( '**' ) ) {
81
- // don't transform for patterns like this
82
- // because users won't intend to do that in most cases
83
- continue
84
- }
74
+ // potential dynamic template string
75
+ if ( rawUrl [ 0 ] === '`' && rawUrl . includes ( '${' ) ) {
76
+ const queryDelimiterIndex = getQueryDelimiterIndex ( rawUrl )
77
+ const hasQueryDelimiter = queryDelimiterIndex !== - 1
78
+ const pureUrl = hasQueryDelimiter
79
+ ? rawUrl . slice ( 0 , queryDelimiterIndex ) + '`'
80
+ : rawUrl
81
+ const queryString = hasQueryDelimiter
82
+ ? rawUrl . slice ( queryDelimiterIndex , - 1 )
83
+ : ''
84
+ const ast = parseAst ( pureUrl )
85
+ const templateLiteral = ( ast as any ) . body [ 0 ] . expression
86
+ if ( templateLiteral . expressions . length ) {
87
+ const pattern = buildGlobPattern ( templateLiteral )
88
+ if ( pattern . startsWith ( '**' ) ) {
89
+ // don't transform for patterns like this
90
+ // because users won't intend to do that in most cases
91
+ continue
92
+ }
85
93
86
- const globOptions = {
87
- eager : true ,
88
- import : 'default' ,
89
- // A hack to allow 'as' & 'query' exist at the same time
90
- query : injectQuery ( queryString , 'url' ) ,
94
+ const globOptions = {
95
+ eager : true ,
96
+ import : 'default' ,
97
+ // A hack to allow 'as' & 'query' exist at the same time
98
+ query : injectQuery ( queryString , 'url' ) ,
99
+ }
100
+ s . update (
101
+ startIndex ,
102
+ endIndex ,
103
+ `new URL((import.meta.glob(${ JSON . stringify (
104
+ pattern ,
105
+ ) } , ${ JSON . stringify (
106
+ globOptions ,
107
+ ) } ))[${ pureUrl } ], import.meta.url)`,
108
+ )
109
+ continue
91
110
}
92
- s . update (
93
- startIndex ,
94
- endIndex ,
95
- `new URL((import.meta.glob(${ JSON . stringify (
96
- pattern ,
97
- ) } , ${ JSON . stringify (
98
- globOptions ,
99
- ) } ))[${ pureUrl } ], import.meta.url)`,
100
- )
101
- continue
102
111
}
103
- }
104
112
105
- const url = rawUrl . slice ( 1 , - 1 )
106
- let file : string | undefined
107
- if ( url [ 0 ] === '.' ) {
108
- file = slash ( path . resolve ( path . dirname ( id ) , url ) )
109
- file = tryFsResolve ( file , fsResolveOptions ) ?? file
110
- } else {
111
- assetResolver ??= createBackCompatIdResolver ( config , {
112
- extensions : [ ] ,
113
- mainFields : [ ] ,
114
- tryIndex : false ,
115
- preferRelative : true ,
116
- } )
117
- file = await assetResolver ( environment , url , id )
118
- file ??=
119
- url [ 0 ] === '/'
120
- ? slash ( path . join ( publicDir , url ) )
121
- : slash ( path . resolve ( path . dirname ( id ) , url ) )
122
- }
113
+ const url = rawUrl . slice ( 1 , - 1 )
114
+ let file : string | undefined
115
+ if ( url [ 0 ] === '.' ) {
116
+ file = slash ( path . resolve ( path . dirname ( id ) , url ) )
117
+ file = tryFsResolve ( file , fsResolveOptions ) ?? file
118
+ } else {
119
+ assetResolver ??= createBackCompatIdResolver ( config , {
120
+ extensions : [ ] ,
121
+ mainFields : [ ] ,
122
+ tryIndex : false ,
123
+ preferRelative : true ,
124
+ } )
125
+ file = await assetResolver ( environment , url , id )
126
+ file ??=
127
+ url [ 0 ] === '/'
128
+ ? slash ( path . join ( publicDir , url ) )
129
+ : slash ( path . resolve ( path . dirname ( id ) , url ) )
130
+ }
123
131
124
- // Get final asset URL. If the file does not exist,
125
- // we fall back to the initial URL and let it resolve in runtime
126
- let builtUrl : string | undefined
127
- if ( file ) {
128
- try {
129
- if ( publicDir && isParentDirectory ( publicDir , file ) ) {
130
- const publicPath = '/' + path . posix . relative ( publicDir , file )
131
- builtUrl = await fileToUrl ( this , publicPath )
132
- } else {
133
- builtUrl = await fileToUrl ( this , file )
132
+ // Get final asset URL. If the file does not exist,
133
+ // we fall back to the initial URL and let it resolve in runtime
134
+ let builtUrl : string | undefined
135
+ if ( file ) {
136
+ try {
137
+ if ( publicDir && isParentDirectory ( publicDir , file ) ) {
138
+ const publicPath = '/' + path . posix . relative ( publicDir , file )
139
+ builtUrl = await fileToUrl ( this , publicPath )
140
+ } else {
141
+ builtUrl = await fileToUrl ( this , file )
142
+ }
143
+ } catch {
144
+ // do nothing, we'll log a warning after this
134
145
}
135
- } catch {
136
- // do nothing, we'll log a warning after this
137
146
}
138
- }
139
- if ( ! builtUrl ) {
140
- const rawExp = code . slice ( startIndex , endIndex )
141
- config . logger . warnOnce (
142
- `\n${ rawExp } doesn't exist at build time, it will remain unchanged to be resolved at runtime. ` +
143
- `If this is intended, you can use the /* @vite-ignore */ comment to suppress this warning.` ,
147
+ if ( ! builtUrl ) {
148
+ const rawExp = code . slice ( startIndex , endIndex )
149
+ config . logger . warnOnce (
150
+ `\n${ rawExp } doesn't exist at build time, it will remain unchanged to be resolved at runtime. ` +
151
+ `If this is intended, you can use the /* @vite-ignore */ comment to suppress this warning.` ,
152
+ )
153
+ builtUrl = url
154
+ }
155
+ s . update (
156
+ startIndex ,
157
+ endIndex ,
158
+ `new URL(${ JSON . stringify ( builtUrl ) } , import.meta.url)` ,
144
159
)
145
- builtUrl = url
146
160
}
147
- s . update (
148
- startIndex ,
149
- endIndex ,
150
- `new URL(${ JSON . stringify ( builtUrl ) } , import.meta.url)` ,
151
- )
152
- }
153
- if ( s ) {
154
- return transformStableResult ( s , id , config )
161
+ if ( s ) {
162
+ return transformStableResult ( s , id , config )
163
+ }
155
164
}
156
- }
157
- return null
165
+ return null
166
+ } ,
158
167
} ,
159
168
}
160
169
}
0 commit comments