Merge remote-tracking branch 'upstream/main'

This commit is contained in:
三咲智子 Kevin Deng 2024-04-18 14:47:57 +08:00
commit 98b701c82c
No known key found for this signature in database
32 changed files with 4515 additions and 3991 deletions

View File

@ -1,4 +0,0 @@
node_modules
dist
temp
coverage

View File

@ -1,144 +0,0 @@
const { builtinModules } = require('node:module')
const DOMGlobals = ['window', 'document']
const NodeGlobals = ['module', 'require']
const banConstEnum = {
selector: 'TSEnumDeclaration[const=true]',
message:
'Please use non-const enums. This project automatically inlines enums.',
}
/**
* @type {import('eslint-define-config').ESLintConfig}
*/
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
},
plugins: ['jest', 'import', '@typescript-eslint'],
rules: {
'no-debugger': 'error',
'no-console': ['error', { allow: ['warn', 'error', 'info'] }],
// most of the codebase are expected to be env agnostic
'no-restricted-globals': ['error', ...DOMGlobals, ...NodeGlobals],
'no-restricted-syntax': [
'error',
banConstEnum,
{
selector: 'ObjectPattern > RestElement',
message:
'Our output target is ES2016, and object rest spread results in ' +
'verbose helpers and should be avoided.',
},
{
selector: 'ObjectExpression > SpreadElement',
message:
'esbuild transpiles object spread into very verbose inline helpers.\n' +
'Please use the `extend` helper from @vue/shared instead.',
},
{
selector: 'AwaitExpression',
message:
'Our output target is ES2016, so async/await syntax should be avoided.',
},
],
'sort-imports': ['error', { ignoreDeclarationSort: true }],
'import/no-nodejs-modules': [
'error',
{ allow: builtinModules.map(mod => `node:${mod}`) },
],
// This rule enforces the preference for using '@ts-expect-error' comments in TypeScript
// code to indicate intentional type errors, improving code clarity and maintainability.
'@typescript-eslint/prefer-ts-expect-error': 'error',
// Enforce the use of 'import type' for importing types
'@typescript-eslint/consistent-type-imports': [
'error',
{
fixStyle: 'inline-type-imports',
disallowTypeAnnotations: false,
},
],
// Enforce the use of top-level import type qualifier when an import only has specifiers with inline type qualifiers
'@typescript-eslint/no-import-type-side-effects': 'error',
},
overrides: [
// tests, no restrictions (runs in Node / jest with jsdom)
{
files: ['**/__tests__/**', 'packages/dts-test/**'],
rules: {
'no-console': 'off',
'no-restricted-globals': 'off',
'no-restricted-syntax': 'off',
'jest/no-disabled-tests': 'error',
'jest/no-focused-tests': 'error',
},
},
// shared, may be used in any env
{
files: ['packages/shared/**', '.eslintrc.cjs'],
rules: {
'no-restricted-globals': 'off',
},
},
// Packages targeting DOM
{
files: ['packages/{vue,vue-compat,runtime-dom}/**'],
rules: {
'no-restricted-globals': ['error', ...NodeGlobals],
},
},
// Packages targeting Node
{
files: ['packages/{compiler-sfc,compiler-ssr,server-renderer}/**'],
rules: {
'no-restricted-globals': ['error', ...DOMGlobals],
'no-restricted-syntax': ['error', banConstEnum],
},
},
// Private package, browser only + no syntax restrictions
{
files: [
'packages/template-explorer/**',
'packages/sfc-playground/**',
'playground/**',
],
rules: {
'no-restricted-globals': ['error', ...NodeGlobals],
'no-restricted-syntax': ['error', banConstEnum],
'no-console': 'off',
},
},
// JavaScript files
{
files: ['*.js', '*.cjs'],
rules: {
// We only do `no-unused-vars` checks for js files, TS files are checked by TypeScript itself.
'no-unused-vars': ['error', { vars: 'all', args: 'none' }],
},
},
// Node scripts
{
files: [
'scripts/**',
'./*.{js,ts}',
'packages/*/*.js',
'packages/vue/*/*.js',
],
rules: {
'no-restricted-globals': 'off',
'no-restricted-syntax': ['error', banConstEnum],
'no-console': 'off',
},
},
// Import nodejs modules in compiler-sfc
{
files: ['packages/compiler-sfc/src/**'],
rules: {
'import/no-nodejs-modules': ['error', { allow: builtinModules }],
},
},
],
}

View File

@ -34,7 +34,7 @@
{ {
groupName: 'lint', groupName: 'lint',
matchPackageNames: ['simple-git-hooks', 'lint-staged'], matchPackageNames: ['simple-git-hooks', 'lint-staged'],
matchPackagePrefixes: ['@typescript-eslint', 'eslint', 'prettier'], matchPackagePrefixes: ['typescript-eslint', 'eslint', 'prettier'],
}, },
], ],
ignoreDeps: [ ignoreDeps: [

View File

@ -1,3 +1,13 @@
## [3.4.23](https://github.com/vuejs/core/compare/v3.4.22...v3.4.23) (2024-04-16)
### Bug Fixes
* **runtime-core:** fix regression for $attrs tracking in slots ([6930e60](https://github.com/vuejs/core/commit/6930e60787e4905a50417190263ae7dd46cf5409)), closes [#10710](https://github.com/vuejs/core/issues/10710)
* **runtime-core:** use same internal object mechanism for slots ([6df53d8](https://github.com/vuejs/core/commit/6df53d85a207986128159d88565e6e7045db2add)), closes [#10709](https://github.com/vuejs/core/issues/10709)
## [3.4.22](https://github.com/vuejs/core/compare/v3.4.21...v3.4.22) (2024-04-15) ## [3.4.22](https://github.com/vuejs/core/compare/v3.4.21...v3.4.22) (2024-04-15)

View File

@ -5,3 +5,9 @@ To report a vulnerability, please email security@vuejs.org.
While the discovery of new vulnerabilities is rare, we also recommend always using the latest versions of Vue and its official companion libraries to ensure your application remains as secure as possible. While the discovery of new vulnerabilities is rare, we also recommend always using the latest versions of Vue and its official companion libraries to ensure your application remains as secure as possible.
Please note that we do not consider XSS via template expressions a valid attack vector, because it can only happen if the user intentionally uses untrusted content as template compilation source. This is similar to knowingly pasting untrusted scripts into a browser console. We explicitly warn users against using untrusted content as template compilation source in our documentation. Please note that we do not consider XSS via template expressions a valid attack vector, because it can only happen if the user intentionally uses untrusted content as template compilation source. This is similar to knowingly pasting untrusted scripts into a browser console. We explicitly warn users against using untrusted content as template compilation source in our documentation.
## Security Hall of Fame
We would like to thank the following security researchers for responsibly disclosing security issues to us.
- Jeet Pal - [GitHub](https://github.com/jeetpal2007) | [Email](jeetpal2007@gmail.com) | [LinkedIn](https://in.linkedin.com/in/jeet-pal-22601a290 )

172
eslint.config.js Normal file
View File

@ -0,0 +1,172 @@
import importX from 'eslint-plugin-import-x'
import tseslint from 'typescript-eslint'
import vitest from 'eslint-plugin-vitest'
import { builtinModules } from 'node:module'
const DOMGlobals = ['window', 'document']
const NodeGlobals = ['module', 'require']
const banConstEnum = {
selector: 'TSEnumDeclaration[const=true]',
message:
'Please use non-const enums. This project automatically inlines enums.',
}
export default tseslint.config(
{
files: ['**/*.js', '**/*.ts', '**/*.tsx'],
extends: [tseslint.configs.base],
plugins: {
'import-x': importX,
},
rules: {
'no-debugger': 'error',
'no-console': ['error', { allow: ['warn', 'error', 'info'] }],
// most of the codebase are expected to be env agnostic
'no-restricted-globals': ['error', ...DOMGlobals, ...NodeGlobals],
'no-restricted-syntax': [
'error',
banConstEnum,
{
selector: 'ObjectPattern > RestElement',
message:
'Our output target is ES2016, and object rest spread results in ' +
'verbose helpers and should be avoided.',
},
{
selector: 'ObjectExpression > SpreadElement',
message:
'esbuild transpiles object spread into very verbose inline helpers.\n' +
'Please use the `extend` helper from @vue/shared instead.',
},
{
selector: 'AwaitExpression',
message:
'Our output target is ES2016, so async/await syntax should be avoided.',
},
],
'sort-imports': ['error', { ignoreDeclarationSort: true }],
'import-x/no-nodejs-modules': [
'error',
{ allow: builtinModules.map(mod => `node:${mod}`) },
],
// This rule enforces the preference for using '@ts-expect-error' comments in TypeScript
// code to indicate intentional type errors, improving code clarity and maintainability.
'@typescript-eslint/prefer-ts-expect-error': 'error',
// Enforce the use of 'import type' for importing types
'@typescript-eslint/consistent-type-imports': [
'error',
{
fixStyle: 'inline-type-imports',
disallowTypeAnnotations: false,
},
],
// Enforce the use of top-level import type qualifier when an import only has specifiers with inline type qualifiers
'@typescript-eslint/no-import-type-side-effects': 'error',
},
},
// tests, no restrictions (runs in Node / Vitest with jsdom)
{
files: ['**/__tests__/**', 'packages/dts-test/**'],
plugins: { vitest },
languageOptions: {
globals: {
...vitest.environments.env.globals,
},
},
rules: {
'no-console': 'off',
'no-restricted-globals': 'off',
'no-restricted-syntax': 'off',
'vitest/no-disabled-tests': 'error',
'vitest/no-focused-tests': 'error',
},
},
// shared, may be used in any env
{
files: ['packages/shared/**', 'eslint.config.js'],
rules: {
'no-restricted-globals': 'off',
},
},
// Packages targeting DOM
{
files: ['packages/{vue,vue-compat,runtime-dom}/**'],
rules: {
'no-restricted-globals': ['error', ...NodeGlobals],
},
},
// Packages targeting Node
{
files: ['packages/{compiler-sfc,compiler-ssr,server-renderer}/**'],
rules: {
'no-restricted-globals': ['error', ...DOMGlobals],
'no-restricted-syntax': ['error', banConstEnum],
},
},
// Private package, browser only + no syntax restrictions
{
files: [
'packages/template-explorer/**',
'packages/sfc-playground/**',
'playground/**',
],
rules: {
'no-restricted-globals': ['error', ...NodeGlobals],
'no-restricted-syntax': ['error', banConstEnum],
'no-console': 'off',
},
},
// JavaScript files
{
files: ['*.js'],
rules: {
// We only do `no-unused-vars` checks for js files, TS files are checked by TypeScript itself.
'no-unused-vars': ['error', { vars: 'all', args: 'none' }],
},
},
// Node scripts
{
files: [
'eslint.config.js',
'rollup.config.js',
'scripts/**',
'./*.{js,ts}',
'packages/*/*.js',
'packages/vue/*/*.js',
],
rules: {
'no-restricted-globals': 'off',
'no-restricted-syntax': ['error', banConstEnum],
'no-console': 'off',
},
},
// Import nodejs modules in compiler-sfc
{
files: ['packages/compiler-sfc/src/**'],
rules: {
'import-x/no-nodejs-modules': ['error', { allow: builtinModules }],
},
},
{
ignores: [
'**/dist/',
'**/temp/',
'**/coverage/',
'.idea/',
'explorations/',
'dts-build/packages',
],
},
)

View File

@ -1,7 +1,7 @@
{ {
"private": true, "private": true,
"version": "3.0.0-vapor", "version": "3.0.0-vapor",
"packageManager": "pnpm@8.15.4", "packageManager": "pnpm@9.0.1",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "node scripts/dev.js vue vue-vapor", "dev": "node scripts/dev.js vue vue-vapor",
@ -13,7 +13,7 @@
"size-esm-runtime": "node scripts/build.js vue vue-vapor -f esm-bundler-runtime", "size-esm-runtime": "node scripts/build.js vue vue-vapor -f esm-bundler-runtime",
"size-esm": "node scripts/build.js runtime-dom runtime-vapor runtime-core reactivity shared -f esm-bundler", "size-esm": "node scripts/build.js runtime-dom runtime-vapor runtime-core reactivity shared -f esm-bundler",
"check": "tsc --incremental --noEmit", "check": "tsc --incremental --noEmit",
"lint": "eslint --cache --ext .js,.ts,.tsx . --ignore-path .gitignore", "lint": "eslint --cache .",
"format": "prettier --write --cache .", "format": "prettier --write --cache .",
"format-check": "prettier --check --cache .", "format-check": "prettier --check --cache .",
"test": "vitest", "test": "vitest",
@ -72,8 +72,6 @@
"@types/minimist": "^1.2.5", "@types/minimist": "^1.2.5",
"@types/node": "^20.12.5", "@types/node": "^20.12.5",
"@types/semver": "^7.5.8", "@types/semver": "^7.5.8",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@typescript-eslint/parser": "^7.4.0",
"@vitest/coverage-istanbul": "^1.4.0", "@vitest/coverage-istanbul": "^1.4.0",
"@vitest/ui": "^1.4.0", "@vitest/ui": "^1.4.0",
"@vue/consolidate": "1.0.0", "@vue/consolidate": "1.0.0",
@ -81,10 +79,9 @@
"enquirer": "^2.4.1", "enquirer": "^2.4.1",
"esbuild": "^0.20.2", "esbuild": "^0.20.2",
"esbuild-plugin-polyfill-node": "^0.3.0", "esbuild-plugin-polyfill-node": "^0.3.0",
"eslint": "^8.57.0", "eslint": "^9.0.0",
"eslint-define-config": "^2.1.0", "eslint-plugin-import-x": "^0.5.0",
"eslint-plugin-import": "npm:eslint-plugin-i@^2.29.1", "eslint-plugin-vitest": "^0.5.3",
"eslint-plugin-jest": "^27.9.0",
"estree-walker": "^2.0.2", "estree-walker": "^2.0.2",
"execa": "^8.0.1", "execa": "^8.0.1",
"jsdom": "^24.0.0", "jsdom": "^24.0.0",
@ -113,7 +110,19 @@
"tslib": "^2.6.2", "tslib": "^2.6.2",
"tsx": "^4.7.2", "tsx": "^4.7.2",
"typescript": "~5.4.5", "typescript": "~5.4.5",
"typescript-eslint": "^7.6.0",
"vite": "^5.2.7", "vite": "^5.2.7",
"vitest": "^1.4.0" "vitest": "^1.4.0"
},
"pnpm": {
"peerDependencyRules": {
"allowedVersions": {
"typescript-eslint>eslint": "^9.0.0",
"@typescript-eslint/eslint-plugin>eslint": "^9.0.0",
"@typescript-eslint/parser>eslint": "^9.0.0",
"@typescript-eslint/type-utils>eslint": "^9.0.0",
"@typescript-eslint/utils>eslint": "^9.0.0"
}
}
} }
} }

View File

@ -16,8 +16,6 @@ import {
import { baseParse } from '../src/parser' import { baseParse } from '../src/parser'
import type { Program } from '@babel/types' import type { Program } from '@babel/types'
/* eslint jest/no-disabled-tests: "off" */
describe('compiler: parse', () => { describe('compiler: parse', () => {
describe('Text', () => { describe('Text', () => {
test('simple text', () => { test('simple text', () => {

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/compiler-core", "name": "@vue/compiler-core",
"version": "3.4.22", "version": "3.4.23",
"description": "@vue/compiler-core", "description": "@vue/compiler-core",
"main": "index.js", "main": "index.js",
"module": "dist/compiler-core.esm-bundler.js", "module": "dist/compiler-core.esm-bundler.js",

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/compiler-dom", "name": "@vue/compiler-dom",
"version": "3.4.22", "version": "3.4.23",
"description": "@vue/compiler-dom", "description": "@vue/compiler-dom",
"main": "index.js", "main": "index.js",
"module": "dist/compiler-dom.esm-bundler.js", "module": "dist/compiler-dom.esm-bundler.js",

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/compiler-sfc", "name": "@vue/compiler-sfc",
"version": "3.4.22", "version": "3.4.23",
"description": "@vue/compiler-sfc", "description": "@vue/compiler-sfc",
"main": "dist/compiler-sfc.cjs.js", "main": "dist/compiler-sfc.cjs.js",
"module": "dist/compiler-sfc.esm-browser.js", "module": "dist/compiler-sfc.esm-browser.js",

View File

@ -25,7 +25,7 @@ describe('ssr: element', () => {
test('v-html', () => { test('v-html', () => {
expect(getCompiledString(`<div v-html="foo"/>`)).toMatchInlineSnapshot(` expect(getCompiledString(`<div v-html="foo"/>`)).toMatchInlineSnapshot(`
"\`<div>\${ "\`<div>\${
_ctx.foo (_ctx.foo) ?? ''
}</div>\`" }</div>\`"
`) `)
}) })

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/compiler-ssr", "name": "@vue/compiler-ssr",
"version": "3.4.22", "version": "3.4.23",
"description": "@vue/compiler-ssr", "description": "@vue/compiler-ssr",
"main": "dist/compiler-ssr.cjs.js", "main": "dist/compiler-ssr.cjs.js",
"types": "dist/compiler-ssr.d.ts", "types": "dist/compiler-ssr.d.ts",

View File

@ -22,6 +22,7 @@ import {
createAssignmentExpression, createAssignmentExpression,
createCallExpression, createCallExpression,
createCompilerError, createCompilerError,
createCompoundExpression,
createConditionalExpression, createConditionalExpression,
createInterpolation, createInterpolation,
createSequenceExpression, createSequenceExpression,
@ -188,7 +189,10 @@ export const ssrTransformElement: NodeTransform = (node, context) => {
// special cases with children override // special cases with children override
if (prop.type === NodeTypes.DIRECTIVE) { if (prop.type === NodeTypes.DIRECTIVE) {
if (prop.name === 'html' && prop.exp) { if (prop.name === 'html' && prop.exp) {
rawChildrenMap.set(node, prop.exp) rawChildrenMap.set(
node,
createCompoundExpression([`(`, prop.exp, `) ?? ''`]),
)
} else if (prop.name === 'text' && prop.exp) { } else if (prop.name === 'text' && prop.exp) {
node.children = [createInterpolation(prop.exp, prop.loc)] node.children = [createInterpolation(prop.exp, prop.loc)]
} else if (prop.name === 'slot') { } else if (prop.name === 'slot') {

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/reactivity", "name": "@vue/reactivity",
"version": "3.4.22", "version": "3.4.23",
"description": "@vue/reactivity", "description": "@vue/reactivity",
"main": "index.js", "main": "index.js",
"module": "dist/reactivity.esm-bundler.js", "module": "dist/reactivity.esm-bundler.js",

View File

@ -1230,4 +1230,9 @@ describe('BaseTransition', () => {
await runTestWithKeepAlive(testInOutBeforeFinish) await runTestWithKeepAlive(testInOutBeforeFinish)
}) })
}) })
// #10719
test('should not error on KeepAlive w/ function children', () => {
expect(() => mount({}, () => () => h('div'), true)).not.toThrow()
})
}) })

View File

@ -20,6 +20,7 @@ import {
render, render,
withModifiers, withModifiers,
} from '@vue/runtime-dom' } from '@vue/runtime-dom'
import { createApp } from 'vue'
import { PatchFlags } from '@vue/shared' import { PatchFlags } from '@vue/shared'
describe('attribute fallthrough', () => { describe('attribute fallthrough', () => {
@ -783,4 +784,31 @@ describe('attribute fallthrough', () => {
expect(textBar).toBe('from GrandChild') expect(textBar).toBe('from GrandChild')
expect(textFoo).toBe('from Child') expect(textFoo).toBe('from Child')
}) })
// covers uncaught regression #10710
it('should track this.$attrs access in slots', async () => {
const GrandChild = {
template: `<slot/>`,
}
const Child = {
components: { GrandChild },
template: `<div><GrandChild>{{ $attrs.foo }}</GrandChild></div>`,
}
const obj = ref(1)
const App = {
render() {
return h(Child, { foo: obj.value })
},
}
const root = document.createElement('div')
createApp(App).mount(root)
expect(root.innerHTML).toBe('<div foo="1">1</div>')
obj.value = 2
await nextTick()
expect(root.innerHTML).toBe('<div foo="2">2</div>')
})
}) })

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/runtime-core", "name": "@vue/runtime-core",
"version": "3.4.22", "version": "3.4.23",
"description": "@vue/runtime-core", "description": "@vue/runtime-core",
"main": "index.js", "main": "index.js",
"module": "dist/runtime-core.esm-bundler.js", "module": "dist/runtime-core.esm-bundler.js",

View File

@ -38,6 +38,7 @@ import { createPropsDefaultThis } from './compat/props'
import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig' import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
import { DeprecationTypes } from './compat/compatConfig' import { DeprecationTypes } from './compat/compatConfig'
import { shouldSkipAttr } from './compat/attrsFallthrough' import { shouldSkipAttr } from './compat/attrsFallthrough'
import { createInternalObject } from './internalObject'
export type ComponentPropsOptions<P = Data> = export type ComponentPropsOptions<P = Data> =
| ComponentObjectPropsOptions<P> | ComponentObjectPropsOptions<P>
@ -185,13 +186,6 @@ type NormalizedProp =
export type NormalizedProps = Record<string, NormalizedProp> export type NormalizedProps = Record<string, NormalizedProp>
export type NormalizedPropsOptions = [NormalizedProps, string[]] | [] export type NormalizedPropsOptions = [NormalizedProps, string[]] | []
/**
* Used during vnode props normalization to check if the vnode props is the
* attrs object of a component via `Object.getPrototypeOf`. This is more
* performant than defining a non-enumerable property.
*/
export const attrsProto = {}
export function initProps( export function initProps(
instance: ComponentInternalInstance, instance: ComponentInternalInstance,
rawProps: Data | null, rawProps: Data | null,
@ -199,7 +193,7 @@ export function initProps(
isSSR = false, isSSR = false,
) { ) {
const props: Data = {} const props: Data = {}
const attrs: Data = Object.create(attrsProto) const attrs: Data = createInternalObject()
instance.propsDefaults = Object.create(null) instance.propsDefaults = Object.create(null)

View File

@ -367,9 +367,10 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
// public $xxx properties // public $xxx properties
if (publicGetter) { if (publicGetter) {
if (key === '$attrs') { if (key === '$attrs') {
track(instance, TrackOpTypes.GET, key) track(instance.attrs, TrackOpTypes.GET, '')
__DEV__ && markAttrsAccessed() __DEV__ && markAttrsAccessed()
} else if (__DEV__ && key === '$slots') { } else if (__DEV__ && key === '$slots') {
// for HMR only
track(instance, TrackOpTypes.GET, key) track(instance, TrackOpTypes.GET, key)
} }
return publicGetter(instance) return publicGetter(instance)

View File

@ -21,9 +21,8 @@ import { isKeepAlive } from './components/KeepAlive'
import { type ContextualRenderFn, withCtx } from './componentRenderContext' import { type ContextualRenderFn, withCtx } from './componentRenderContext'
import { isHmrUpdating } from './hmr' import { isHmrUpdating } from './hmr'
import { DeprecationTypes, isCompatEnabled } from './compat/compatConfig' import { DeprecationTypes, isCompatEnabled } from './compat/compatConfig'
import { toRaw } from '@vue/reactivity' import { TriggerOpTypes, trigger } from '@vue/reactivity'
import { trigger } from '@vue/reactivity' import { createInternalObject } from './internalObject'
import { TriggerOpTypes } from '@vue/reactivity'
export type Slot<T extends any = any> = ( export type Slot<T extends any = any> = (
...args: IfAny<T, any[], [T] | (T extends undefined ? [] : never)> ...args: IfAny<T, any[], [T] | (T extends undefined ? [] : never)>
@ -166,26 +165,18 @@ export const initSlots = (
instance: ComponentInternalInstance, instance: ComponentInternalInstance,
children: VNodeNormalizedChildren, children: VNodeNormalizedChildren,
) => { ) => {
const slots = (instance.slots = createInternalObject())
if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) { if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
const type = (children as RawSlots)._ const type = (children as RawSlots)._
if (type) { if (type) {
// users can get the shallow readonly version of the slots object through `this.$slots`, extend(slots, children as InternalSlots)
// we should avoid the proxy object polluting the slots of the internal instance
instance.slots = toRaw(children as InternalSlots)
// make compiler marker non-enumerable // make compiler marker non-enumerable
def(instance.slots, '_', type) def(slots, '_', type)
} else { } else {
normalizeObjectSlots( normalizeObjectSlots(children as RawSlots, slots, instance)
children as RawSlots,
(instance.slots = {}),
instance,
)
}
} else {
instance.slots = {}
if (children) {
normalizeVNodeSlots(instance, children)
} }
} else if (children) {
normalizeVNodeSlots(instance, children)
} }
} }

View File

@ -16,7 +16,7 @@ import { warn } from '../warning'
import { isKeepAlive } from './KeepAlive' import { isKeepAlive } from './KeepAlive'
import { SchedulerJobFlags, toRaw } from '@vue/reactivity' import { SchedulerJobFlags, toRaw } from '@vue/reactivity'
import { ErrorCodes, callWithAsyncErrorHandling } from '../errorHandling' import { ErrorCodes, callWithAsyncErrorHandling } from '../errorHandling'
import { PatchFlags, ShapeFlags, isArray } from '@vue/shared' import { PatchFlags, ShapeFlags, isArray, isFunction } from '@vue/shared'
import { onBeforeUnmount, onMounted } from '../apiLifecycle' import { onBeforeUnmount, onMounted } from '../apiLifecycle'
import type { RendererElement } from '../renderer' import type { RendererElement } from '../renderer'
@ -458,15 +458,27 @@ function emptyPlaceholder(vnode: VNode): VNode | undefined {
} }
function getKeepAliveChild(vnode: VNode): VNode | undefined { function getKeepAliveChild(vnode: VNode): VNode | undefined {
return isKeepAlive(vnode) if (!isKeepAlive(vnode)) {
? // #7121 ensure get the child component subtree in case return vnode
// it's been replaced during HMR }
__DEV__ && vnode.component // #7121 ensure get the child component subtree in case
? vnode.component.subTree // it's been replaced during HMR
: vnode.children if (__DEV__ && vnode.component) {
? ((vnode.children as VNodeArrayChildren)[0] as VNode) return vnode.component.subTree
: undefined }
: vnode
const { shapeFlag, children } = vnode
if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
return (children as VNodeArrayChildren)[0] as VNode
}
if (
shapeFlag & ShapeFlags.SLOTS_CHILDREN &&
isFunction((children as any).default)
) {
return (children as any).default()
}
} }
export function setTransitionHooks(vnode: VNode, hooks: TransitionHooks) { export function setTransitionHooks(vnode: VNode, hooks: TransitionHooks) {

View File

@ -814,7 +814,6 @@ function hydrateSuspense(
suspense.resolve(false, true) suspense.resolve(false, true)
} }
return result return result
/* eslint-enable no-restricted-globals */
} }
function normalizeSuspenseChildren(vnode: VNode) { function normalizeSuspenseChildren(vnode: VNode) {

View File

@ -0,0 +1,12 @@
/**
* Used during vnode props/slots normalization to check if the vnode props/slots
* are the internal attrs / slots object of a component via
* `Object.getPrototypeOf`. This is more performant than defining a
* non-enumerable property. (one of the optimizations done for ssr-benchmark)
*/
const internalObjectProto = Object.create(null)
export const createInternalObject = () => Object.create(internalObjectProto)
export const isInternalObject = (obj: object) =>
Object.getPrototypeOf(obj) === internalObjectProto

View File

@ -55,7 +55,7 @@ import { convertLegacyVModelProps } from './compat/componentVModel'
import { defineLegacyVNodeProperties } from './compat/renderFn' import { defineLegacyVNodeProperties } from './compat/renderFn'
import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling' import { ErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
import type { ComponentPublicInstance } from './componentPublicInstance' import type { ComponentPublicInstance } from './componentPublicInstance'
import { attrsProto } from './componentProps' import { isInternalObject } from './internalObject'
export const Fragment = Symbol.for('v-fgt') as any as { export const Fragment = Symbol.for('v-fgt') as any as {
__isFragment: true __isFragment: true
@ -617,9 +617,7 @@ function _createVNode(
export function guardReactiveProps(props: (Data & VNodeProps) | null) { export function guardReactiveProps(props: (Data & VNodeProps) | null) {
if (!props) return null if (!props) return null
return isProxy(props) || Object.getPrototypeOf(props) === attrsProto return isProxy(props) || isInternalObject(props) ? extend({}, props) : props
? extend({}, props)
: props
} }
export function cloneVNode<T, U>( export function cloneVNode<T, U>(
@ -791,7 +789,7 @@ export function normalizeChildren(vnode: VNode, children: unknown) {
} else { } else {
type = ShapeFlags.SLOTS_CHILDREN type = ShapeFlags.SLOTS_CHILDREN
const slotFlag = (children as RawSlots)._ const slotFlag = (children as RawSlots)._
if (!slotFlag) { if (!slotFlag && !isInternalObject(children)) {
// if slots are not normalized, attach context instance // if slots are not normalized, attach context instance
// (compiled / normalized slots already have context) // (compiled / normalized slots already have context)
;(children as RawSlots)._ctx = currentRenderingInstance ;(children as RawSlots)._ctx = currentRenderingInstance

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/runtime-dom", "name": "@vue/runtime-dom",
"version": "3.4.22", "version": "3.4.23",
"description": "@vue/runtime-dom", "description": "@vue/runtime-dom",
"main": "index.js", "main": "index.js",
"module": "dist/runtime-dom.esm-bundler.js", "module": "dist/runtime-dom.esm-bundler.js",

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/server-renderer", "name": "@vue/server-renderer",
"version": "3.4.22", "version": "3.4.23",
"description": "@vue/server-renderer", "description": "@vue/server-renderer",
"main": "index.js", "main": "index.js",
"module": "dist/server-renderer.esm-bundler.js", "module": "dist/server-renderer.esm-bundler.js",

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/shared", "name": "@vue/shared",
"version": "3.4.22", "version": "3.4.23",
"description": "internal utils shared across @vue packages", "description": "internal utils shared across @vue packages",
"main": "index.js", "main": "index.js",
"module": "dist/shared.esm-bundler.js", "module": "dist/shared.esm-bundler.js",

View File

@ -1,6 +1,6 @@
{ {
"name": "@vue/compat", "name": "@vue/compat",
"version": "3.4.22", "version": "3.4.23",
"description": "Vue 3 compatibility build for Vue 2", "description": "Vue 3 compatibility build for Vue 2",
"main": "index.js", "main": "index.js",
"module": "dist/vue.runtime.esm-bundler.js", "module": "dist/vue.runtime.esm-bundler.js",

View File

@ -1,6 +1,6 @@
{ {
"name": "vue", "name": "vue",
"version": "3.4.22", "version": "3.4.23",
"description": "The progressive JavaScript framework for building modern web UI.", "description": "The progressive JavaScript framework for building modern web UI.",
"main": "index.js", "main": "index.js",
"module": "dist/vue.runtime.esm-bundler.js", "module": "dist/vue.runtime.esm-bundler.js",

File diff suppressed because it is too large Load Diff

View File

@ -383,7 +383,7 @@ async function getCIResult() {
) )
const data = await res.json() const data = await res.json()
return data.workflow_runs.length > 0 return data.workflow_runs.length > 0
} catch (e) { } catch {
console.error('Failed to get CI status for current commit.') console.error('Failed to get CI status for current commit.')
return false return false
} }
@ -409,7 +409,7 @@ async function isInSyncWithRemote() {
}) })
return yes return yes
} }
} catch (e) { } catch {
console.error( console.error(
pico.red('Failed to check whether local HEAD is up-to-date with remote.'), pico.red('Failed to check whether local HEAD is up-to-date with remote.'),
) )