wip: generate valid v-model and TS code in script setup inline mode
This commit is contained in:
parent
6e870f5b30
commit
c15bd6235e
@ -169,6 +169,10 @@ export interface TransformOptions extends SharedTransformCodegenOptions {
|
|||||||
* needed to render inline CSS variables on component root
|
* needed to render inline CSS variables on component root
|
||||||
*/
|
*/
|
||||||
ssrCssVars?: string
|
ssrCssVars?: string
|
||||||
|
/**
|
||||||
|
* Indicates that transforms should try to output valid TS code
|
||||||
|
*/
|
||||||
|
isTS?: boolean
|
||||||
onError?: (error: CompilerError) => void
|
onError?: (error: CompilerError) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ export const POP_SCOPE_ID = Symbol(__DEV__ ? `popScopeId` : ``)
|
|||||||
export const WITH_SCOPE_ID = Symbol(__DEV__ ? `withScopeId` : ``)
|
export const WITH_SCOPE_ID = Symbol(__DEV__ ? `withScopeId` : ``)
|
||||||
export const WITH_CTX = Symbol(__DEV__ ? `withCtx` : ``)
|
export const WITH_CTX = Symbol(__DEV__ ? `withCtx` : ``)
|
||||||
export const UNREF = Symbol(__DEV__ ? `unref` : ``)
|
export const UNREF = Symbol(__DEV__ ? `unref` : ``)
|
||||||
|
export const IS_REF = Symbol(__DEV__ ? `isRef` : ``)
|
||||||
|
|
||||||
// Name mapping for runtime helpers that need to be imported from 'vue' in
|
// Name mapping for runtime helpers that need to be imported from 'vue' in
|
||||||
// generated code. Make sure these are correctly exported in the runtime!
|
// generated code. Make sure these are correctly exported in the runtime!
|
||||||
@ -64,7 +65,8 @@ export const helperNameMap: any = {
|
|||||||
[POP_SCOPE_ID]: `popScopeId`,
|
[POP_SCOPE_ID]: `popScopeId`,
|
||||||
[WITH_SCOPE_ID]: `withScopeId`,
|
[WITH_SCOPE_ID]: `withScopeId`,
|
||||||
[WITH_CTX]: `withCtx`,
|
[WITH_CTX]: `withCtx`,
|
||||||
[UNREF]: `unref`
|
[UNREF]: `unref`,
|
||||||
|
[IS_REF]: `isRef`
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerRuntimeHelpers(helpers: any) {
|
export function registerRuntimeHelpers(helpers: any) {
|
||||||
|
@ -125,6 +125,7 @@ export function createTransformContext(
|
|||||||
ssrCssVars = ``,
|
ssrCssVars = ``,
|
||||||
bindingMetadata = EMPTY_OBJ,
|
bindingMetadata = EMPTY_OBJ,
|
||||||
inline = false,
|
inline = false,
|
||||||
|
isTS = false,
|
||||||
onError = defaultOnError
|
onError = defaultOnError
|
||||||
}: TransformOptions
|
}: TransformOptions
|
||||||
): TransformContext {
|
): TransformContext {
|
||||||
@ -144,6 +145,7 @@ export function createTransformContext(
|
|||||||
ssrCssVars,
|
ssrCssVars,
|
||||||
bindingMetadata,
|
bindingMetadata,
|
||||||
inline,
|
inline,
|
||||||
|
isTS,
|
||||||
onError,
|
onError,
|
||||||
|
|
||||||
// state
|
// state
|
||||||
|
@ -14,6 +14,7 @@ import {
|
|||||||
hasScopeRef,
|
hasScopeRef,
|
||||||
isStaticExp
|
isStaticExp
|
||||||
} from '../utils'
|
} from '../utils'
|
||||||
|
import { helperNameMap, IS_REF, UNREF } from '../runtimeHelpers'
|
||||||
|
|
||||||
export const transformModel: DirectiveTransform = (dir, node, context) => {
|
export const transformModel: DirectiveTransform = (dir, node, context) => {
|
||||||
const { exp, arg } = dir
|
const { exp, arg } = dir
|
||||||
@ -24,10 +25,16 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
|
|||||||
return createTransformProps()
|
return createTransformProps()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const rawExp = exp.loc.source
|
||||||
const expString =
|
const expString =
|
||||||
exp.type === NodeTypes.SIMPLE_EXPRESSION ? exp.content : exp.loc.source
|
exp.type === NodeTypes.SIMPLE_EXPRESSION ? exp.content : rawExp
|
||||||
|
|
||||||
if (!isMemberExpression(expString)) {
|
// im SFC <script setup> inline mode, the exp may have been transformed into
|
||||||
|
// _unref(exp)
|
||||||
|
const isUnrefExp =
|
||||||
|
!__BROWSER__ && expString.startsWith(`_${helperNameMap[UNREF]}`)
|
||||||
|
|
||||||
|
if (!isMemberExpression(expString) && !isUnrefExp) {
|
||||||
context.onError(
|
context.onError(
|
||||||
createCompilerError(ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION, exp.loc)
|
createCompilerError(ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION, exp.loc)
|
||||||
)
|
)
|
||||||
@ -53,14 +60,25 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
|
|||||||
: createCompoundExpression(['"onUpdate:" + ', arg])
|
: createCompoundExpression(['"onUpdate:" + ', arg])
|
||||||
: `onUpdate:modelValue`
|
: `onUpdate:modelValue`
|
||||||
|
|
||||||
|
const assigmentExp = isUnrefExp
|
||||||
|
? // v-model used on a potentially ref binding in <script setup> inline mode.
|
||||||
|
// not the most beautiful codegen here but it gets the job done.
|
||||||
|
createSimpleExpression(
|
||||||
|
`$event => { if (${context.helperString(IS_REF)}(${rawExp})) {` +
|
||||||
|
`${rawExp}.value = $event` +
|
||||||
|
` } else {${context.isTS ? `\n//@ts-ignore\n` : ``}` +
|
||||||
|
`${rawExp} = $event` +
|
||||||
|
` }}`,
|
||||||
|
false,
|
||||||
|
exp.loc
|
||||||
|
)
|
||||||
|
: createCompoundExpression([`$event => (`, exp, ` = $event)`])
|
||||||
|
|
||||||
const props = [
|
const props = [
|
||||||
// modelValue: foo
|
// modelValue: foo
|
||||||
createObjectProperty(propName, dir.exp!),
|
createObjectProperty(propName, dir.exp!),
|
||||||
// "onUpdate:modelValue": $event => (foo = $event)
|
// "onUpdate:modelValue": $event => (foo = $event)
|
||||||
createObjectProperty(
|
createObjectProperty(eventName, assigmentExp)
|
||||||
eventName,
|
|
||||||
createCompoundExpression([`$event => (`, exp, ` = $event)`])
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
|
|
||||||
// cache v-model handler if applicable (when it doesn't refer any scope vars)
|
// cache v-model handler if applicable (when it doesn't refer any scope vars)
|
||||||
|
@ -122,9 +122,13 @@ export const transformOn: DirectiveTransform = (
|
|||||||
if (isInlineStatement || (shouldCache && isMemberExp)) {
|
if (isInlineStatement || (shouldCache && isMemberExp)) {
|
||||||
// wrap inline statement in a function expression
|
// wrap inline statement in a function expression
|
||||||
exp = createCompoundExpression([
|
exp = createCompoundExpression([
|
||||||
`${isInlineStatement ? `$event` : `(...args)`} => ${
|
`${
|
||||||
hasMultipleStatements ? `{` : `(`
|
isInlineStatement
|
||||||
}`,
|
? `$event`
|
||||||
|
: `${
|
||||||
|
!__BROWSER__ && context.isTS ? `\n//@ts-ignore\n` : ``
|
||||||
|
}(...args)`
|
||||||
|
} => ${hasMultipleStatements ? `{` : `(`}`,
|
||||||
exp,
|
exp,
|
||||||
hasMultipleStatements ? `}` : `)`
|
hasMultipleStatements ? `}` : `)`
|
||||||
])
|
])
|
||||||
|
@ -814,11 +814,12 @@ export function compileScript(
|
|||||||
...options.templateOptions,
|
...options.templateOptions,
|
||||||
filename,
|
filename,
|
||||||
source: sfc.template.content,
|
source: sfc.template.content,
|
||||||
|
inMap: sfc.template.map,
|
||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
isTS,
|
||||||
bindingMetadata
|
bindingMetadata
|
||||||
}
|
}
|
||||||
// TODO source map
|
|
||||||
})
|
})
|
||||||
if (tips.length) {
|
if (tips.length) {
|
||||||
tips.forEach(warnOnce)
|
tips.forEach(warnOnce)
|
||||||
@ -827,6 +828,16 @@ export function compileScript(
|
|||||||
if (typeof err === 'string') {
|
if (typeof err === 'string') {
|
||||||
throw new Error(err)
|
throw new Error(err)
|
||||||
} else if (err) {
|
} else if (err) {
|
||||||
|
if (err.loc) {
|
||||||
|
err.message +=
|
||||||
|
`\n` +
|
||||||
|
generateCodeFrame(
|
||||||
|
source,
|
||||||
|
err.loc.start.offset,
|
||||||
|
err.loc.end.offset
|
||||||
|
) +
|
||||||
|
`\n`
|
||||||
|
}
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
if (preamble) {
|
if (preamble) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user