wip(ssr): v-bind basic usage
This commit is contained in:
parent
7f38c1e0ff
commit
6a5ed49ea9
@ -0,0 +1,26 @@
|
|||||||
|
import {
|
||||||
|
baseParse as parse,
|
||||||
|
transform,
|
||||||
|
ElementNode,
|
||||||
|
CallExpression,
|
||||||
|
noopDirectiveTransform
|
||||||
|
} from '../../src'
|
||||||
|
import { transformElement } from '../../src/transforms/transformElement'
|
||||||
|
|
||||||
|
describe('compiler: noop directive transform', () => {
|
||||||
|
test('should add no props to DOM', () => {
|
||||||
|
const ast = parse(`<div v-noop/>`)
|
||||||
|
transform(ast, {
|
||||||
|
nodeTransforms: [transformElement],
|
||||||
|
directiveTransforms: {
|
||||||
|
noop: noopDirectiveTransform
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const node = ast.children[0] as ElementNode
|
||||||
|
const codegenArgs = (node.codegenNode as CallExpression).arguments
|
||||||
|
|
||||||
|
// As v-noop adds no properties the codegen should be identical to
|
||||||
|
// rendering a div with no props or reactive data (so just the tag as the arg)
|
||||||
|
expect(codegenArgs.length).toBe(1)
|
||||||
|
})
|
||||||
|
})
|
@ -405,8 +405,7 @@ describe('compiler: element transform', () => {
|
|||||||
foo(dir) {
|
foo(dir) {
|
||||||
_dir = dir
|
_dir = dir
|
||||||
return {
|
return {
|
||||||
props: [createObjectProperty(dir.arg!, dir.exp!)],
|
props: [createObjectProperty(dir.arg!, dir.exp!)]
|
||||||
needRuntime: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ export {
|
|||||||
export * from './ast'
|
export * from './ast'
|
||||||
export * from './utils'
|
export * from './utils'
|
||||||
export { registerRuntimeHelpers } from './runtimeHelpers'
|
export { registerRuntimeHelpers } from './runtimeHelpers'
|
||||||
|
export { noopDirectiveTransform } from './transforms/noopDirectiveTransform'
|
||||||
|
|
||||||
// expose transforms so higher-order compilers can import and extend them
|
// expose transforms so higher-order compilers can import and extend them
|
||||||
export { transformModel } from './transforms/vModel'
|
export { transformModel } from './transforms/vModel'
|
||||||
|
@ -28,7 +28,8 @@ export interface ParserOptions {
|
|||||||
|
|
||||||
export interface TransformOptions {
|
export interface TransformOptions {
|
||||||
nodeTransforms?: NodeTransform[]
|
nodeTransforms?: NodeTransform[]
|
||||||
directiveTransforms?: { [name: string]: DirectiveTransform | undefined }
|
directiveTransforms?: Record<string, DirectiveTransform | undefined>
|
||||||
|
ssrDirectiveTransforms?: Record<string, DirectiveTransform | undefined>
|
||||||
isBuiltInComponent?: (tag: string) => symbol | void
|
isBuiltInComponent?: (tag: string) => symbol | void
|
||||||
// Transform expressions like {{ foo }} to `_ctx.foo`.
|
// Transform expressions like {{ foo }} to `_ctx.foo`.
|
||||||
// If this option is false, the generated code will be wrapped in a
|
// If this option is false, the generated code will be wrapped in a
|
||||||
|
@ -61,7 +61,7 @@ export type DirectiveTransform = (
|
|||||||
|
|
||||||
export interface DirectiveTransformResult {
|
export interface DirectiveTransformResult {
|
||||||
props: Property[]
|
props: Property[]
|
||||||
needRuntime: boolean | symbol
|
needRuntime?: boolean | symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
// A structural directive transform is a technically a NodeTransform;
|
// A structural directive transform is a technically a NodeTransform;
|
||||||
@ -114,6 +114,7 @@ function createTransformContext(
|
|||||||
cacheHandlers = false,
|
cacheHandlers = false,
|
||||||
nodeTransforms = [],
|
nodeTransforms = [],
|
||||||
directiveTransforms = {},
|
directiveTransforms = {},
|
||||||
|
ssrDirectiveTransforms = {},
|
||||||
isBuiltInComponent = NOOP,
|
isBuiltInComponent = NOOP,
|
||||||
ssr = false,
|
ssr = false,
|
||||||
onError = defaultOnError
|
onError = defaultOnError
|
||||||
@ -126,6 +127,7 @@ function createTransformContext(
|
|||||||
cacheHandlers,
|
cacheHandlers,
|
||||||
nodeTransforms,
|
nodeTransforms,
|
||||||
directiveTransforms,
|
directiveTransforms,
|
||||||
|
ssrDirectiveTransforms,
|
||||||
isBuiltInComponent,
|
isBuiltInComponent,
|
||||||
ssr,
|
ssr,
|
||||||
onError,
|
onError,
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
import { DirectiveTransform } from '../transform'
|
||||||
|
|
||||||
|
export const noopDirectiveTransform: DirectiveTransform = () => ({ props: [] })
|
@ -30,7 +30,6 @@ export const transformBind: DirectiveTransform = (dir, node, context) => {
|
|||||||
return {
|
return {
|
||||||
props: [
|
props: [
|
||||||
createObjectProperty(arg!, exp || createSimpleExpression('', true, loc))
|
createObjectProperty(arg!, exp || createSimpleExpression('', true, loc))
|
||||||
],
|
]
|
||||||
needRuntime: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,5 +101,5 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createTransformProps(props: Property[] = []) {
|
function createTransformProps(props: Property[] = []) {
|
||||||
return { props, needRuntime: false }
|
return { props }
|
||||||
}
|
}
|
||||||
|
@ -99,8 +99,7 @@ export const transformOn: DirectiveTransform = (
|
|||||||
eventName,
|
eventName,
|
||||||
exp || createSimpleExpression(`() => {}`, false, loc)
|
exp || createSimpleExpression(`() => {}`, false, loc)
|
||||||
)
|
)
|
||||||
],
|
]
|
||||||
needRuntime: false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply extended compiler augmentor
|
// apply extended compiler augmentor
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
import {
|
|
||||||
baseParse as parse,
|
|
||||||
transform,
|
|
||||||
ElementNode,
|
|
||||||
CallExpression
|
|
||||||
} from '@vue/compiler-core'
|
|
||||||
import { transformCloak } from '../../src/transforms/vCloak'
|
|
||||||
import { transformElement } from '../../../compiler-core/src/transforms/transformElement'
|
|
||||||
|
|
||||||
function transformWithCloak(template: string) {
|
|
||||||
const ast = parse(template)
|
|
||||||
transform(ast, {
|
|
||||||
nodeTransforms: [transformElement],
|
|
||||||
directiveTransforms: {
|
|
||||||
cloak: transformCloak
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return ast.children[0] as ElementNode
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('compiler: v-cloak transform', () => {
|
|
||||||
test('should add no props to DOM', () => {
|
|
||||||
const node = transformWithCloak(`<div v-cloak/>`)
|
|
||||||
const codegenArgs = (node.codegenNode as CallExpression).arguments
|
|
||||||
|
|
||||||
// As v-cloak adds no properties the codegen should be identical to
|
|
||||||
// rendering a div with no props or reactive data (so just the tag as the arg)
|
|
||||||
expect(codegenArgs.length).toBe(1)
|
|
||||||
})
|
|
||||||
})
|
|
@ -28,7 +28,8 @@ export const enum DOMErrorCodes {
|
|||||||
X_V_MODEL_ON_INVALID_ELEMENT,
|
X_V_MODEL_ON_INVALID_ELEMENT,
|
||||||
X_V_MODEL_ARG_ON_ELEMENT,
|
X_V_MODEL_ARG_ON_ELEMENT,
|
||||||
X_V_MODEL_ON_FILE_INPUT_ELEMENT,
|
X_V_MODEL_ON_FILE_INPUT_ELEMENT,
|
||||||
X_V_SHOW_NO_EXPRESSION
|
X_V_SHOW_NO_EXPRESSION,
|
||||||
|
__EXTEND_POINT__
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DOMErrorMessages: { [code: number]: string } = {
|
export const DOMErrorMessages: { [code: number]: string } = {
|
||||||
|
@ -5,12 +5,12 @@ import {
|
|||||||
CodegenResult,
|
CodegenResult,
|
||||||
isBuiltInType,
|
isBuiltInType,
|
||||||
ParserOptions,
|
ParserOptions,
|
||||||
RootNode
|
RootNode,
|
||||||
|
noopDirectiveTransform
|
||||||
} from '@vue/compiler-core'
|
} from '@vue/compiler-core'
|
||||||
import { parserOptionsMinimal } from './parserOptionsMinimal'
|
import { parserOptionsMinimal } from './parserOptionsMinimal'
|
||||||
import { parserOptionsStandard } from './parserOptionsStandard'
|
import { parserOptionsStandard } from './parserOptionsStandard'
|
||||||
import { transformStyle } from './transforms/transformStyle'
|
import { transformStyle } from './transforms/transformStyle'
|
||||||
import { transformCloak } from './transforms/vCloak'
|
|
||||||
import { transformVHtml } from './transforms/vHtml'
|
import { transformVHtml } from './transforms/vHtml'
|
||||||
import { transformVText } from './transforms/vText'
|
import { transformVText } from './transforms/vText'
|
||||||
import { transformModel } from './transforms/vModel'
|
import { transformModel } from './transforms/vModel'
|
||||||
@ -31,7 +31,7 @@ export function compile(
|
|||||||
...options,
|
...options,
|
||||||
nodeTransforms: [transformStyle, ...(options.nodeTransforms || [])],
|
nodeTransforms: [transformStyle, ...(options.nodeTransforms || [])],
|
||||||
directiveTransforms: {
|
directiveTransforms: {
|
||||||
cloak: transformCloak,
|
cloak: noopDirectiveTransform,
|
||||||
html: transformVHtml,
|
html: transformVHtml,
|
||||||
text: transformVText,
|
text: transformVText,
|
||||||
model: transformModel, // override compiler-core
|
model: transformModel, // override compiler-core
|
||||||
@ -56,4 +56,5 @@ export function parse(template: string, options: ParserOptions = {}): RootNode {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { DOMErrorCodes } from './errors'
|
||||||
export * from '@vue/compiler-core'
|
export * from '@vue/compiler-core'
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
import { DirectiveTransform } from '@vue/compiler-core'
|
|
||||||
|
|
||||||
export const transformCloak: DirectiveTransform = () => {
|
|
||||||
return { props: [], needRuntime: false }
|
|
||||||
}
|
|
@ -24,7 +24,6 @@ export const transformVHtml: DirectiveTransform = (dir, node, context) => {
|
|||||||
createSimpleExpression(`innerHTML`, true, loc),
|
createSimpleExpression(`innerHTML`, true, loc),
|
||||||
exp || createSimpleExpression('', true)
|
exp || createSimpleExpression('', true)
|
||||||
)
|
)
|
||||||
],
|
]
|
||||||
needRuntime: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,8 +102,7 @@ export const transformOn: DirectiveTransform = (dir, node, context) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: [createObjectProperty(key, handlerExp)],
|
props: [createObjectProperty(key, handlerExp)]
|
||||||
needRuntime: false
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@ export const transformVText: DirectiveTransform = (dir, node, context) => {
|
|||||||
createSimpleExpression(`textContent`, true, loc),
|
createSimpleExpression(`textContent`, true, loc),
|
||||||
exp || createSimpleExpression('', true)
|
exp || createSimpleExpression('', true)
|
||||||
)
|
)
|
||||||
],
|
]
|
||||||
needRuntime: false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
packages/compiler-ssr/__tests__/ssrVBind.spec.ts
Normal file
13
packages/compiler-ssr/__tests__/ssrVBind.spec.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { compile } from '../src'
|
||||||
|
|
||||||
|
describe('ssr: v-bind', () => {
|
||||||
|
test('basic', () => {
|
||||||
|
expect(compile(`<div :id="id"/>`).code).toMatchInlineSnapshot(`
|
||||||
|
"const { _renderAttr } = require(\\"vue\\")
|
||||||
|
|
||||||
|
return function ssrRender(_ctx, _push, _parent) {
|
||||||
|
_push(\`<div\${_renderAttr(\\"id\\", _ctx.id)}></div>\`)
|
||||||
|
}"
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
})
|
25
packages/compiler-ssr/src/errors.ts
Normal file
25
packages/compiler-ssr/src/errors.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import {
|
||||||
|
SourceLocation,
|
||||||
|
CompilerError,
|
||||||
|
createCompilerError,
|
||||||
|
DOMErrorCodes
|
||||||
|
} from '@vue/compiler-dom'
|
||||||
|
|
||||||
|
export interface SSRCompilerError extends CompilerError {
|
||||||
|
code: SSRErrorCodes
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createSSRCompilerError(
|
||||||
|
code: SSRErrorCodes,
|
||||||
|
loc?: SourceLocation
|
||||||
|
): SSRCompilerError {
|
||||||
|
return createCompilerError(code, loc, SSRErrorMessages)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum SSRErrorCodes {
|
||||||
|
X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM = DOMErrorCodes.__EXTEND_POINT__
|
||||||
|
}
|
||||||
|
|
||||||
|
export const SSRErrorMessages: { [code: number]: string } = {
|
||||||
|
[SSRErrorCodes.X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM]: `Custom directive is missing corresponding SSR transform and will be ignored.`
|
||||||
|
}
|
@ -7,20 +7,22 @@ import {
|
|||||||
CompilerOptions,
|
CompilerOptions,
|
||||||
transformExpression,
|
transformExpression,
|
||||||
trackVForSlotScopes,
|
trackVForSlotScopes,
|
||||||
trackSlotScopes
|
trackSlotScopes,
|
||||||
|
noopDirectiveTransform
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import { ssrCodegenTransform } from './ssrCodegenTransform'
|
import { ssrCodegenTransform } from './ssrCodegenTransform'
|
||||||
import { ssrTransformIf } from './transforms/ssrVIf'
|
|
||||||
import { ssrTransformFor } from './transforms/ssrVFor'
|
|
||||||
import { ssrTransformElement } from './transforms/ssrTransformElement'
|
import { ssrTransformElement } from './transforms/ssrTransformElement'
|
||||||
import { ssrTransformComponent } from './transforms/ssrTransformComponent'
|
import { ssrTransformComponent } from './transforms/ssrTransformComponent'
|
||||||
import { ssrTransformSlotOutlet } from './transforms/ssrTransformSlotOutlet'
|
import { ssrTransformSlotOutlet } from './transforms/ssrTransformSlotOutlet'
|
||||||
|
import { ssrTransformIf } from './transforms/ssrVIf'
|
||||||
export interface SSRCompilerOptions extends CompilerOptions {}
|
import { ssrTransformFor } from './transforms/ssrVFor'
|
||||||
|
import { ssrVBind } from './transforms/ssrVBind'
|
||||||
|
import { ssrVModel } from './transforms/ssrVModel'
|
||||||
|
import { ssrVShow } from './transforms/ssrVShow'
|
||||||
|
|
||||||
export function compile(
|
export function compile(
|
||||||
template: string,
|
template: string,
|
||||||
options: SSRCompilerOptions = {}
|
options: CompilerOptions = {}
|
||||||
): CodegenResult {
|
): CodegenResult {
|
||||||
options = {
|
options = {
|
||||||
mode: 'cjs',
|
mode: 'cjs',
|
||||||
@ -50,9 +52,13 @@ export function compile(
|
|||||||
trackSlotScopes,
|
trackSlotScopes,
|
||||||
...(options.nodeTransforms || []) // user transforms
|
...(options.nodeTransforms || []) // user transforms
|
||||||
],
|
],
|
||||||
directiveTransforms: {
|
ssrDirectiveTransforms: {
|
||||||
// TODO server-side directive transforms
|
on: noopDirectiveTransform,
|
||||||
...(options.directiveTransforms || {}) // user transforms
|
cloak: noopDirectiveTransform,
|
||||||
|
bind: ssrVBind,
|
||||||
|
model: ssrVModel,
|
||||||
|
show: ssrVShow,
|
||||||
|
...(options.ssrDirectiveTransforms || {}) // user transforms
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -4,9 +4,12 @@ import {
|
|||||||
ElementTypes,
|
ElementTypes,
|
||||||
TemplateLiteral,
|
TemplateLiteral,
|
||||||
createTemplateLiteral,
|
createTemplateLiteral,
|
||||||
createInterpolation
|
createInterpolation,
|
||||||
|
createCallExpression
|
||||||
} from '@vue/compiler-dom'
|
} from '@vue/compiler-dom'
|
||||||
import { escapeHtml } from '@vue/shared'
|
import { escapeHtml } from '@vue/shared'
|
||||||
|
import { createSSRCompilerError, SSRErrorCodes } from '../errors'
|
||||||
|
import { SSR_RENDER_ATTR } from '../runtimeHelpers'
|
||||||
|
|
||||||
export const ssrTransformElement: NodeTransform = (node, context) => {
|
export const ssrTransformElement: NodeTransform = (node, context) => {
|
||||||
if (
|
if (
|
||||||
@ -19,10 +22,25 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
|
|||||||
const openTag: TemplateLiteral['elements'] = [`<${node.tag}`]
|
const openTag: TemplateLiteral['elements'] = [`<${node.tag}`]
|
||||||
let rawChildren
|
let rawChildren
|
||||||
|
|
||||||
|
// v-bind="obj" or v-bind:[key] can potentially overwrite other static
|
||||||
|
// attrs and can affect final rendering result, so when they are present
|
||||||
|
// we need to bail out to full `renderAttrs`
|
||||||
|
const hasDynamicVBind = node.props.some(
|
||||||
|
p =>
|
||||||
|
p.type === NodeTypes.DIRECTIVE &&
|
||||||
|
p.name === 'bind' &&
|
||||||
|
(!p.arg || // v-bind="obj"
|
||||||
|
p.arg.type !== NodeTypes.SIMPLE_EXPRESSION || // v-bind:[_ctx.foo]
|
||||||
|
!p.arg.isStatic) // v-bind:[foo]
|
||||||
|
)
|
||||||
|
|
||||||
|
if (hasDynamicVBind) {
|
||||||
|
}
|
||||||
|
|
||||||
for (let i = 0; i < node.props.length; i++) {
|
for (let i = 0; i < node.props.length; i++) {
|
||||||
const prop = node.props[i]
|
const prop = node.props[i]
|
||||||
if (prop.type === NodeTypes.DIRECTIVE) {
|
|
||||||
// special cases with children override
|
// special cases with children override
|
||||||
|
if (prop.type === NodeTypes.DIRECTIVE) {
|
||||||
if (prop.name === 'html' && prop.exp) {
|
if (prop.name === 'html' && prop.exp) {
|
||||||
node.children = []
|
node.children = []
|
||||||
rawChildren = prop.exp
|
rawChildren = prop.exp
|
||||||
@ -40,13 +58,28 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
|
|||||||
) {
|
) {
|
||||||
node.children = [createInterpolation(prop.exp, prop.loc)]
|
node.children = [createInterpolation(prop.exp, prop.loc)]
|
||||||
// TODO handle <textrea> with dynamic v-bind
|
// TODO handle <textrea> with dynamic v-bind
|
||||||
} else {
|
} else if (!hasDynamicVBind) {
|
||||||
const directiveTransform = context.directiveTransforms[prop.name]
|
// Directive transforms.
|
||||||
|
const directiveTransform = context.ssrDirectiveTransforms[prop.name]
|
||||||
if (directiveTransform) {
|
if (directiveTransform) {
|
||||||
// TODO directive transforms
|
const { props } = directiveTransform(prop, node, context)
|
||||||
|
for (let j = 0; j < props.length; j++) {
|
||||||
|
const { key, value } = props[i]
|
||||||
|
openTag.push(
|
||||||
|
createCallExpression(context.helper(SSR_RENDER_ATTR), [
|
||||||
|
key,
|
||||||
|
value
|
||||||
|
])
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// no corresponding ssr directive transform found.
|
// no corresponding ssr directive transform found.
|
||||||
// TODO emit error
|
context.onError(
|
||||||
|
createSSRCompilerError(
|
||||||
|
SSRErrorCodes.X_SSR_CUSTOM_DIRECTIVE_NO_TRANSFORM,
|
||||||
|
prop.loc
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -54,7 +87,7 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
|
|||||||
if (node.tag === 'textarea' && prop.name === 'value' && prop.value) {
|
if (node.tag === 'textarea' && prop.name === 'value' && prop.value) {
|
||||||
node.children = []
|
node.children = []
|
||||||
rawChildren = escapeHtml(prop.value.content)
|
rawChildren = escapeHtml(prop.value.content)
|
||||||
} else {
|
} else if (!hasDynamicVBind) {
|
||||||
// static prop
|
// static prop
|
||||||
openTag.push(
|
openTag.push(
|
||||||
` ${prop.name}` +
|
` ${prop.name}` +
|
||||||
|
@ -1 +1,18 @@
|
|||||||
// TODO
|
import { DirectiveTransform, createObjectProperty } from '@vue/compiler-dom'
|
||||||
|
|
||||||
|
export const ssrVBind: DirectiveTransform = (dir, node, context) => {
|
||||||
|
if (!dir.exp) {
|
||||||
|
// error
|
||||||
|
return { props: [] }
|
||||||
|
} else {
|
||||||
|
// TODO modifiers
|
||||||
|
return {
|
||||||
|
props: [
|
||||||
|
createObjectProperty(
|
||||||
|
dir.arg!, // v-bind="obj" is handled separately
|
||||||
|
dir.exp
|
||||||
|
)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
// TODO
|
|
@ -1 +1,7 @@
|
|||||||
// TODO
|
import { DirectiveTransform } from '@vue/compiler-dom'
|
||||||
|
|
||||||
|
export const ssrVModel: DirectiveTransform = (dir, node, context) => {
|
||||||
|
return {
|
||||||
|
props: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
// TODO
|
|
@ -1 +1,7 @@
|
|||||||
// TODO
|
import { DirectiveTransform } from '@vue/compiler-dom'
|
||||||
|
|
||||||
|
export const ssrVShow: DirectiveTransform = (dir, node, context) => {
|
||||||
|
return {
|
||||||
|
props: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user