Skip to content

Commit ad83bdf

Browse files
authored
feat: asset handling for support vite dev. (#90)
1 parent f7bfc16 commit ad83bdf

File tree

5 files changed

+105
-24
lines changed

5 files changed

+105
-24
lines changed

lib/compileTemplate.ts

+7-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
} from './types'
66

77
import assetUrlsModule, {
8-
AssetURLOptions
8+
AssetURLOptions,
9+
TransformAssetUrlsOptions
910
} from './templateCompilerModules/assetUrl'
1011
import srcsetModule from './templateCompilerModules/srcset'
1112

@@ -18,6 +19,7 @@ export interface TemplateCompileOptions {
1819
compiler: VueTemplateCompiler
1920
compilerOptions?: VueTemplateCompilerOptions
2021
transformAssetUrls?: AssetURLOptions | boolean
22+
transformAssetUrlsOptions?: TransformAssetUrlsOptions
2123
preprocessLang?: string
2224
preprocessOptions?: any
2325
transpileOptions?: any
@@ -103,6 +105,7 @@ function actuallyCompile(
103105
compilerOptions = {},
104106
transpileOptions = {},
105107
transformAssetUrls,
108+
transformAssetUrlsOptions,
106109
isProduction = process.env.NODE_ENV === 'production',
107110
isFunctional = false,
108111
optimizeSSR = false,
@@ -116,9 +119,9 @@ function actuallyCompile(
116119
if (transformAssetUrls) {
117120
const builtInModules = [
118121
transformAssetUrls === true
119-
? assetUrlsModule()
120-
: assetUrlsModule(transformAssetUrls),
121-
srcsetModule()
122+
? assetUrlsModule(undefined, transformAssetUrlsOptions)
123+
: assetUrlsModule(transformAssetUrls, transformAssetUrlsOptions),
124+
srcsetModule(transformAssetUrlsOptions)
122125
]
123126
finalCompilerOptions = Object.assign({}, compilerOptions, {
124127
modules: [...builtInModules, ...(compilerOptions.modules || [])],

lib/templateCompilerModules/assetUrl.ts

+30-7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ export interface AssetURLOptions {
66
[name: string]: string | string[]
77
}
88

9+
export interface TransformAssetUrlsOptions {
10+
/**
11+
* If base is provided, instead of transforming relative asset urls into
12+
* imports, they will be directly rewritten to absolute urls.
13+
*/
14+
base?: string
15+
}
16+
917
const defaultOptions: AssetURLOptions = {
1018
audio: 'src',
1119
video: ['src', 'poster'],
@@ -15,37 +23,52 @@ const defaultOptions: AssetURLOptions = {
1523
use: ['xlink:href', 'href']
1624
}
1725

18-
export default (userOptions?: AssetURLOptions) => {
26+
export default (
27+
userOptions?: AssetURLOptions,
28+
transformAssetUrlsOption?: TransformAssetUrlsOptions
29+
) => {
1930
const options = userOptions
2031
? Object.assign({}, defaultOptions, userOptions)
2132
: defaultOptions
2233

2334
return {
2435
postTransformNode: (node: ASTNode) => {
25-
transform(node, options)
36+
transform(node, options, transformAssetUrlsOption)
2637
}
2738
}
2839
}
2940

30-
function transform(node: ASTNode, options: AssetURLOptions) {
41+
function transform(
42+
node: ASTNode,
43+
options: AssetURLOptions,
44+
transformAssetUrlsOption?: TransformAssetUrlsOptions
45+
) {
3146
for (const tag in options) {
3247
if ((tag === '*' || node.tag === tag) && node.attrs) {
3348
const attributes = options[tag]
3449
if (typeof attributes === 'string') {
35-
node.attrs.some(attr => rewrite(attr, attributes))
50+
node.attrs.some(attr =>
51+
rewrite(attr, attributes, transformAssetUrlsOption)
52+
)
3653
} else if (Array.isArray(attributes)) {
37-
attributes.forEach(item => node.attrs.some(attr => rewrite(attr, item)))
54+
attributes.forEach(item =>
55+
node.attrs.some(attr => rewrite(attr, item, transformAssetUrlsOption))
56+
)
3857
}
3958
}
4059
}
4160
}
4261

43-
function rewrite(attr: Attr, name: string) {
62+
function rewrite(
63+
attr: Attr,
64+
name: string,
65+
transformAssetUrlsOption?: TransformAssetUrlsOptions
66+
) {
4467
if (attr.name === name) {
4568
const value = attr.value
4669
// only transform static URLs
4770
if (value.charAt(0) === '"' && value.charAt(value.length - 1) === '"') {
48-
attr.value = urlToRequire(value.slice(1, -1))
71+
attr.value = urlToRequire(value.slice(1, -1), transformAssetUrlsOption)
4972
return true
5073
}
5174
}

lib/templateCompilerModules/srcset.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
// vue compiler module for transforming `img:srcset` to a number of `require`s
22

33
import { urlToRequire, ASTNode } from './utils'
4+
import { TransformAssetUrlsOptions } from './assetUrl'
45

56
interface ImageCandidate {
67
require: string
78
descriptor: string
89
}
910

10-
export default () => ({
11+
export default (transformAssetUrlsOptions?: TransformAssetUrlsOptions) => ({
1112
postTransformNode: (node: ASTNode) => {
12-
transform(node)
13+
transform(node, transformAssetUrlsOptions)
1314
}
1415
})
1516

1617
// http://w3c.github.io/html/semantics-embedded-content.html#ref-for-image-candidate-string-5
1718
const escapedSpaceCharacters = /( |\\t|\\n|\\f|\\r)+/g
1819

19-
function transform(node: ASTNode) {
20+
function transform(
21+
node: ASTNode,
22+
transformAssetUrlsOptions?: TransformAssetUrlsOptions
23+
) {
2024
const tags = ['img', 'source']
2125

2226
if (tags.indexOf(node.tag) !== -1 && node.attrs) {
@@ -40,7 +44,10 @@ function transform(node: ASTNode) {
4044
.replace(escapedSpaceCharacters, ' ')
4145
.trim()
4246
.split(' ', 2)
43-
return { require: urlToRequire(url), descriptor }
47+
return {
48+
require: urlToRequire(url, transformAssetUrlsOptions),
49+
descriptor
50+
}
4451
})
4552

4653
// "require(url1)"

lib/templateCompilerModules/utils.ts

+29-9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import { TransformAssetUrlsOptions } from './assetUrl'
2+
import { UrlWithStringQuery, parse as uriParse } from 'url'
3+
import path from 'path'
4+
15
export interface Attr {
26
name: string
37
value: string
@@ -8,20 +12,36 @@ export interface ASTNode {
812
attrs: Attr[]
913
}
1014

11-
import { UrlWithStringQuery, parse as uriParse } from 'url'
12-
13-
export function urlToRequire(url: string): string {
15+
export function urlToRequire(
16+
url: string,
17+
transformAssetUrlsOption: TransformAssetUrlsOptions = {}
18+
): string {
1419
const returnValue = `"${url}"`
1520
// same logic as in transform-require.js
1621
const firstChar = url.charAt(0)
17-
if (firstChar === '.' || firstChar === '~' || firstChar === '@') {
18-
if (firstChar === '~') {
19-
const secondChar = url.charAt(1)
20-
url = url.slice(secondChar === '/' ? 2 : 1)
21-
}
22+
if (firstChar === '~') {
23+
const secondChar = url.charAt(1)
24+
url = url.slice(secondChar === '/' ? 2 : 1)
25+
}
2226

23-
const uriParts = parseUriParts(url)
27+
const uriParts = parseUriParts(url)
2428

29+
if (transformAssetUrlsOption.base) {
30+
// explicit base - directly rewrite the url into absolute url
31+
// does not apply to absolute urls or urls that start with `@`
32+
// since they are aliases
33+
if (firstChar === '.' || firstChar === '~') {
34+
// when packaged in the browser, path will be using the posix-
35+
// only version provided by rollup-plugin-node-builtins.
36+
return `"${(path.posix || path).join(
37+
transformAssetUrlsOption.base,
38+
uriParts.path + (uriParts.hash || '')
39+
)}"`
40+
}
41+
return returnValue
42+
}
43+
44+
if (firstChar === '.' || firstChar === '~' || firstChar === '@') {
2545
if (!uriParts.hash) {
2646
return `require("${url}")`
2747
} else {

test/compileTemplate.spec.ts

+28
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,31 @@ test('transform srcset', () => {
204204
)
205205
expect(vnode.children[18].data.attrs.srcset).toBe('test-url 2x, test-url 3x')
206206
})
207+
208+
test('transform assetUrls and srcset with base option', () => {
209+
const source = `
210+
<div>
211+
<img src="./logo.png">
212+
<img src="~fixtures/logo.png">
213+
<img src="~/fixtures/logo.png">
214+
<img src="./logo.png" srcset="./logo.png 2x, ./logo.png 3x">
215+
</div>
216+
`
217+
const result = compileTemplate({
218+
compiler: compiler as VueTemplateCompiler,
219+
filename: 'example.vue',
220+
source,
221+
transformAssetUrls: true,
222+
transformAssetUrlsOptions: { base: '/base/' }
223+
})
224+
225+
expect(result.errors.length).toBe(0)
226+
227+
const vnode = mockRender(result.code)
228+
expect(vnode.children[0].data.attrs.src).toBe('/base/logo.png')
229+
expect(vnode.children[2].data.attrs.src).toBe('/base/fixtures/logo.png')
230+
expect(vnode.children[4].data.attrs.src).toBe('/base/fixtures/logo.png')
231+
expect(vnode.children[6].data.attrs.srcset).toBe(
232+
'/base/logo.png 2x, /base/logo.png 3x'
233+
)
234+
})

0 commit comments

Comments
 (0)