Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/compiler-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export {
type NodeTransform,
type StructuralDirectiveTransform,
type DirectiveTransform,
type ImportItem,
} from './transform'
export {
generate,
Expand Down
18 changes: 9 additions & 9 deletions packages/compiler-sfc/src/compileTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,10 @@ import {
type AssetURLOptions,
type AssetURLTagConfig,
createAssetUrlTransformWithOptions,
defaultAssetUrlOptions,
normalizeOptions,
transformAssetUrl,
} from './template/transformAssetUrl'
import {
createSrcsetTransformWithOptions,
transformSrcset,
} from './template/transformSrcset'
import { createSrcsetTransformWithOptions } from './template/transformSrcset'
import { generateCodeFrame, isObject } from '@vue/shared'
import * as CompilerDOM from '@vue/compiler-dom'
import * as CompilerVapor from '@vue/compiler-vapor'
Expand Down Expand Up @@ -185,14 +182,17 @@ function doCompileTemplate({
const warnings: CompilerError[] = []

let nodeTransforms: NodeTransform[] = []
if (isObject(transformAssetUrls)) {
const assetOptions = normalizeOptions(transformAssetUrls)
if (transformAssetUrls !== false) {
const assetOptions = isObject(transformAssetUrls)
? normalizeOptions(transformAssetUrls)
: defaultAssetUrlOptions

assetOptions.vapor = vapor

nodeTransforms = [
createAssetUrlTransformWithOptions(assetOptions),
createSrcsetTransformWithOptions(assetOptions),
]
} else if (transformAssetUrls !== false) {
nodeTransforms = [transformAssetUrl, transformSrcset]
}

if (ssr && !ssrCssVars) {
Expand Down
15 changes: 13 additions & 2 deletions packages/compiler-sfc/src/template/transformAssetUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export interface AssetURLOptions {
*/
includeAbsolute?: boolean
tags?: AssetURLTagConfig
vapor?: boolean
}

export const defaultAssetUrlOptions: Required<AssetURLOptions> = {
Expand All @@ -44,6 +45,7 @@ export const defaultAssetUrlOptions: Required<AssetURLOptions> = {
image: ['xlink:href', 'href'],
use: ['xlink:href', 'href'],
},
vapor: false,
}

export const normalizeOptions = (
Expand Down Expand Up @@ -134,7 +136,13 @@ export const transformAssetUrl: NodeTransform = (
// otherwise, transform the url into an import.
// this assumes a bundler will resolve the import into the correct
// absolute url (e.g. webpack file-loader)
const exp = getImportsExpressionExp(url.path, url.hash, attr.loc, context)
const exp = getImportsExpressionExp(
url.path,
url.hash,
attr.loc,
context,
options.vapor,
)
node.props[index] = {
type: NodeTypes.DIRECTIVE,
name: 'bind',
Expand All @@ -152,6 +160,7 @@ function getImportsExpressionExp(
hash: string | null,
loc: SourceLocation,
context: TransformContext,
vapor = false,
): ExpressionNode {
if (path) {
let name: string
Expand Down Expand Up @@ -211,6 +220,8 @@ function getImportsExpressionExp(
}
return context.hoist(finalExp)
} else {
return createSimpleExpression(`''`, false, loc, ConstantTypes.CAN_STRINGIFY)
return vapor
? createSimpleExpression(`''`, true, loc, ConstantTypes.CAN_STRINGIFY)
: createSimpleExpression(`''`, false, loc, ConstantTypes.CAN_STRINGIFY)
}
}
57 changes: 52 additions & 5 deletions packages/compiler-sfc/src/template/transformSrcset.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import path from 'path'
import {
type CompoundExpressionNode,
ConstantTypes,
type ExpressionNode,
type NodeTransform,
Expand Down Expand Up @@ -36,6 +37,24 @@ export const createSrcsetTransformWithOptions = (
(transformSrcset as Function)(node, context, options)
}

export function flattenCompoundExpression(
compoundExpression: CompoundExpressionNode,
): string {
return compoundExpression.children
.map(child => {
if (typeof child === 'string') {
return child
} else if (typeof child === 'symbol') {
return child.description
} else if (child.type === NodeTypes.COMPOUND_EXPRESSION) {
return flattenCompoundExpression(child)
} else {
return child.content
}
})
.join('')
}

export const transformSrcset: NodeTransform = (
node,
context,
Expand All @@ -47,7 +66,25 @@ export const transformSrcset: NodeTransform = (
if (attr.name === 'srcset' && attr.type === NodeTypes.ATTRIBUTE) {
if (!attr.value) return
const value = attr.value.content
if (!value) return
if (!value) {
// Handle empty srcset
if (options.vapor) {
node.props[index] = {
type: NodeTypes.DIRECTIVE,
name: 'bind',
arg: createSimpleExpression('srcset', true, attr.loc),
exp: createSimpleExpression(
`''`,
true,
attr.loc,
ConstantTypes.CAN_STRINGIFY,
),
modifiers: [],
loc: attr.loc,
}
}
return
}
const imageCandidates: ImageCandidate[] = value.split(',').map(s => {
// The attribute value arrives here with all whitespace, except
// normal spaces, represented by escape sequences
Expand Down Expand Up @@ -151,10 +188,20 @@ export const transformSrcset: NodeTransform = (
}
})

let exp: ExpressionNode = compoundExpression
if (context.hoistStatic) {
exp = context.hoist(compoundExpression)
exp.constType = ConstantTypes.CAN_STRINGIFY
let exp: ExpressionNode
if (options.vapor) {
exp = createSimpleExpression(
flattenCompoundExpression(compoundExpression),
false,
attr.loc,
ConstantTypes.CAN_STRINGIFY,
)
} else {
exp = compoundExpression
if (context.hoistStatic) {
exp = context.hoist(compoundExpression)
exp.constType = ConstantTypes.CAN_STRINGIFY
}
}

node.props[index] = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`compiler sfc: transform asset url > should allow for full base URLs, with paths 1`] = `
"import { template as _template } from 'vue';
const t0 = _template("<img src=\\"http://localhost:3000/src/logo.png\\">", true)

export function render(_ctx) {
const n0 = t0()
return n0
}"
`;

exports[`compiler sfc: transform asset url > should allow for full base URLs, without paths 1`] = `
"import { template as _template } from 'vue';
const t0 = _template("<img src=\\"http://localhost:3000/logo.png\\">", true)

export function render(_ctx) {
const n0 = t0()
return n0
}"
`;

exports[`compiler sfc: transform asset url > should allow for full base URLs, without port 1`] = `
"import { template as _template } from 'vue';
const t0 = _template("<img src=\\"http://localhost/logo.png\\">", true)

export function render(_ctx) {
const n0 = t0()
return n0
}"
`;

exports[`compiler sfc: transform asset url > should allow for full base URLs, without protocol 1`] = `
"import { template as _template } from 'vue';
const t0 = _template("<img src=\\"//localhost/logo.png\\">", true)

export function render(_ctx) {
const n0 = t0()
return n0
}"
`;

exports[`compiler sfc: transform asset url > support uri fragment 1`] = `
"import { template as _template } from 'vue';
import _imports_0 from '@svg/file.svg';
const t0 = _template("<use href=\\"" + _imports_0 + '#fragment' + "\\"></use>")

export function render(_ctx) {
const n0 = t0()
const n1 = t0()
return [n0, n1]
}"
`;

exports[`compiler sfc: transform asset url > support uri is empty 1`] = `
"import { template as _template } from 'vue';
const t0 = _template("<use href=\\"\\"></use>", true)

export function render(_ctx) {
const n0 = t0()
return n0
}"
`;

exports[`compiler sfc: transform asset url > transform assetUrls 1`] = `
"import { template as _template } from 'vue';
import _imports_0 from './logo.png';
import _imports_1 from 'fixtures/logo.png';
import _imports_2 from '/fixtures/logo.png';
const t0 = _template("<img src=\\"" + _imports_0 + "\\">")
const t1 = _template("<img src=\\"" + _imports_1 + "\\">")
const t2 = _template("<img src=\\"http://example.com/fixtures/logo.png\\">")
const t3 = _template("<img src=\\"//example.com/fixtures/logo.png\\">")
const t4 = _template("<img src=\\"" + _imports_2 + "\\">")
const t5 = _template("<img src=\\"data:image/png;base64,i\\">")

export function render(_ctx) {
const n0 = t0()
const n1 = t1()
const n2 = t1()
const n3 = t2()
const n4 = t3()
const n5 = t4()
const n6 = t5()
return [n0, n1, n2, n3, n4, n5, n6]
}"
`;

exports[`compiler sfc: transform asset url > transform with stringify 1`] = `
"import { template as _template } from 'vue';
import _imports_0 from './bar.png';
import _imports_1 from '/bar.png';
const t0 = _template("<div><img src=\\"" + _imports_0 + "\\"><img src=\\"" + _imports_1 + "\\"><img src=\\"https://foo.bar/baz.png\\"><img src=\\"//foo.bar/baz.png\\"><img src=\\"" + _imports_0 + "\\"></div>", true)

export function render(_ctx) {
const n0 = t0()
return n0
}"
`;

exports[`compiler sfc: transform asset url > with explicit base 1`] = `
"import { template as _template } from 'vue';
import _imports_0 from 'bar.png';
import _imports_1 from '@theme/bar.png';
const t0 = _template("<img src=\\"/foo/bar.png\\">")
const t1 = _template("<img src=\\"" + _imports_0 + "\\">")
const t2 = _template("<img src=\\"" + _imports_1 + "\\">")

export function render(_ctx) {
const n0 = t0()
const n1 = t1()
const n2 = t1()
const n3 = t2()
return [n0, n1, n2, n3]
}"
`;

exports[`compiler sfc: transform asset url > with includeAbsolute: true 1`] = `
"import { template as _template } from 'vue';
import _imports_0 from './bar.png';
import _imports_1 from '/bar.png';
const t0 = _template("<img src=\\"" + _imports_0 + "\\">")
const t1 = _template("<img src=\\"" + _imports_1 + "\\">")
const t2 = _template("<img src=\\"https://foo.bar/baz.png\\">")
const t3 = _template("<img src=\\"//foo.bar/baz.png\\">")

export function render(_ctx) {
const n0 = t0()
const n1 = t1()
const n2 = t2()
const n3 = t3()
return [n0, n1, n2, n3]
}"
`;
Loading