diff --git a/packages/compiler-core/src/transforms/transformExpression.ts b/packages/compiler-core/src/transforms/transformExpression.ts index 6cbb59627..0658ecc56 100644 --- a/packages/compiler-core/src/transforms/transformExpression.ts +++ b/packages/compiler-core/src/transforms/transformExpression.ts @@ -23,6 +23,7 @@ import { parseJS, walkJS } from '../utils' +import { globalsWhitelist } from '@vue/shared' export const transformExpression: NodeTransform = (node, context) => { if (node.type === NodeTypes.INTERPOLATION) { @@ -215,17 +216,6 @@ const isPropertyShorthand = (node: Node, parent: Node) => const isStaticPropertyKey = (node: Node, parent: Node) => isPropertyKey(node, parent) && (parent as Property).value !== node -const globals = new Set( - ( - 'Infinity,undefined,NaN,isFinite,isNaN,' + - 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + - 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + - 'require,' + // for webpack - 'arguments,' - ) // parsed as identifier but is a special keyword... - .split(',') -) - function shouldPrefix(identifier: Identifier, parent: Node) { if ( !( @@ -245,8 +235,12 @@ function shouldPrefix(identifier: Identifier, parent: Node) { ) && // not in an Array destructure pattern !(parent.type === 'ArrayPattern') && - // skip globals + commonly used shorthands - !globals.has(identifier.name) + // skip whitelisted globals + !globalsWhitelist.has(identifier.name) && + // special case for webpack compilation + identifier.name !== `require` && + // is a special keyword but parsed as identifier + identifier.name !== `arguments` ) { return true } diff --git a/packages/runtime-core/src/componentProxy.ts b/packages/runtime-core/src/componentProxy.ts index 05f784287..39ee392c1 100644 --- a/packages/runtime-core/src/componentProxy.ts +++ b/packages/runtime-core/src/componentProxy.ts @@ -1,7 +1,7 @@ import { ComponentInternalInstance, Data } from './component' import { nextTick } from './scheduler' import { instanceWatch } from './apiWatch' -import { EMPTY_OBJ, hasOwn } from '@vue/shared' +import { EMPTY_OBJ, hasOwn, globalsWhitelist } from '@vue/shared' import { ExtracComputedReturns } from './apiOptions' import { UnwrapRef } from '@vue/reactivity' @@ -78,15 +78,10 @@ export const PublicInstanceProxyHandlers = { } } }, - has(target: ComponentInternalInstance, key: string): boolean { - const { renderContext, data, props } = target - // TODO handle $xxx properties - return ( - key[0] !== '_' && - ((data !== EMPTY_OBJ && hasOwn(data, key)) || - hasOwn(renderContext, key) || - hasOwn(props, key)) - ) + // this trap is only called in browser-compiled render functions that use + // `with (this) {}` + has(_: any, key: string): boolean { + return key[0] !== '_' && !globalsWhitelist.has(key) }, set(target: ComponentInternalInstance, key: string, value: any): boolean { const { data, renderContext } = target diff --git a/packages/shared/src/globalsWhitelist.ts b/packages/shared/src/globalsWhitelist.ts new file mode 100644 index 000000000..97e258388 --- /dev/null +++ b/packages/shared/src/globalsWhitelist.ts @@ -0,0 +1,7 @@ +export const globalsWhitelist = new Set( + ( + 'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' + + 'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' + + 'Object,Boolean,String,RegExp,Map,Set,JSON,Intl' + ).split(',') +) diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 93781a8d2..11a72c1dc 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,4 +1,5 @@ export * from './patchFlags' +export { globalsWhitelist } from './globalsWhitelist' export const EMPTY_OBJ: { readonly [key: string]: any } = __DEV__ ? Object.freeze({})