diff --git a/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap index 40f635ff435..d2ec37c611b 100644 --- a/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap +++ b/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap @@ -51,6 +51,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 27, @@ -119,6 +120,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 28, @@ -187,6 +189,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 29, @@ -272,6 +275,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 35, @@ -357,6 +361,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 34, @@ -442,6 +447,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 36, @@ -527,6 +533,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 35, @@ -595,6 +602,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 27, @@ -663,6 +671,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 26, @@ -731,6 +740,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 28, @@ -799,6 +809,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 27, @@ -867,6 +878,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 39, @@ -959,6 +971,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 50, @@ -1027,6 +1040,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 32, @@ -1095,6 +1109,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 29, @@ -1163,6 +1178,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 28, @@ -1306,6 +1322,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 45, @@ -1380,6 +1397,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 39, @@ -1454,6 +1472,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 34, @@ -1522,6 +1541,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 12, @@ -1590,6 +1610,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 13, @@ -1664,6 +1685,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 25, @@ -1756,6 +1778,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 30, @@ -1824,6 +1847,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 13, @@ -1892,6 +1916,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 14, @@ -1960,6 +1985,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 15, @@ -2028,6 +2054,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 22, @@ -2096,6 +2123,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 16, @@ -2164,6 +2192,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 33, @@ -2232,6 +2261,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 29, @@ -2306,6 +2336,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 16, @@ -2380,6 +2411,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 15, @@ -2473,6 +2505,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 19, @@ -2566,6 +2599,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 20, @@ -2659,6 +2693,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 18, @@ -2768,6 +2803,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 23, @@ -2877,6 +2913,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 24, @@ -2986,6 +3023,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 25, @@ -3095,6 +3133,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 23, @@ -3204,6 +3243,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 24, @@ -3313,6 +3353,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 25, @@ -3422,6 +3463,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 24, @@ -3531,6 +3573,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 22, @@ -3599,6 +3642,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 37, @@ -3643,6 +3687,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 16, @@ -3711,6 +3756,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 25, @@ -3779,6 +3825,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 26, @@ -3847,6 +3894,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 41, @@ -3915,6 +3963,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 26, @@ -3983,6 +4032,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 25, @@ -4069,6 +4119,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 31, @@ -4137,6 +4188,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 27, @@ -4222,6 +4274,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 28, @@ -4331,6 +4384,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 39, @@ -4424,6 +4478,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 38, @@ -4517,6 +4572,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 37, @@ -4567,6 +4623,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 25, @@ -4635,6 +4692,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 26, @@ -4703,6 +4761,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 27, @@ -4771,6 +4830,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 26, @@ -4916,6 +4976,7 @@ class=\\"bar\\">", "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 30, @@ -5060,6 +5121,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 53, @@ -5128,6 +5190,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 20, @@ -5196,6 +5259,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 32, @@ -5264,6 +5328,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 40, @@ -5332,6 +5397,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 35, @@ -5400,6 +5466,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 31, @@ -5468,6 +5535,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 30, @@ -5536,6 +5604,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 29, @@ -5604,6 +5673,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 30, @@ -5713,6 +5783,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 41, @@ -5822,6 +5893,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 41, @@ -5931,6 +6003,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 41, @@ -6040,6 +6113,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 42, @@ -6149,6 +6223,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 42, @@ -6258,6 +6333,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 45, @@ -6367,6 +6443,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 45, @@ -6476,6 +6553,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 42, @@ -6569,6 +6647,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 35, @@ -6678,6 +6757,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 42, @@ -6746,6 +6826,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 29, @@ -6857,6 +6938,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 37, @@ -6925,6 +7007,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 31, @@ -6993,6 +7076,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 30, @@ -7061,6 +7145,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 25, @@ -7111,6 +7196,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 34, @@ -7161,6 +7247,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 28, @@ -7247,6 +7334,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 34, @@ -7315,6 +7403,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 28, @@ -7422,6 +7511,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 25, @@ -7496,6 +7586,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 16, @@ -7570,6 +7661,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 27, @@ -7614,6 +7706,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 3, @@ -7658,6 +7751,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 7, @@ -7720,6 +7814,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 5, @@ -7797,6 +7892,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 8, @@ -7987,6 +8083,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 37, @@ -8196,6 +8293,7 @@ Object { "directives": Array [], "helpers": Array [], "hoists": Array [], + "imports": Array [], "loc": Object { "end": Object { "column": 7, diff --git a/packages/compiler-core/__tests__/codegen.spec.ts b/packages/compiler-core/__tests__/codegen.spec.ts index c356dbac71f..2a116bb771f 100644 --- a/packages/compiler-core/__tests__/codegen.spec.ts +++ b/packages/compiler-core/__tests__/codegen.spec.ts @@ -34,6 +34,7 @@ function createRoot(options: Partial = {}): RootNode { helpers: [], components: [], directives: [], + imports: [], hoists: [], cached: 0, codegenNode: createSimpleExpression(`null`, false), diff --git a/packages/compiler-core/src/ast.ts b/packages/compiler-core/src/ast.ts index ebd7a605c83..7cbbd275323 100644 --- a/packages/compiler-core/src/ast.ts +++ b/packages/compiler-core/src/ast.ts @@ -11,6 +11,7 @@ import { FRAGMENT } from './runtimeHelpers' import { PropsExpression } from './transforms/transformElement' +import { ImportsOption } from './transform' // Vue template is a platform-agnostic superset of HTML (syntax only). // More namespaces like SVG and MathML are declared by platform specific @@ -94,6 +95,7 @@ export interface RootNode extends Node { components: string[] directives: string[] hoists: JSChildNode[] + imports: ImportsOption[] cached: number codegenNode: TemplateChildNode | JSChildNode | undefined } diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts index d903d023cb8..649b5f623fd 100644 --- a/packages/compiler-core/src/codegen.ts +++ b/packages/compiler-core/src/codegen.ts @@ -38,6 +38,7 @@ import { CREATE_COMMENT, CREATE_TEXT } from './runtimeHelpers' +import { ImportsOption } from './transform' type CodegenNode = TemplateChildNode | JSChildNode @@ -229,6 +230,10 @@ export function generate( if (hasHelpers) { push(`import { ${ast.helpers.map(helper).join(', ')} } from "vue"\n`) } + if (ast.imports.length) { + genImports(ast.imports, context) + newline() + } genHoists(ast.hoists, context) newline() push(`export default `) @@ -327,6 +332,18 @@ function genHoists(hoists: JSChildNode[], context: CodegenContext) { }) } +function genImports(importsOptions: ImportsOption[], context: CodegenContext) { + if (!importsOptions.length) { + return + } + importsOptions.forEach(imports => { + context.push(`import `) + genNode(imports.exp, context) + context.push(` from '${imports.path}'`) + context.newline() + }) +} + function isText(n: string | CodegenNode) { return ( isString(n) || diff --git a/packages/compiler-core/src/parse.ts b/packages/compiler-core/src/parse.ts index a794b3cfd81..63b5626c83c 100644 --- a/packages/compiler-core/src/parse.ts +++ b/packages/compiler-core/src/parse.ts @@ -106,6 +106,7 @@ export function parse(content: string, options: ParserOptions = {}): RootNode { components: [], directives: [], hoists: [], + imports: [], cached: 0, codegenNode: undefined, loc: getSelection(context, start) diff --git a/packages/compiler-core/src/transform.ts b/packages/compiler-core/src/transform.ts index 88125d321d9..fa70cc92253 100644 --- a/packages/compiler-core/src/transform.ts +++ b/packages/compiler-core/src/transform.ts @@ -74,12 +74,18 @@ export interface TransformOptions { onError?: (error: CompilerError) => void } +export interface ImportsOption { + exp: string | ExpressionNode + path: string +} + export interface TransformContext extends Required { root: RootNode helpers: Set components: Set directives: Set hoists: JSChildNode[] + imports: Set cached: number identifiers: { [name: string]: number | undefined } scopes: { @@ -119,6 +125,7 @@ function createTransformContext( components: new Set(), directives: new Set(), hoists: [], + imports: new Set(), cached: 0, identifiers: {}, scopes: { @@ -293,6 +300,7 @@ function finalizeRoot(root: RootNode, context: TransformContext) { root.helpers = [...context.helpers] root.components = [...context.components] root.directives = [...context.directives] + root.imports = [...context.imports] root.hoists = context.hoists root.cached = context.cached } diff --git a/packages/compiler-sfc/__tests__/__snapshots__/templateTransformAssetUrl.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/templateTransformAssetUrl.spec.ts.snap new file mode 100644 index 00000000000..4004ddbcf07 --- /dev/null +++ b/packages/compiler-sfc/__tests__/__snapshots__/templateTransformAssetUrl.spec.ts.snap @@ -0,0 +1,39 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`compiler sfc: transform asset url support uri fragment 1`] = ` +"import { createVNode, createBlock, openBlock } from \\"vue\\" +import _imports_0 from '@svg/file.svg' + + +const _hoisted_1 = _imports_0 + '#fragment' + +export default function render() { + const _ctx = this + return (openBlock(), createBlock(\\"use\\", { href: _hoisted_1 })) +}" +`; + +exports[`compiler sfc: transform asset url support uri is empty 1`] = ` +"import { createVNode, createBlock, openBlock } from \\"vue\\" + +export default function render() { + const _ctx = this + return (openBlock(), createBlock(\\"use\\", { href: '' })) +}" +`; + +exports[`compiler sfc: transform asset url transform assetUrls 1`] = ` +"import { createVNode, createBlock, Fragment, openBlock } from \\"vue\\" +import _imports_0 from './logo.png' +import _imports_1 from 'fixtures/logo.png' + + +export default function render() { + const _ctx = this + return (openBlock(), createBlock(Fragment, null, [ + createVNode(\\"img\\", { src: _imports_0 }), + createVNode(\\"img\\", { src: _imports_1 }), + createVNode(\\"img\\", { src: _imports_1 }) + ])) +}" +`; diff --git a/packages/compiler-sfc/__tests__/templateTransformAssetUrl.spec.ts b/packages/compiler-sfc/__tests__/templateTransformAssetUrl.spec.ts new file mode 100644 index 00000000000..a5e64058cd4 --- /dev/null +++ b/packages/compiler-sfc/__tests__/templateTransformAssetUrl.spec.ts @@ -0,0 +1,47 @@ +import { generate, parse, transform } from '@vue/compiler-core' +import { transformAssetUrl } from '../src/templateTransformAssetUrl' +import { transformElement } from '../../compiler-core/src/transforms/transformElement' +import { transformBind } from '../../compiler-core/src/transforms/vBind' + +function compileWithAssetUrls(template: string) { + const ast = parse(template) + transform(ast, { + nodeTransforms: [transformAssetUrl, transformElement], + directiveTransforms: { + bind: transformBind + } + }) + return generate(ast, { mode: 'module' }) +} + +describe('compiler sfc: transform asset url', () => { + test('transform assetUrls', () => { + const result = compileWithAssetUrls(` + + + + `) + + expect(result.code).toMatchSnapshot() + }) + + /** + * vuejs/component-compiler-utils#22 Support uri fragment in transformed require + */ + test('support uri fragment', () => { + const result = compileWithAssetUrls( + '' + ) + + expect(result.code).toMatchSnapshot() + }) + + /** + * vuejs/component-compiler-utils#22 Support uri fragment in transformed require + */ + test('support uri is empty', () => { + const result = compileWithAssetUrls('') + + expect(result.code).toMatchSnapshot() + }) +}) diff --git a/packages/compiler-sfc/src/templateTransformAssetUrl.ts b/packages/compiler-sfc/src/templateTransformAssetUrl.ts index 3025bfa4817..982c1981102 100644 --- a/packages/compiler-sfc/src/templateTransformAssetUrl.ts +++ b/packages/compiler-sfc/src/templateTransformAssetUrl.ts @@ -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) + } } diff --git a/packages/compiler-sfc/src/templateUtils.ts b/packages/compiler-sfc/src/templateUtils.ts index 1ebb28946de..7099b2841bf 100644 --- a/packages/compiler-sfc/src/templateUtils.ts +++ b/packages/compiler-sfc/src/templateUtils.ts @@ -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) } /**