feat(compiler-sfc): transform asset url (#500)

This commit is contained in:
likui
2019-12-02 01:02:53 +08:00
committed by Evan You
parent 22957436e8
commit 810b3a3e2a
10 changed files with 294 additions and 19 deletions

View File

@@ -1,5 +1,81 @@
import { NodeTransform } from '@vue/compiler-core'
import {
AttributeNode,
createSimpleExpression,
ExpressionNode,
NodeTransform,
NodeTypes,
SourceLocation,
TransformContext
} from '@vue/compiler-core'
import { parseUrl } from './templateUtils'
export const transformAssetUrl: NodeTransform = () => {
// TODO
export interface AssetURLOptions {
[name: string]: string[]
}
const assetURLOptions: AssetURLOptions = {
video: ['src', 'poster'],
source: ['src'],
img: ['src'],
image: ['xlink:href', 'href'],
use: ['xlink:href', 'href']
}
export const transformAssetUrl: NodeTransform = (node, context) => {
if (node.type === NodeTypes.ELEMENT) {
for (const tag in assetURLOptions) {
if ((tag === '*' || node.tag === tag) && node.props.length) {
const attributes = assetURLOptions[tag]
attributes.forEach(item => {
node.props.forEach((attr: AttributeNode, index) => {
if (attr.type !== NodeTypes.ATTRIBUTE) return
if (attr.name !== item) return
if (!attr.value) return
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(
path: string | undefined,
hash: string | undefined,
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)
}
}

View File

@@ -1,30 +1,16 @@
import { UrlWithStringQuery, parse as uriParse } from 'url'
// TODO use imports instead.
// We need an extra transform context API for injecting arbitrary import
// statements.
export function urlToRequire(url: string): string {
const returnValue = `"${url}"`
export function parseUrl(url: string): UrlWithStringQuery {
const firstChar = url.charAt(0)
if (firstChar === '.' || firstChar === '~' || firstChar === '@') {
if (firstChar === '~') {
const secondChar = url.charAt(1)
url = url.slice(secondChar === '/' ? 2 : 1)
}
const uriParts = parseUriParts(url)
if (!uriParts.hash) {
return `require("${url}")`
} else {
// support uri fragment case by excluding it from
// the require and instead appending it as string;
// assuming that the path part is sufficient according to
// the above caseing(t.i. no protocol-auth-host parts expected)
return `require("${uriParts.path}") + "${uriParts.hash}"`
}
}
return returnValue
return parseUriParts(url)
}
/**