1
+ import path from 'path'
1
2
import {
2
3
createSimpleExpression ,
3
4
ExpressionNode ,
@@ -12,54 +13,97 @@ export interface AssetURLOptions {
12
13
[ name : string ] : string [ ]
13
14
}
14
15
15
- const defaultOptions : AssetURLOptions = {
16
- video : [ 'src' , 'poster' ] ,
17
- source : [ 'src' ] ,
18
- img : [ 'src' ] ,
19
- image : [ 'xlink:href' , 'href' ] ,
20
- use : [ 'xlink:href' , 'href' ]
16
+ export interface NormlaizedAssetURLOptions {
17
+ base ?: string | null
18
+ tags ?: AssetURLOptions
19
+ }
20
+
21
+ const defaultAssetUrlOptions : Required < NormlaizedAssetURLOptions > = {
22
+ base : null ,
23
+ tags : {
24
+ video : [ 'src' , 'poster' ] ,
25
+ source : [ 'src' ] ,
26
+ img : [ 'src' ] ,
27
+ image : [ 'xlink:href' , 'href' ] ,
28
+ use : [ 'xlink:href' , 'href' ]
29
+ }
21
30
}
22
31
23
32
export const createAssetUrlTransformWithOptions = (
24
- options : AssetURLOptions
33
+ options : NormlaizedAssetURLOptions
25
34
) : NodeTransform => {
26
35
const mergedOptions = {
27
- ...defaultOptions ,
36
+ ...defaultAssetUrlOptions ,
28
37
...options
29
38
}
30
39
return ( node , context ) =>
31
40
( transformAssetUrl as Function ) ( node , context , mergedOptions )
32
41
}
33
42
43
+ /**
44
+ * A `@vue/compiler-core` plugin that transforms relative asset urls into
45
+ * either imports or absolute urls.
46
+ *
47
+ * ``` js
48
+ * // Before
49
+ * createVNode('img', { src: './logo.png' })
50
+ *
51
+ * // After
52
+ * import _imports_0 from './logo.png'
53
+ * createVNode('img', { src: _imports_0 })
54
+ * ```
55
+ */
34
56
export const transformAssetUrl : NodeTransform = (
35
57
node ,
36
58
context ,
37
- options : AssetURLOptions = defaultOptions
59
+ options : NormlaizedAssetURLOptions = defaultAssetUrlOptions
38
60
) => {
39
61
if ( node . type === NodeTypes . ELEMENT ) {
40
- for ( const tag in options ) {
62
+ const tags = options . tags || defaultAssetUrlOptions . tags
63
+ for ( const tag in tags ) {
41
64
if ( ( tag === '*' || node . tag === tag ) && node . props . length ) {
42
- const attributes = options [ tag ]
43
- attributes . forEach ( item => {
65
+ const attributes = tags [ tag ]
66
+ attributes . forEach ( name => {
44
67
node . props . forEach ( ( attr , index ) => {
45
- if ( attr . type !== NodeTypes . ATTRIBUTE ) return
46
- if ( attr . name !== item ) return
47
- if ( ! attr . value ) return
48
- if ( ! isRelativeUrl ( attr . value . content ) ) return
68
+ if (
69
+ attr . type !== NodeTypes . ATTRIBUTE ||
70
+ attr . name !== name ||
71
+ ! attr . value ||
72
+ ! isRelativeUrl ( attr . value . content )
73
+ ) {
74
+ return
75
+ }
49
76
const url = parseUrl ( attr . value . content )
50
- const exp = getImportsExpressionExp (
51
- url . path ,
52
- url . hash ,
53
- attr . loc ,
54
- context
55
- )
56
- node . props [ index ] = {
57
- type : NodeTypes . DIRECTIVE ,
58
- name : 'bind' ,
59
- arg : createSimpleExpression ( item , true , attr . loc ) ,
60
- exp,
61
- modifiers : [ ] ,
62
- loc : attr . loc
77
+ if ( options . base ) {
78
+ // explicit base - directly rewrite the url into absolute url
79
+ // does not apply to url that starts with `@` since they are
80
+ // aliases
81
+ if ( attr . value . content [ 0 ] !== '@' ) {
82
+ // when packaged in the browser, path will be using the posix-
83
+ // only version provided by rollup-plugin-node-builtins.
84
+ attr . value . content = ( path . posix || path ) . join (
85
+ options . base ,
86
+ url . path + ( url . hash || '' )
87
+ )
88
+ }
89
+ } else {
90
+ // otherwise, transform the url into an import.
91
+ // this assumes a bundler will resolve the import into the correct
92
+ // absolute url (e.g. webpack file-loader)
93
+ const exp = getImportsExpressionExp (
94
+ url . path ,
95
+ url . hash ,
96
+ attr . loc ,
97
+ context
98
+ )
99
+ node . props [ index ] = {
100
+ type : NodeTypes . DIRECTIVE ,
101
+ name : 'bind' ,
102
+ arg : createSimpleExpression ( name , true , attr . loc ) ,
103
+ exp,
104
+ modifiers : [ ] ,
105
+ loc : attr . loc
106
+ }
63
107
}
64
108
} )
65
109
} )
0 commit comments