Skip to content

Commit e521de1

Browse files
committed
Merge branch 'script-setup-2'
2 parents 3a6b120 + cea8b25 commit e521de1

25 files changed

+2265
-1109
lines changed

packages/compiler-core/src/codegen.ts

+27-8
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,13 @@ type CodegenNode = TemplateChildNode | JSChildNode | SSRCodegenNode
6060

6161
export interface CodegenResult {
6262
code: string
63+
preamble: string
6364
ast: RootNode
6465
map?: RawSourceMap
6566
}
6667

6768
export interface CodegenContext
68-
extends Omit<Required<CodegenOptions>, 'bindingMetadata'> {
69+
extends Omit<Required<CodegenOptions>, 'bindingMetadata' | 'inline'> {
6970
source: string
7071
code: string
7172
line: number
@@ -199,12 +200,18 @@ export function generate(
199200
const hasHelpers = ast.helpers.length > 0
200201
const useWithBlock = !prefixIdentifiers && mode !== 'module'
201202
const genScopeId = !__BROWSER__ && scopeId != null && mode === 'module'
203+
const isSetupInlined = !!options.inline
202204

203205
// preambles
206+
// in setup() inline mode, the preamble is generated in a sub context
207+
// and returned separately.
208+
const preambleContext = isSetupInlined
209+
? createCodegenContext(ast, options)
210+
: context
204211
if (!__BROWSER__ && mode === 'module') {
205-
genModulePreamble(ast, context, genScopeId)
212+
genModulePreamble(ast, preambleContext, genScopeId, isSetupInlined)
206213
} else {
207-
genFunctionPreamble(ast, context)
214+
genFunctionPreamble(ast, preambleContext)
208215
}
209216

210217
// binding optimizations
@@ -213,10 +220,17 @@ export function generate(
213220
: ``
214221
// enter render function
215222
if (!ssr) {
216-
if (genScopeId) {
217-
push(`const render = ${PURE_ANNOTATION}_withId(`)
223+
if (isSetupInlined) {
224+
if (genScopeId) {
225+
push(`${PURE_ANNOTATION}_withId(`)
226+
}
227+
push(`(_ctx, _cache${optimizeSources}) => {`)
228+
} else {
229+
if (genScopeId) {
230+
push(`const render = ${PURE_ANNOTATION}_withId(`)
231+
}
232+
push(`function render(_ctx, _cache${optimizeSources}) {`)
218233
}
219-
push(`function render(_ctx, _cache${optimizeSources}) {`)
220234
} else {
221235
if (genScopeId) {
222236
push(`const ssrRender = ${PURE_ANNOTATION}_withId(`)
@@ -290,6 +304,7 @@ export function generate(
290304
return {
291305
ast,
292306
code: context.code,
307+
preamble: isSetupInlined ? preambleContext.code : ``,
293308
// SourceMapGenerator does have toJSON() method but it's not in the types
294309
map: context.map ? (context.map as any).toJSON() : undefined
295310
}
@@ -356,7 +371,8 @@ function genFunctionPreamble(ast: RootNode, context: CodegenContext) {
356371
function genModulePreamble(
357372
ast: RootNode,
358373
context: CodegenContext,
359-
genScopeId: boolean
374+
genScopeId: boolean,
375+
inline?: boolean
360376
) {
361377
const {
362378
push,
@@ -423,7 +439,10 @@ function genModulePreamble(
423439

424440
genHoists(ast.hoists, context)
425441
newline()
426-
push(`export `)
442+
443+
if (!inline) {
444+
push(`export `)
445+
}
427446
}
428447

429448
function genAssets(

packages/compiler-core/src/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ export {
77
TransformOptions,
88
CodegenOptions,
99
HoistTransform,
10-
BindingMetadata
10+
BindingMetadata,
11+
BindingTypes
1112
} from './options'
1213
export { baseParse, TextModes } from './parse'
1314
export {

packages/compiler-core/src/options.ts

+39-19
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,47 @@ export type HoistTransform = (
6161
parent: ParentNode
6262
) => void
6363

64+
export const enum BindingTypes {
65+
DATA = 'data',
66+
PROPS = 'props',
67+
SETUP = 'setup',
68+
CONST = 'const',
69+
OPTIONS = 'options'
70+
}
71+
6472
export interface BindingMetadata {
65-
[key: string]: 'data' | 'props' | 'setup' | 'options'
73+
[key: string]: BindingTypes
74+
}
75+
76+
interface SharedTransformCodegenOptions {
77+
/**
78+
* Transform expressions like {{ foo }} to `_ctx.foo`.
79+
* If this option is false, the generated code will be wrapped in a
80+
* `with (this) { ... }` block.
81+
* - This is force-enabled in module mode, since modules are by default strict
82+
* and cannot use `with`
83+
* @default mode === 'module'
84+
*/
85+
prefixIdentifiers?: boolean
86+
/**
87+
* Generate SSR-optimized render functions instead.
88+
* The resulting function must be attached to the component via the
89+
* `ssrRender` option instead of `render`.
90+
*/
91+
ssr?: boolean
92+
/**
93+
* Optional binding metadata analyzed from script - used to optimize
94+
* binding access when `prefixIdentifiers` is enabled.
95+
*/
96+
bindingMetadata?: BindingMetadata
97+
/**
98+
* Compile the function for inlining inside setup().
99+
* This allows the function to directly access setup() local bindings.
100+
*/
101+
inline?: boolean
66102
}
67103

68-
export interface TransformOptions {
104+
export interface TransformOptions extends SharedTransformCodegenOptions {
69105
/**
70106
* An array of node transforms to be applied to every AST node.
71107
*/
@@ -128,26 +164,15 @@ export interface TransformOptions {
128164
* SFC scoped styles ID
129165
*/
130166
scopeId?: string | null
131-
/**
132-
* Generate SSR-optimized render functions instead.
133-
* The resulting function must be attached to the component via the
134-
* `ssrRender` option instead of `render`.
135-
*/
136-
ssr?: boolean
137167
/**
138168
* SFC `<style vars>` injection string
139169
* needed to render inline CSS variables on component root
140170
*/
141171
ssrCssVars?: string
142-
/**
143-
* Optional binding metadata analyzed from script - used to optimize
144-
* binding access when `prefixIdentifiers` is enabled.
145-
*/
146-
bindingMetadata?: BindingMetadata
147172
onError?: (error: CompilerError) => void
148173
}
149174

150-
export interface CodegenOptions {
175+
export interface CodegenOptions extends SharedTransformCodegenOptions {
151176
/**
152177
* - `module` mode will generate ES module import statements for helpers
153178
* and export the render function as the default export.
@@ -189,11 +214,6 @@ export interface CodegenOptions {
189214
* @default 'Vue'
190215
*/
191216
runtimeGlobalName?: string
192-
// we need to know this during codegen to generate proper preambles
193-
prefixIdentifiers?: boolean
194-
bindingMetadata?: BindingMetadata
195-
// generate ssr-specific code?
196-
ssr?: boolean
197217
}
198218

199219
export type CompilerOptions = ParserOptions & TransformOptions & CodegenOptions

packages/compiler-core/src/runtimeHelpers.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const PUSH_SCOPE_ID = Symbol(__DEV__ ? `pushScopeId` : ``)
2929
export const POP_SCOPE_ID = Symbol(__DEV__ ? `popScopeId` : ``)
3030
export const WITH_SCOPE_ID = Symbol(__DEV__ ? `withScopeId` : ``)
3131
export const WITH_CTX = Symbol(__DEV__ ? `withCtx` : ``)
32+
export const UNREF = Symbol(__DEV__ ? `unref` : ``)
3233

3334
// Name mapping for runtime helpers that need to be imported from 'vue' in
3435
// generated code. Make sure these are correctly exported in the runtime!
@@ -62,7 +63,8 @@ export const helperNameMap: any = {
6263
[PUSH_SCOPE_ID]: `pushScopeId`,
6364
[POP_SCOPE_ID]: `popScopeId`,
6465
[WITH_SCOPE_ID]: `withScopeId`,
65-
[WITH_CTX]: `withCtx`
66+
[WITH_CTX]: `withCtx`,
67+
[UNREF]: `unref`
6668
}
6769

6870
export function registerRuntimeHelpers(helpers: any) {

packages/compiler-core/src/transform.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
isArray,
2323
NOOP,
2424
PatchFlags,
25-
PatchFlagNames
25+
PatchFlagNames,
26+
EMPTY_OBJ
2627
} from '@vue/shared'
2728
import { defaultOnError } from './errors'
2829
import {
@@ -122,7 +123,8 @@ export function createTransformContext(
122123
scopeId = null,
123124
ssr = false,
124125
ssrCssVars = ``,
125-
bindingMetadata = {},
126+
bindingMetadata = EMPTY_OBJ,
127+
inline = false,
126128
onError = defaultOnError
127129
}: TransformOptions
128130
): TransformContext {
@@ -141,6 +143,7 @@ export function createTransformContext(
141143
ssr,
142144
ssrCssVars,
143145
bindingMetadata,
146+
inline,
144147
onError,
145148

146149
// state

packages/compiler-core/src/transforms/hoistStatic.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -207,11 +207,11 @@ export function getStaticType(
207207
case NodeTypes.TEXT_CALL:
208208
return getStaticType(node.content, resultCache)
209209
case NodeTypes.SIMPLE_EXPRESSION:
210-
return node.isConstant
211-
? node.isRuntimeConstant
212-
? StaticType.HAS_RUNTIME_CONSTANT
213-
: StaticType.FULL_STATIC
214-
: StaticType.NOT_STATIC
210+
return node.isRuntimeConstant
211+
? StaticType.HAS_RUNTIME_CONSTANT
212+
: node.isConstant
213+
? StaticType.FULL_STATIC
214+
: StaticType.NOT_STATIC
215215
case NodeTypes.COMPOUND_EXPRESSION:
216216
let returnType = StaticType.FULL_STATIC
217217
for (let i = 0; i < node.children.length; i++) {

packages/compiler-core/src/transforms/transformElement.ts

+33-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ import {
2626
isSymbol,
2727
isOn,
2828
isObject,
29-
isReservedProp
29+
isReservedProp,
30+
capitalize,
31+
camelize,
32+
EMPTY_OBJ
3033
} from '@vue/shared'
3134
import { createCompilerError, ErrorCodes } from '../errors'
3235
import {
@@ -37,7 +40,8 @@ import {
3740
TO_HANDLERS,
3841
TELEPORT,
3942
KEEP_ALIVE,
40-
SUSPENSE
43+
SUSPENSE,
44+
UNREF
4145
} from '../runtimeHelpers'
4246
import {
4347
getInnerRange,
@@ -50,6 +54,7 @@ import {
5054
} from '../utils'
5155
import { buildSlots } from './vSlot'
5256
import { getStaticType } from './hoistStatic'
57+
import { BindingTypes } from '../options'
5358

5459
// some directive transforms (e.g. v-model) may return a symbol for runtime
5560
// import, which should be used instead of a resolveDirective call.
@@ -246,8 +251,32 @@ export function resolveComponentType(
246251
}
247252

248253
// 3. user component (from setup bindings)
249-
if (context.bindingMetadata[tag] === 'setup') {
250-
return `$setup[${JSON.stringify(tag)}]`
254+
const bindings = context.bindingMetadata
255+
if (bindings !== EMPTY_OBJ) {
256+
const checkType = (type: BindingTypes) => {
257+
let resolvedTag = tag
258+
if (
259+
bindings[resolvedTag] === type ||
260+
bindings[(resolvedTag = camelize(tag))] === type ||
261+
bindings[(resolvedTag = capitalize(camelize(tag)))] === type
262+
) {
263+
return resolvedTag
264+
}
265+
}
266+
const tagFromSetup = checkType(BindingTypes.SETUP)
267+
if (tagFromSetup) {
268+
return context.inline
269+
? // setup scope bindings may be refs so they need to be unrefed
270+
`${context.helperString(UNREF)}(${tagFromSetup})`
271+
: `$setup[${JSON.stringify(tagFromSetup)}]`
272+
}
273+
const tagFromConst = checkType(BindingTypes.CONST)
274+
if (tagFromConst) {
275+
return context.inline
276+
? // in inline mode, const setup bindings (e.g. imports) can be used as-is
277+
tagFromConst
278+
: `$setup[${JSON.stringify(tagFromConst)}]`
279+
}
251280
}
252281

253282
// 4. user component (resolve)

0 commit comments

Comments
 (0)