2019-12-02 01:02:53 +08:00
|
|
|
import {
|
|
|
|
createSimpleExpression,
|
|
|
|
ExpressionNode,
|
|
|
|
NodeTransform,
|
|
|
|
NodeTypes,
|
|
|
|
SourceLocation,
|
|
|
|
TransformContext
|
|
|
|
} from '@vue/compiler-core'
|
2020-01-20 22:57:17 +08:00
|
|
|
import { isRelativeUrl, parseUrl } from './templateUtils'
|
2019-11-07 10:58:15 +08:00
|
|
|
|
2019-12-02 01:02:53 +08:00
|
|
|
export interface AssetURLOptions {
|
|
|
|
[name: string]: string[]
|
|
|
|
}
|
|
|
|
|
2019-12-11 01:22:23 +08:00
|
|
|
const defaultOptions: AssetURLOptions = {
|
2019-12-02 01:02:53 +08:00
|
|
|
video: ['src', 'poster'],
|
|
|
|
source: ['src'],
|
|
|
|
img: ['src'],
|
|
|
|
image: ['xlink:href', 'href'],
|
|
|
|
use: ['xlink:href', 'href']
|
|
|
|
}
|
|
|
|
|
2019-12-11 01:22:23 +08:00
|
|
|
export const createAssetUrlTransformWithOptions = (
|
|
|
|
options: AssetURLOptions
|
|
|
|
): NodeTransform => {
|
|
|
|
const mergedOptions = {
|
|
|
|
...defaultOptions,
|
|
|
|
...options
|
|
|
|
}
|
|
|
|
return (node, context) =>
|
|
|
|
(transformAssetUrl as Function)(node, context, mergedOptions)
|
|
|
|
}
|
|
|
|
|
|
|
|
export const transformAssetUrl: NodeTransform = (
|
|
|
|
node,
|
|
|
|
context,
|
|
|
|
options: AssetURLOptions = defaultOptions
|
|
|
|
) => {
|
2019-12-02 01:02:53 +08:00
|
|
|
if (node.type === NodeTypes.ELEMENT) {
|
2019-12-11 01:22:23 +08:00
|
|
|
for (const tag in options) {
|
2019-12-02 01:02:53 +08:00
|
|
|
if ((tag === '*' || node.tag === tag) && node.props.length) {
|
2019-12-11 01:22:23 +08:00
|
|
|
const attributes = options[tag]
|
2019-12-02 01:02:53 +08:00
|
|
|
attributes.forEach(item => {
|
2020-03-23 23:08:22 +08:00
|
|
|
node.props.forEach((attr, index) => {
|
2019-12-02 01:02:53 +08:00
|
|
|
if (attr.type !== NodeTypes.ATTRIBUTE) return
|
|
|
|
if (attr.name !== item) return
|
|
|
|
if (!attr.value) return
|
2020-01-20 22:57:17 +08:00
|
|
|
if (!isRelativeUrl(attr.value.content)) return
|
2019-12-02 01:02:53 +08:00
|
|
|
const url = parseUrl(attr.value.content)
|
|
|
|
const exp = getImportsExpressionExp(
|
|
|
|
url.path,
|
|
|
|
url.hash,
|
|
|
|
attr.loc,
|
|
|
|
context
|
|
|
|
)
|
|
|
|
node.props[index] = {
|
|
|
|
type: NodeTypes.DIRECTIVE,
|
|
|
|
name: 'bind',
|
|
|
|
arg: createSimpleExpression(item, true, attr.loc),
|
|
|
|
exp,
|
|
|
|
modifiers: [],
|
|
|
|
loc: attr.loc
|
|
|
|
}
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function getImportsExpressionExp(
|
2020-04-16 21:33:30 +08:00
|
|
|
path: string | null,
|
|
|
|
hash: string | null,
|
2019-12-02 01:02:53 +08:00
|
|
|
loc: SourceLocation,
|
|
|
|
context: TransformContext
|
|
|
|
): ExpressionNode {
|
|
|
|
if (path) {
|
|
|
|
const importsArray = Array.from(context.imports)
|
|
|
|
const existing = importsArray.find(i => i.path === path)
|
|
|
|
if (existing) {
|
|
|
|
return existing.exp as ExpressionNode
|
|
|
|
}
|
|
|
|
const name = `_imports_${importsArray.length}`
|
|
|
|
const exp = createSimpleExpression(name, false, loc, true)
|
|
|
|
context.imports.add({ exp, path })
|
|
|
|
if (hash && path) {
|
|
|
|
return context.hoist(
|
|
|
|
createSimpleExpression(`${name} + '${hash}'`, false, loc, true)
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
return exp
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return createSimpleExpression(`''`, false, loc, true)
|
|
|
|
}
|
2019-11-07 10:58:15 +08:00
|
|
|
}
|