Skip to content

Commit 452aa9d

Browse files
committed
wip: handle script analyzed bindings when prefixing identifiers
1 parent 903d9b2 commit 452aa9d

File tree

10 files changed

+92
-31
lines changed

10 files changed

+92
-31
lines changed

Diff for: packages/compiler-sfc/src/compileScript.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -1209,7 +1209,11 @@ export function compileScript(
12091209
allBindings[key] = true
12101210
}
12111211
}
1212-
const returned = `{ ${Object.keys(allBindings).join(', ')} }`
1212+
// __sfc marker indicates these bindings are compiled from <script setup>
1213+
// and should not be proxied on `this`
1214+
const returned = `{ ${__TEST__ ? `` : `__sfc: true,`}${Object.keys(
1215+
allBindings
1216+
).join(', ')} }`
12131217

12141218
s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`)
12151219

Diff for: packages/compiler-sfc/src/compileTemplate.ts

+20-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1-
import { VueTemplateCompiler, VueTemplateCompilerOptions } from './types'
1+
import {
2+
BindingMetadata,
3+
VueTemplateCompiler,
4+
VueTemplateCompilerOptions
5+
} from './types'
26
import assetUrlsModule, {
37
AssetURLOptions,
48
TransformAssetUrlsOptions
59
} from './templateCompilerModules/assetUrl'
610
import srcsetModule from './templateCompilerModules/srcset'
711
import consolidate from '@vue/consolidate'
812
import * as _compiler from 'web/entry-compiler'
9-
import { stripWith } from './stripWith'
13+
import { prefixIdentifiers } from './prefixIdentifiers'
1014
import { WarningMessage } from 'types/compiler'
1115

1216
export interface TemplateCompileOptions {
@@ -24,6 +28,7 @@ export interface TemplateCompileOptions {
2428
optimizeSSR?: boolean
2529
prettify?: boolean
2630
isTS?: boolean
31+
bindings?: BindingMetadata
2732
}
2833

2934
export interface TemplateCompileResult {
@@ -107,7 +112,8 @@ function actuallyCompile(
107112
isFunctional = false,
108113
optimizeSSR = false,
109114
prettify = true,
110-
isTS = false
115+
isTS = false,
116+
bindings
111117
} = options
112118

113119
const compile =
@@ -144,15 +150,23 @@ function actuallyCompile(
144150
// transpile code with vue-template-es2015-compiler, which is a forked
145151
// version of Buble that applies ES2015 transforms + stripping `with` usage
146152
let code =
147-
`var __render__ = ${stripWith(
153+
`var __render__ = ${prefixIdentifiers(
148154
render,
149155
`render`,
150156
isFunctional,
151157
isTS,
152-
transpileOptions
158+
transpileOptions,
159+
bindings
153160
)}\n` +
154161
`var __staticRenderFns__ = [${staticRenderFns.map(code =>
155-
stripWith(code, ``, isFunctional, isTS, transpileOptions)
162+
prefixIdentifiers(
163+
code,
164+
``,
165+
isFunctional,
166+
isTS,
167+
transpileOptions,
168+
bindings
169+
)
156170
)}]` +
157171
`\n`
158172

Diff for: packages/compiler-sfc/src/stripWith.ts renamed to packages/compiler-sfc/src/prefixIdentifiers.ts

+31-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import MagicString from 'magic-string'
22
import { parseExpression, ParserOptions, ParserPlugin } from '@babel/parser'
33
import { makeMap } from 'shared/util'
44
import { walkIdentifiers } from './babelUtils'
5+
import { BindingMetadata } from './types'
56

67
const doNotPrefix = makeMap(
78
'Infinity,undefined,NaN,isFinite,isNaN,' +
@@ -16,12 +17,13 @@ const doNotPrefix = makeMap(
1617
* The input is expected to be the render function code directly returned from
1718
* `compile()` calls, e.g. `with(this){return ...}`
1819
*/
19-
export function stripWith(
20+
export function prefixIdentifiers(
2021
source: string,
2122
fnName = '',
2223
isFunctional = false,
2324
isTS = false,
24-
babelOptions: ParserOptions = {}
25+
babelOptions: ParserOptions = {},
26+
bindings?: BindingMetadata
2527
) {
2628
source = `function ${fnName}(${isFunctional ? `_c,_vm` : ``}){${source}\n}`
2729

@@ -40,21 +42,45 @@ export function stripWith(
4042
walkIdentifiers(
4143
ast,
4244
ident => {
43-
if (doNotPrefix(ident.name)) {
45+
const { name } = ident
46+
if (doNotPrefix(name)) {
4447
return
4548
}
46-
s.prependRight(ident.start!, '_vm.')
49+
50+
if (!bindings) {
51+
s.prependRight(ident.start!, '_vm.')
52+
return
53+
}
54+
55+
s.overwrite(ident.start!, ident.end!, rewriteIdentifier(name, bindings))
4756
},
4857
node => {
4958
if (node.type === 'WithStatement') {
5059
s.remove(node.start!, node.body.start! + 1)
5160
s.remove(node.end! - 1, node.end!)
5261
if (!isFunctional) {
53-
s.prependRight(node.start!, `var _vm=this;var _c=_vm._self._c;`)
62+
s.prependRight(
63+
node.start!,
64+
`var _vm=this,_c=_vm._self._c${
65+
bindings ? `,_setup=_vm._setupProxy;` : `;`
66+
}`
67+
)
5468
}
5569
}
5670
}
5771
)
5872

5973
return s.toString()
6074
}
75+
76+
export function rewriteIdentifier(
77+
name: string,
78+
bindings: BindingMetadata
79+
): string {
80+
const type = bindings[name]
81+
if (type && type.startsWith('setup')) {
82+
return `_setup.${name}`
83+
} else {
84+
return `_vm.${name}`
85+
}
86+
}

Diff for: packages/compiler-sfc/test/stripWith.spec.ts renamed to packages/compiler-sfc/test/prefixIdentifiers.spec.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { stripWith } from '../src/stripWith'
1+
import { prefixIdentifiers } from '../src/prefixIdentifiers'
22
import { compile } from 'web/entry-compiler'
33
import { format } from 'prettier'
44

@@ -11,7 +11,7 @@ it('should work', () => {
1111
</foo>
1212
</div>`)
1313

14-
const result = format(stripWith(render, `render`), {
14+
const result = format(prefixIdentifiers(render, `render`), {
1515
semi: false,
1616
parser: 'babel'
1717
})
@@ -24,8 +24,8 @@ it('should work', () => {
2424

2525
expect(result).toMatchInlineSnapshot(`
2626
"function render() {
27-
var _vm = this
28-
var _c = _vm._self._c
27+
var _vm = this,
28+
_c = _vm._self._c
2929
return _c(
3030
\\"div\\",
3131
{ attrs: { id: \\"app\\" } },
@@ -39,8 +39,8 @@ it('should work', () => {
3939
_c(\\"foo\\", {
4040
inlineTemplate: {
4141
render: function () {
42-
var _vm = this
43-
var _c = _vm._self._c
42+
var _vm = this,
43+
_c = _vm._self._c
4444
return _c(\\"div\\", [_vm._v(_vm._s(_vm.bar))])
4545
},
4646
staticRenderFns: [],

Diff for: scripts/config.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,8 @@ function genConfig(name) {
278278
// built-in vars
279279
const vars = {
280280
__VERSION__: version,
281-
__DEV__: `process.env.NODE_ENV !== 'production'`
281+
__DEV__: `process.env.NODE_ENV !== 'production'`,
282+
__TEST__: false
282283
}
283284
// feature flags
284285
Object.keys(featureFlags).forEach(key => {

Diff for: src/global.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
declare const __DEV__: boolean
2+
declare const __TEST__: boolean
23

34
interface Window {
45
__VUE_DEVTOOLS_GLOBAL_HOOK__: DevtoolsHook

Diff for: src/types/compiler.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { BindingMetadata } from 'sfc/types'
2+
13
export type CompilerOptions = {
24
warn?: Function // allow customizing warning in different environments; e.g. node
35
modules?: Array<ModuleOptions> // platform specific modules; e.g. style; class
@@ -28,6 +30,8 @@ export type CompilerOptions = {
2830

2931
// for ssr optimization compiler
3032
scopeId?: string
33+
34+
bindingMetadata?: BindingMetadata
3135
}
3236

3337
export type WarningMessage = {

Diff for: src/types/component.ts

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ export declare class Component {
108108

109109
// @v3
110110
_setupState?: Record<string, any>
111+
_setupProxy?: Record<string, any>
111112
_setupContext?: SetupContext
112113
_attrsProxy?: Record<string, any>
113114
_slotsProxy?: Record<string, () => VNode[]>

Diff for: src/v3/apiSetup.ts

+20-11
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,20 @@ export function initSetup(vm: Component) {
4343
)
4444
}
4545
vm._setupState = setupResult
46-
for (const key in setupResult) {
47-
if (!isReserved(key)) {
48-
proxySetupProperty(vm, setupResult, key)
49-
} else if (__DEV__) {
50-
warn(`Avoid using variables that start with _ or $ in setup().`)
46+
// __sfc indicates compiled bindings from <script setup>
47+
if (!setupResult.__sfc) {
48+
for (const key in setupResult) {
49+
if (!isReserved(key)) {
50+
proxySetupProperty(vm, setupResult, key)
51+
} else if (__DEV__) {
52+
warn(`Avoid using variables that start with _ or $ in setup().`)
53+
}
54+
}
55+
} else {
56+
// exposed for compiled render fn
57+
const proxy = (vm._setupProxy = {})
58+
for (const key in setupResult) {
59+
proxySetupProperty(proxy, setupResult, key)
5160
}
5261
}
5362
} else if (__DEV__ && setupResult !== undefined) {
@@ -61,17 +70,17 @@ export function initSetup(vm: Component) {
6170
}
6271

6372
function proxySetupProperty(
64-
vm: Component,
73+
target: any,
6574
setupResult: Record<string, any>,
6675
key: string
6776
) {
68-
const raw = setupResult[key]
69-
const unwrap = isRef(raw)
70-
Object.defineProperty(vm, key, {
77+
let raw = setupResult[key]
78+
Object.defineProperty(target, key, {
7179
enumerable: true,
7280
configurable: true,
73-
get: unwrap ? () => raw.value : () => setupResult[key],
74-
set: unwrap ? v => (raw.value = v) : v => (setupResult[key] = v)
81+
get: () => (isRef(raw) ? raw.value : raw),
82+
set: newVal =>
83+
isRef(raw) ? (raw.value = newVal) : (raw = setupResult[key] = newVal)
7584
})
7685
}
7786

Diff for: vitest.config.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ export default defineConfig({
1717
}
1818
},
1919
define: {
20-
__DEV__: true
20+
__DEV__: true,
21+
__TEST__: true
2122
},
2223
test: {
2324
globals: true,

0 commit comments

Comments
 (0)