chore: Merge branch 'main' into minor

This commit is contained in:
Evan You 2023-12-11 22:03:28 +08:00
commit 982a145d38
44 changed files with 1520 additions and 398 deletions

View File

@ -58,6 +58,31 @@ jobs:
- name: Run ssr unit tests
run: pnpm run test-unit server-renderer
benchmarks:
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
env:
PUPPETEER_SKIP_DOWNLOAD: 'true'
steps:
- uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v2
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version-file: '.node-version'
cache: 'pnpm'
- run: pnpm install
- name: Run benchmarks
uses: CodSpeedHQ/action@v2
with:
run: pnpm vitest bench --run
token: ${{ secrets.CODSPEED_TOKEN }}
e2e-test:
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository

View File

@ -1,3 +1,20 @@
## [3.3.11](https://github.com/vuejs/core/compare/v3.3.10...v3.3.11) (2023-12-08)
### Bug Fixes
* **custom-element:** correctly handle number type props in prod ([#8989](https://github.com/vuejs/core/issues/8989)) ([d74d364](https://github.com/vuejs/core/commit/d74d364d62db8e48881af6b5a75ce4fb5f36cc35))
* **reactivity:** fix mutation on user proxy of reactive Array ([6ecbd5c](https://github.com/vuejs/core/commit/6ecbd5ce2a7f59314a8326a1d193874b87f4d8c8)), closes [#9742](https://github.com/vuejs/core/issues/9742) [#9751](https://github.com/vuejs/core/issues/9751) [#9750](https://github.com/vuejs/core/issues/9750)
* **runtime-dom:** fix width and height prop check condition ([5b00286](https://github.com/vuejs/core/commit/5b002869c533220706f9788b496b8ca8d8e98609)), closes [#9762](https://github.com/vuejs/core/issues/9762)
* **shared:** handle Map with symbol keys in toDisplayString ([#9731](https://github.com/vuejs/core/issues/9731)) ([364821d](https://github.com/vuejs/core/commit/364821d6bdb1775e2f55a69bcfb9f40f7acf1506)), closes [#9727](https://github.com/vuejs/core/issues/9727)
* **shared:** handle more Symbol cases in toDisplayString ([983d45d](https://github.com/vuejs/core/commit/983d45d4f8eb766b5a16b7ea93b86d3c51618fa6))
* **Suspense:** properly get anchor when mount fallback vnode ([#9770](https://github.com/vuejs/core/issues/9770)) ([b700328](https://github.com/vuejs/core/commit/b700328342e17dc16b19316c2e134a26107139d2)), closes [#9769](https://github.com/vuejs/core/issues/9769)
* **types:** ref() return type should not be any when initial value is any ([#9768](https://github.com/vuejs/core/issues/9768)) ([cdac121](https://github.com/vuejs/core/commit/cdac12161ec27b45ded48854c3d749664b6d4a6d))
* **watch:** should not fire pre watcher on child component unmount ([#7181](https://github.com/vuejs/core/issues/7181)) ([6784f0b](https://github.com/vuejs/core/commit/6784f0b1f8501746ea70d87d18ed63a62cf6b76d)), closes [#7030](https://github.com/vuejs/core/issues/7030)
# [3.4.0-alpha.4](https://github.com/vuejs/core/compare/v3.3.10...v3.4.0-alpha.4) (2023-12-04)
@ -19,74 +36,6 @@
# [3.4.0-alpha.3](https://github.com/vuejs/core/compare/v3.4.0-alpha.2...v3.4.0-alpha.3) (2023-11-28)
### Bug Fixes
* **parser:** directive arg should be undefined on shorthands with no arg ([e49dffc](https://github.com/vuejs/core/commit/e49dffc9ece86bddf094b9ad4ad15eb4856d6277))
### Features
* **dx:** link errors to docs in prod build ([#9165](https://github.com/vuejs/core/issues/9165)) ([9f8ba98](https://github.com/vuejs/core/commit/9f8ba9821fe166f77e63fa940e9e7e13ec3344fa))
# [3.4.0-alpha.2](https://github.com/vuejs/core/compare/v3.3.9...v3.4.0-alpha.2) (2023-11-27)
### Bug Fixes
* avoid confusing breakage in @vitejs/plugin-vue ([ceec69c](https://github.com/vuejs/core/commit/ceec69c8ccb96c433a4a506ad2e85e276998bade))
* **compiler-core:** fix line/column tracking when fast forwarding ([2e65ea4](https://github.com/vuejs/core/commit/2e65ea481f74db8649df8110a031cbdc98f98c84))
* **compiler-sfc:** fix ast reuse for ssr ([fb619cf](https://github.com/vuejs/core/commit/fb619cf9a440239f0ba88e327d10001a6a3c8171))
* **compiler-sfc:** support `:is` and `:where` selector in scoped css rewrite ([#8929](https://github.com/vuejs/core/issues/8929)) ([c6083dc](https://github.com/vuejs/core/commit/c6083dcad31f3e9292c687fada9e32f287e2317f))
* **compiler-sfc:** use correct compiler when re-parsing in ssr mode ([678378a](https://github.com/vuejs/core/commit/678378afd559481badb486b243722b6287862e09))
* feat!: remove reactivity transform (#9321) ([79b8a09](https://github.com/vuejs/core/commit/79b8a0905bf363bf82edd2096fef10c3db6d9c3c)), closes [#9321](https://github.com/vuejs/core/issues/9321)
### Features
* **compiler-core:** support specifying root namespace when parsing ([40f72d5](https://github.com/vuejs/core/commit/40f72d5e50b389cb11b7ca13461aa2a75ddacdb4))
* **compiler-core:** support v-bind shorthand for key and value with the same name ([#9451](https://github.com/vuejs/core/issues/9451)) ([26399aa](https://github.com/vuejs/core/commit/26399aa6fac1596b294ffeba06bb498d86f5508c))
* **compiler:** improve parsing tolerance for language-tools ([41ff68e](https://github.com/vuejs/core/commit/41ff68ea579d933333392146625560359acb728a))
* **reactivity:** expose last result for computed getter ([#9497](https://github.com/vuejs/core/issues/9497)) ([48b47a1](https://github.com/vuejs/core/commit/48b47a1ab63577e2dbd91947eea544e3ef185b85))
### Performance Improvements
* avoid sfc source map unnecessary serialization and parsing ([f15d2f6](https://github.com/vuejs/core/commit/f15d2f6cf69c0c39f8dfb5c33122790c68bf92e2))
* **codegen:** optimize line / column calculation during codegen ([3be53d9](https://github.com/vuejs/core/commit/3be53d9b974dae1a10eb795cade71ae765e17574))
* **codegen:** optimize source map generation ([c11002f](https://github.com/vuejs/core/commit/c11002f16afd243a2b15b546816e73882eea9e4d))
* **compiler-sfc:** remove magic-string trim on script ([e8e3ec6](https://github.com/vuejs/core/commit/e8e3ec6ca7392e43975c75b56eaaa711d5ea9410))
* **compiler-sfc:** use faster source map addMapping ([50cde7c](https://github.com/vuejs/core/commit/50cde7cfbcc49022ba88f5f69fa9b930b483c282))
* optimize away isBuiltInType ([66c0ed0](https://github.com/vuejs/core/commit/66c0ed0a3c1c6f37dafc6b1c52b75c6bf60e3136))
* optimize makeMap ([ae6fba9](https://github.com/vuejs/core/commit/ae6fba94954bac6430902f77b0d1113a98a75b18))
* optimize position cloning ([2073236](https://github.com/vuejs/core/commit/20732366b9b3530d33b842cf1fc985919afb9317))
### BREAKING CHANGES
* Reactivity Transform was marked deprecated in 3.3 and is now removed in 3.4. This change does not require a major due to the feature being experimental. Users who wish to continue using the feature can do so via the external plugin at https://vue-macros.dev/features/reactivity-transform.html
# [3.4.0-alpha.1](https://github.com/vuejs/core/compare/v3.3.7...v3.4.0-alpha.1) (2023-10-28)
### Features
* **compiler-core:** export error message ([#8729](https://github.com/vuejs/core/issues/8729)) ([f7e80ee](https://github.com/vuejs/core/commit/f7e80ee4a065a9eaba98720abf415d9e87756cbd))
* **compiler-sfc:** expose resolve type-based props and emits ([#8874](https://github.com/vuejs/core/issues/8874)) ([9e77580](https://github.com/vuejs/core/commit/9e77580c0c2f0d977bd0031a1d43cc334769d433))
* export runtime error strings ([#9301](https://github.com/vuejs/core/issues/9301)) ([feb2f2e](https://github.com/vuejs/core/commit/feb2f2edce2d91218a5e9a52c81e322e4033296b))
* **reactivity:** more efficient reactivity system ([#5912](https://github.com/vuejs/core/issues/5912)) ([16e06ca](https://github.com/vuejs/core/commit/16e06ca08f5a1e2af3fc7fb35de153dbe0c3087d)), closes [#311](https://github.com/vuejs/core/issues/311) [#1811](https://github.com/vuejs/core/issues/1811) [#6018](https://github.com/vuejs/core/issues/6018) [#7160](https://github.com/vuejs/core/issues/7160) [#8714](https://github.com/vuejs/core/issues/8714) [#9149](https://github.com/vuejs/core/issues/9149) [#9419](https://github.com/vuejs/core/issues/9419) [#9464](https://github.com/vuejs/core/issues/9464)
* **runtime-core:** add `once` option to watch ([#9034](https://github.com/vuejs/core/issues/9034)) ([a645e7a](https://github.com/vuejs/core/commit/a645e7aa51006516ba668b3a4365d296eb92ee7d))
## [3.3.10](https://github.com/vuejs/core/compare/v3.3.9...v3.3.10) (2023-12-04)

View File

@ -1,7 +1,7 @@
{
"private": true,
"version": "3.4.0-alpha.4",
"packageManager": "pnpm@8.11.0",
"packageManager": "pnpm@8.12.0",
"type": "module",
"scripts": {
"dev": "node scripts/dev.js",
@ -22,6 +22,7 @@
"test-dts": "run-s build-dts test-dts-only",
"test-dts-only": "tsc -p ./packages/dts-test/tsconfig.test.json",
"test-coverage": "vitest -c vitest.unit.config.ts --coverage",
"test-bench": "vitest bench",
"release": "node scripts/release.js",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s",
"dev-esm": "node scripts/dev.js -if esm-bundler-runtime",
@ -60,6 +61,7 @@
"devDependencies": {
"@babel/parser": "^7.23.5",
"@babel/types": "^7.23.5",
"@codspeed/vitest-plugin": "^2.3.1",
"@rollup/plugin-alias": "^5.0.1",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-json": "^6.0.1",
@ -68,33 +70,33 @@
"@rollup/plugin-terser": "^0.4.4",
"@types/hash-sum": "^1.0.2",
"@types/minimist": "^1.2.5",
"@types/node": "^20.10.3",
"@types/node": "^20.10.4",
"@types/semver": "^7.5.5",
"@typescript-eslint/parser": "^6.13.0",
"@vitest/coverage-istanbul": "^0.34.6",
"@typescript-eslint/parser": "^6.13.2",
"@vitest/coverage-istanbul": "^1.0.4",
"@vue/consolidate": "0.17.3",
"conventional-changelog-cli": "^4.1.0",
"enquirer": "^2.4.1",
"esbuild": "^0.19.5",
"esbuild-plugin-polyfill-node": "^0.3.0",
"eslint": "^8.54.0",
"eslint": "^8.55.0",
"eslint-define-config": "^1.24.1",
"eslint-plugin-jest": "^27.6.0",
"estree-walker": "^2.0.2",
"execa": "^8.0.1",
"jsdom": "^22.1.0",
"lint-staged": "^15.1.0",
"jsdom": "^23.0.1",
"lint-staged": "^15.2.0",
"lodash": "^4.17.21",
"magic-string": "^0.30.5",
"markdown-table": "^3.0.3",
"marked": "^9.1.6",
"marked": "^11.0.1",
"minimist": "^1.2.8",
"npm-run-all": "^4.1.5",
"picocolors": "^1.0.0",
"prettier": "^3.1.0",
"prettier": "^3.1.1",
"pretty-bytes": "^6.1.1",
"pug": "^3.0.2",
"puppeteer": "~21.5.2",
"puppeteer": "~21.6.0",
"rimraf": "^5.0.5",
"rollup": "^4.1.4",
"rollup-plugin-dts": "^6.1.0",
@ -108,7 +110,7 @@
"tslib": "^2.6.2",
"tsx": "^4.6.2",
"typescript": "^5.2.2",
"vite": "^5.0.0",
"vitest": "^1.0.0"
"vite": "^5.0.5",
"vitest": "^1.0.4"
}
}

View File

@ -18,6 +18,47 @@ return { props, bar }
}"
`;
exports[`defineProps > custom element retains the props type & default value & production mode 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
interface Props {
foo?: number;
}
export default /*#__PURE__*/_defineComponent({
__name: 'app.ce',
props: {
foo: { default: 5.5, type: Number }
},
setup(__props: any, { expose: __expose }) {
__expose();
const props = __props;
return { props }
}
})"
`;
exports[`defineProps > custom element retains the props type & production mode 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
export default /*#__PURE__*/_defineComponent({
__name: 'app.ce',
props: {
foo: {type: Number}
},
setup(__props: any, { expose: __expose }) {
__expose();
const props = __props
return { props }
}
})"
`;
exports[`defineProps > defineProps w/ runtime options 1`] = `
"import { defineComponent as _defineComponent } from 'vue'

View File

@ -710,4 +710,35 @@ const props = defineProps({ foo: String })
'da-sh': BindingTypes.PROPS
})
})
// #8989
test('custom element retains the props type & production mode', () => {
const { content } = compile(
`<script setup lang="ts">
const props = defineProps<{ foo: number}>()
</script>`,
{ isProd: true, customElement: filename => /\.ce\.vue$/.test(filename) },
{ filename: 'app.ce.vue' }
)
expect(content).toMatch(`foo: {type: Number}`)
assertCode(content)
})
test('custom element retains the props type & default value & production mode', () => {
const { content } = compile(
`<script setup lang="ts">
interface Props {
foo?: number;
}
const props = withDefaults(defineProps<Props>(), {
foo: 5.5,
});
</script>`,
{ isProd: true, customElement: filename => /\.ce\.vue$/.test(filename) },
{ filename: 'app.ce.vue' }
)
expect(content).toMatch(`foo: { default: 5.5, type: Number }`)
assertCode(content)
})
})

View File

@ -117,6 +117,10 @@ export interface SFCScriptCompileOptions {
fileExists(file: string): boolean
readFile(file: string): string | undefined
}
/**
* Transform Vue SFCs into custom elements.
*/
customElement?: boolean | ((filename: string) => boolean)
}
export interface ImportBinding {

View File

@ -12,6 +12,7 @@ import { TypeScope } from './resolveType'
export class ScriptCompileContext {
isJS: boolean
isTS: boolean
isCE = false
scriptAst: Program | null
scriptSetupAst: Program | null
@ -95,6 +96,14 @@ export class ScriptCompileContext {
scriptSetupLang === 'ts' ||
scriptSetupLang === 'tsx'
const customElement = options.customElement
const filename = this.descriptor.filename
if (customElement) {
this.isCE =
typeof customElement === 'boolean'
? customElement
: customElement(filename)
}
// resolve parser plugins
const plugins: ParserPlugin[] = resolveParserPlugins(
(scriptLang || scriptSetupLang)!,

View File

@ -281,6 +281,17 @@ function genRuntimePropFromType(
defaultString
])} }`
} else {
// #8989 for custom element, should keep the type
if (ctx.isCE) {
if (defaultString) {
return `${finalKey}: ${`{ ${defaultString}, type: ${toRuntimeTypeString(
type
)} }`}`
} else {
return `${finalKey}: {type: ${toRuntimeTypeString(type)}}`
}
}
// production: checks are useless
return `${finalKey}: ${defaultString ? `{ ${defaultString} }` : `{}`}`
}

View File

@ -83,6 +83,9 @@ export type SimpleTypeResolveContext = Pick<
// emits
| 'emitsTypeDecl'
// customElement
| 'isCE'
> &
Partial<
Pick<ScriptCompileContext, 'scope' | 'globalScopes' | 'deps' | 'fs'>
@ -1475,6 +1478,7 @@ export function inferRuntimeType(
scope
)
}
break
case 'TSMethodSignature':
case 'TSFunctionType':
return ['Function']

View File

@ -18,7 +18,7 @@ import {
computed,
ShallowRef
} from 'vue'
import { expectType, describe, IsUnion } from './utils'
import { expectType, describe, IsUnion, IsAny } from './utils'
function plainType(arg: number | Ref<number>) {
// ref coercing
@ -79,6 +79,10 @@ function plainType(arg: number | Ref<number>) {
// should still unwrap in objects nested in arrays
const arr2 = ref([{ a: ref(1) }]).value
expectType<number>(arr2[0].a)
// any value should return Ref<any>, not any
const a = ref(1 as any)
expectType<IsAny<typeof a>>(false)
}
plainType(1)
@ -191,6 +195,12 @@ if (refStatus.value === 'initial') {
expectType<IsUnion<typeof shallowUnionAsCast>>(false)
}
{
// any value should return Ref<any>, not any
const a = shallowRef(1 as any)
expectType<IsAny<typeof a>>(false)
}
describe('shallowRef with generic', <T>() => {
const r = ref({}) as MaybeRef<T>
expectType<ShallowRef<T> | Ref<T>>(shallowRef(r))

View File

@ -260,6 +260,30 @@ describe('defineSlots', () => {
expectType<Slots>(slotsUntype)
})
describe('defineSlots generic', <T extends Record<string, any>>() => {
const props = defineProps<{
item: T
}>()
const slots = defineSlots<
{
[K in keyof T as `slot-${K & string}`]?: (props: { item: T }) => any
} & {
label?: (props: { item: T }) => any
}
>()
for (const key of Object.keys(props.item) as (keyof T & string)[]) {
slots[`slot-${String(key)}`]?.({
item: props.item
})
}
slots.label?.({ item: props.item })
// @ts-expect-error calling wrong slot
slots.foo({})
})
describe('defineModel', () => {
// overload 1
const modelValueRequired = defineModel<boolean>({ required: true })
@ -336,6 +360,78 @@ describe('useSlots', () => {
expectType<Slots>(slots)
})
describe('defineSlots generic', <T extends Record<string, any>>() => {
const props = defineProps<{
item: T
}>()
const slots = defineSlots<
{
[K in keyof T as `slot-${K & string}`]?: (props: { item: T }) => any
} & {
label?: (props: { item: T }) => any
}
>()
// @ts-expect-error slots should be readonly
slots.label = () => {}
// @ts-expect-error non existing slot
slots['foo-asdas']?.({
item: props.item
})
for (const key in props.item) {
slots[`slot-${String(key)}`]?.({
item: props.item
})
slots[`slot-${String(key as keyof T)}`]?.({
item: props.item
})
}
for (const key of Object.keys(props.item) as (keyof T)[]) {
slots[`slot-${String(key)}`]?.({
item: props.item
})
}
slots.label?.({ item: props.item })
// @ts-expect-error calling wrong slot
slots.foo({})
})
describe('defineSlots generic strict', <T extends {
foo: 'foo'
bar: 'bar'
}>() => {
const props = defineProps<{
item: T
}>()
const slots = defineSlots<
{
[K in keyof T as `slot-${K & string}`]?: (props: { item: T }) => any
} & {
label?: (props: { item: T }) => any
}
>()
// slot-bar/foo should be automatically inferred
slots['slot-bar']?.({ item: props.item })
slots['slot-foo']?.({ item: props.item })
slots.label?.({ item: props.item })
// @ts-expect-error not part of the extends
slots['slot-RANDOM']?.({ item: props.item })
// @ts-expect-error slots should be readonly
slots.label = () => {}
// @ts-expect-error calling wrong slot
slots.foo({})
})
// #6420
describe('toRefs w/ type declaration', () => {
const props = defineProps<{

View File

@ -112,3 +112,11 @@ expectType<JSX.Element>(
)
// @ts-expect-error
;<Suspense onResolve={123} />
// svg
expectType<JSX.Element>(
<svg
xmlnsXlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
/>
)

View File

@ -0,0 +1,41 @@
{
"name": "@vue/reactivity-transform",
"version": "3.3.11",
"description": "@vue/reactivity-transform",
"main": "dist/reactivity-transform.cjs.js",
"files": [
"dist"
],
"buildOptions": {
"formats": [
"cjs"
],
"prod": false
},
"types": "dist/reactivity-transform.d.ts",
"repository": {
"type": "git",
"url": "git+https://github.com/vuejs/core.git",
"directory": "packages/reactivity-transform"
},
"keywords": [
"vue"
],
"author": "Evan You",
"license": "MIT",
"bugs": {
"url": "https://github.com/vuejs/core/issues"
},
"homepage": "https://github.com/vuejs/core/tree/dev/packages/reactivity-transform#readme",
"dependencies": {
"@babel/parser": "^7.23.5",
"@vue/compiler-core": "workspace:*",
"@vue/shared": "workspace:*",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.5"
},
"devDependencies": {
"@babel/core": "^7.23.5",
"@babel/types": "^7.23.5"
}
}

View File

@ -0,0 +1,126 @@
import { describe, bench } from 'vitest'
import { ComputedRef, Ref, computed, ref } from '../src/index'
describe('computed', () => {
bench('create computed', () => {
computed(() => 100)
})
{
let i = 0
const o = ref(100)
bench('write independent ref dep', () => {
o.value = i++
})
}
{
const v = ref(100)
computed(() => v.value * 2)
let i = 0
bench("write ref, don't read computed (never invoked)", () => {
v.value = i++
})
}
{
const v = ref(100)
computed(() => {
return v.value * 2
})
let i = 0
bench("write ref, don't read computed (never invoked)", () => {
v.value = i++
})
}
{
const v = ref(100)
const c = computed(() => {
return v.value * 2
})
c.value
let i = 0
bench("write ref, don't read computed (invoked)", () => {
v.value = i++
})
}
{
const v = ref(100)
const c = computed(() => {
return v.value * 2
})
let i = 0
bench('write ref, read computed', () => {
v.value = i++
c.value
})
}
{
const v = ref(100)
const computeds = []
for (let i = 0, n = 1000; i < n; i++) {
const c = computed(() => {
return v.value * 2
})
computeds.push(c)
}
let i = 0
bench("write ref, don't read 1000 computeds (never invoked)", () => {
v.value = i++
})
}
{
const v = ref(100)
const computeds = []
for (let i = 0, n = 1000; i < n; i++) {
const c = computed(() => {
return v.value * 2
})
c.value
computeds.push(c)
}
let i = 0
bench("write ref, don't read 1000 computeds (invoked)", () => {
v.value = i++
})
}
{
const v = ref(100)
const computeds: ComputedRef<number>[] = []
for (let i = 0, n = 1000; i < n; i++) {
const c = computed(() => {
return v.value * 2
})
c.value
computeds.push(c)
}
let i = 0
bench('write ref, read 1000 computeds', () => {
v.value = i++
computeds.forEach(c => c.value)
})
}
{
const refs: Ref<number>[] = []
for (let i = 0, n = 1000; i < n; i++) {
refs.push(ref(i))
}
const c = computed(() => {
let total = 0
refs.forEach(ref => (total += ref.value))
return total
})
let i = 0
const n = refs.length
bench('1000 refs, 1 computed', () => {
refs[i++ % n].value++
c.value
})
}
})

View File

@ -158,6 +158,21 @@ describe('reactivity/reactive', () => {
expect(original.bar).toBe(original2)
})
// #1246
test('mutation on objects using reactive as prototype should not trigger', () => {
const observed = reactive({ foo: 1 })
const original = Object.create(observed)
let dummy
effect(() => (dummy = original.foo))
expect(dummy).toBe(1)
observed.foo = 2
expect(dummy).toBe(2)
original.foo = 3
expect(dummy).toBe(2)
original.foo = 4
expect(dummy).toBe(2)
})
test('toRaw', () => {
const original = { foo: 1 }
const observed = reactive(original)
@ -166,11 +181,18 @@ describe('reactivity/reactive', () => {
})
test('toRaw on object using reactive as prototype', () => {
const original = reactive({})
const obj = Object.create(original)
const original = { foo: 1 }
const observed = reactive(original)
const inherted = Object.create(observed)
expect(toRaw(inherted)).toBe(inherted)
})
test('toRaw on user Proxy wrapping reactive', () => {
const original = {}
const re = reactive(original)
const obj = new Proxy(re, {})
const raw = toRaw(obj)
expect(raw).toBe(obj)
expect(raw).not.toBe(toRaw(original))
expect(raw).toBe(original)
})
test('should not unwrap Ref<T>', () => {

View File

@ -0,0 +1,92 @@
import { bench } from 'vitest'
import { computed, reactive, readonly, shallowRef, triggerRef } from '../src'
for (let amount = 1e1; amount < 1e4; amount *= 10) {
{
const rawArray = []
for (let i = 0, n = amount; i < n; i++) {
rawArray.push(i)
}
const r = reactive(rawArray)
const c = computed(() => {
return r.reduce((v, a) => a + v, 0)
})
bench(`reduce *reactive* array, ${amount} elements`, () => {
for (let i = 0, n = r.length; i < n; i++) {
r[i]++
}
c.value
})
}
{
const rawArray = []
for (let i = 0, n = amount; i < n; i++) {
rawArray.push(i)
}
const r = reactive(rawArray)
const c = computed(() => {
return r.reduce((v, a) => a + v, 0)
})
bench(
`reduce *reactive* array, ${amount} elements, only change first value`,
() => {
r[0]++
c.value
}
)
}
{
const rawArray = []
for (let i = 0, n = amount; i < n; i++) {
rawArray.push(i)
}
const r = reactive({ arr: readonly(rawArray) })
const c = computed(() => {
return r.arr.reduce((v, a) => a + v, 0)
})
bench(`reduce *readonly* array, ${amount} elements`, () => {
r.arr = r.arr.map(v => v + 1)
c.value
})
}
{
const rawArray = []
for (let i = 0, n = amount; i < n; i++) {
rawArray.push(i)
}
const r = shallowRef(rawArray)
const c = computed(() => {
return r.value.reduce((v, a) => a + v, 0)
})
bench(`reduce *raw* array, copied, ${amount} elements`, () => {
r.value = r.value.map(v => v + 1)
c.value
})
}
{
const rawArray: number[] = []
for (let i = 0, n = amount; i < n; i++) {
rawArray.push(i)
}
const r = shallowRef(rawArray)
const c = computed(() => {
return r.value.reduce((v, a) => a + v, 0)
})
bench(`reduce *raw* array, manually triggered, ${amount} elements`, () => {
for (let i = 0, n = rawArray.length; i < n; i++) {
rawArray[i]++
}
triggerRef(r)
c.value
})
}
}

View File

@ -175,6 +175,15 @@ describe('reactivity/reactive/Array', () => {
expect(length).toBe('01')
})
// #9742
test('mutation on user proxy of reactive Array', () => {
const array = reactive<number[]>([])
const proxy = new Proxy(array, {})
proxy.push(1)
expect(array).toHaveLength(1)
expect(proxy).toHaveLength(1)
})
describe('Array methods w/ refs', () => {
let original: any[]
beforeEach(() => {

View File

@ -0,0 +1,143 @@
import { bench } from 'vitest'
import { reactive, computed, ComputedRef } from '../src'
function createMap(obj: Record<string, any>) {
const map = new Map()
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
map.set(key, obj[key])
}
}
return map
}
bench('create reactive map', () => {
reactive(createMap({ a: 1 }))
})
{
let i = 0
const r = reactive(createMap({ a: 1 }))
bench('write reactive map property', () => {
r.set('a', i++)
})
}
{
const r = reactive(createMap({ a: 1 }))
computed(() => {
return r.get('a') * 2
})
let i = 0
bench("write reactive map, don't read computed (never invoked)", () => {
r.set('a', i++)
})
}
{
const r = reactive(createMap({ a: 1 }))
const c = computed(() => {
return r.get('a') * 2
})
c.value
let i = 0
bench("write reactive map, don't read computed (invoked)", () => {
r.set('a', i++)
})
}
{
const r = reactive(createMap({ a: 1 }))
const c = computed(() => {
return r.get('a') * 2
})
let i = 0
bench('write reactive map, read computed', () => {
r.set('a', i++)
c.value
})
}
{
const _m = new Map()
for (let i = 0; i < 10000; i++) {
_m.set(i, i)
}
const r = reactive(_m)
const c = computed(() => {
let total = 0
r.forEach((value, key) => {
total += value
})
return total
})
bench("write reactive map (10'000 items), read computed", () => {
r.set(5000, r.get(5000) + 1)
c.value
})
}
{
const r = reactive(createMap({ a: 1 }))
const computeds = []
for (let i = 0, n = 1000; i < n; i++) {
const c = computed(() => {
return r.get('a') * 2
})
computeds.push(c)
}
let i = 0
bench("write reactive map, don't read 1000 computeds (never invoked)", () => {
r.set('a', i++)
})
}
{
const r = reactive(createMap({ a: 1 }))
const computeds = []
for (let i = 0, n = 1000; i < n; i++) {
const c = computed(() => {
return r.get('a') * 2
})
c.value
computeds.push(c)
}
let i = 0
bench("write reactive map, don't read 1000 computeds (invoked)", () => {
r.set('a', i++)
})
}
{
const r = reactive(createMap({ a: 1 }))
const computeds: ComputedRef<number>[] = []
for (let i = 0, n = 1000; i < n; i++) {
const c = computed(() => {
return r.get('a') * 2
})
computeds.push(c)
}
let i = 0
bench('write reactive map, read 1000 computeds', () => {
r.set('a', i++)
computeds.forEach(c => c.value)
})
}
{
const reactives: Map<any, any>[] = []
for (let i = 0, n = 1000; i < n; i++) {
reactives.push(reactive(createMap({ a: i })))
}
const c = computed(() => {
let total = 0
reactives.forEach(r => (total += r.get('a')))
return total
})
let i = 0
const n = reactives.length
bench('1000 reactive maps, 1 computed', () => {
reactives[i++ % n].set('a', reactives[i++ % n].get('a') + 1)
c.value
})
}

View File

@ -0,0 +1,114 @@
import { bench } from 'vitest'
import { ComputedRef, computed, reactive } from '../src'
bench('create reactive obj', () => {
reactive({ a: 1 })
})
{
let i = 0
const r = reactive({ a: 1 })
bench('write reactive obj property', () => {
r.a = i++
})
}
{
const r = reactive({ a: 1 })
computed(() => {
return r.a * 2
})
let i = 0
bench("write reactive obj, don't read computed (never invoked)", () => {
r.a = i++
})
}
{
const r = reactive({ a: 1 })
const c = computed(() => {
return r.a * 2
})
c.value
let i = 0
bench("write reactive obj, don't read computed (invoked)", () => {
r.a = i++
})
}
{
const r = reactive({ a: 1 })
const c = computed(() => {
return r.a * 2
})
let i = 0
bench('write reactive obj, read computed', () => {
r.a = i++
c.value
})
}
{
const r = reactive({ a: 1 })
const computeds = []
for (let i = 0, n = 1000; i < n; i++) {
const c = computed(() => {
return r.a * 2
})
computeds.push(c)
}
let i = 0
bench("write reactive obj, don't read 1000 computeds (never invoked)", () => {
r.a = i++
})
}
{
const r = reactive({ a: 1 })
const computeds = []
for (let i = 0, n = 1000; i < n; i++) {
const c = computed(() => {
return r.a * 2
})
c.value
computeds.push(c)
}
let i = 0
bench("write reactive obj, don't read 1000 computeds (invoked)", () => {
r.a = i++
})
}
{
const r = reactive({ a: 1 })
const computeds: ComputedRef<number>[] = []
for (let i = 0, n = 1000; i < n; i++) {
const c = computed(() => {
return r.a * 2
})
computeds.push(c)
}
let i = 0
bench('write reactive obj, read 1000 computeds', () => {
r.a = i++
computeds.forEach(c => c.value)
})
}
{
const reactives: Record<string, number>[] = []
for (let i = 0, n = 1000; i < n; i++) {
reactives.push(reactive({ a: i }))
}
const c = computed(() => {
let total = 0
reactives.forEach(r => (total += r.a))
return total
})
let i = 0
const n = reactives.length
bench('1000 reactive objs, 1 computed', () => {
reactives[i++ % n].a++
c.value
})
}

View File

@ -0,0 +1,33 @@
import { describe, bench } from 'vitest'
import { ref } from '../src/index'
describe('ref', () => {
bench('create ref', () => {
ref(100)
})
{
let i = 0
const v = ref(100)
bench('write ref', () => {
v.value = i++
})
}
{
const v = ref(100)
bench('read ref', () => {
v.value
})
}
{
let i = 0
const v = ref(100)
bench('write/read ref', () => {
v.value = i++
v.value
})
}
})

View File

@ -101,19 +101,25 @@ class BaseReactiveHandler implements ProxyHandler<Target> {
return isReadonly
} else if (key === ReactiveFlags.IS_SHALLOW) {
return shallow
} else if (
key === ReactiveFlags.RAW &&
receiver ===
(isReadonly
? shallow
? shallowReadonlyMap
: readonlyMap
: shallow
? shallowReactiveMap
: reactiveMap
).get(target)
) {
return target
} else if (key === ReactiveFlags.RAW) {
if (
receiver ===
(isReadonly
? shallow
? shallowReadonlyMap
: readonlyMap
: shallow
? shallowReactiveMap
: reactiveMap
).get(target) ||
// receiver is not the reactive proxy, but has the same prototype
// this means the reciever is a user proxy of the reactive proxy
Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)
) {
return target
}
// early return undefined
return
}
const targetIsArray = isArray(target)
@ -169,17 +175,19 @@ class MutableReactiveHandler extends BaseReactiveHandler {
receiver: object
): boolean {
let oldValue = (target as any)[key]
if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) {
return false
}
if (!this._shallow) {
const isOldValueReadonly = isReadonly(oldValue)
if (!isShallow(value) && !isReadonly(value)) {
oldValue = toRaw(oldValue)
value = toRaw(value)
}
if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
oldValue.value = value
return true
if (isOldValueReadonly) {
return false
} else {
oldValue.value = value
return true
}
}
} else {
// in shallow mode, objects are set as-is regardless of reactive or not

View File

@ -100,7 +100,6 @@ export function isRef(r: any): r is Ref {
* @param value - The object to wrap in the ref.
* @see {@link https://vuejs.org/api/reactivity-core.html#ref}
*/
export function ref<T extends Ref>(value: T): T
export function ref<T>(value: T): Ref<UnwrapRef<T>>
export function ref<T = any>(): Ref<T | undefined>
export function ref(value?: unknown) {

View File

@ -0,0 +1,58 @@
import { nextTick, ref, watch, watchEffect } from '../src'
import { bench } from 'vitest'
bench('create watcher', () => {
const v = ref(100)
watch(v, v => {})
})
{
const v = ref(100)
watch(v, v => {})
let i = 0
bench('update ref to trigger watcher (scheduled but not executed)', () => {
v.value = i++
})
}
{
const v = ref(100)
watch(v, v => {})
let i = 0
bench('update ref to trigger watcher (executed)', async () => {
v.value = i++
return nextTick()
})
}
{
bench('create watchEffect', () => {
watchEffect(() => {})
})
}
{
const v = ref(100)
watchEffect(() => {
v.value
})
let i = 0
bench(
'update ref to trigger watchEffect (scheduled but not executed)',
() => {
v.value = i++
}
)
}
{
const v = ref(100)
watchEffect(() => {
v.value
})
let i = 0
bench('update ref to trigger watchEffect (executed)', async () => {
v.value = i++
await nextTick()
})
}

View File

@ -549,6 +549,98 @@ describe('api: watch', () => {
expect(cb).not.toHaveBeenCalled()
})
// #7030
it('should not fire on child component unmount w/ flush: pre', async () => {
const visible = ref(true)
const cb = vi.fn()
const Parent = defineComponent({
props: ['visible'],
render() {
return visible.value ? h(Comp) : null
}
})
const Comp = {
setup() {
watch(visible, cb, { flush: 'pre' })
},
render() {}
}
const App = {
render() {
return h(Parent, {
visible: visible.value
})
}
}
render(h(App), nodeOps.createElement('div'))
expect(cb).not.toHaveBeenCalled()
visible.value = false
await nextTick()
expect(cb).not.toHaveBeenCalled()
})
// #7030
it('flush: pre watcher in child component should not fire before parent update', async () => {
const b = ref(0)
const calls: string[] = []
const Comp = {
setup() {
watch(
() => b.value,
val => {
calls.push('watcher child')
},
{ flush: 'pre' }
)
return () => {
b.value
calls.push('render child')
}
}
}
const Parent = {
props: ['a'],
setup() {
watch(
() => b.value,
val => {
calls.push('watcher parent')
},
{ flush: 'pre' }
)
return () => {
b.value
calls.push('render parent')
return h(Comp)
}
}
}
const App = {
render() {
return h(Parent, {
a: b.value
})
}
}
render(h(App), nodeOps.createElement('div'))
expect(calls).toEqual(['render parent', 'render child'])
b.value++
await nextTick()
expect(calls).toEqual([
'render parent',
'render child',
'watcher parent',
'render parent',
'watcher child',
'render child'
])
})
// #1763
it('flush: pre watcher watching props should fire before child update', async () => {
const a = ref(0)

View File

@ -1185,6 +1185,72 @@ describe('Suspense', () => {
expect(calls).toEqual([`one mounted`, `one unmounted`, `two mounted`])
})
test('mount the fallback content is in the correct position', async () => {
const makeComp = (name: string, delay = 0) =>
defineAsyncComponent(
{
setup() {
return () => h('div', [name])
}
},
delay
)
const One = makeComp('one')
const Two = makeComp('two', 20)
const view = shallowRef(One)
const Comp = {
setup() {
return () =>
h('div', [
h(
Suspense,
{
timeout: 10
},
{
default: h(view.value),
fallback: h('div', 'fallback')
}
),
h('div', 'three')
])
}
}
const root = nodeOps.createElement('div')
render(h(Comp), root)
expect(serializeInner(root)).toBe(
`<div><div>fallback</div><div>three</div></div>`
)
await deps[0]
await nextTick()
expect(serializeInner(root)).toBe(
`<div><div>one</div><div>three</div></div>`
)
view.value = Two
await nextTick()
expect(serializeInner(root)).toBe(
`<div><div>one</div><div>three</div></div>`
)
await new Promise(r => setTimeout(r, 10))
await nextTick()
expect(serializeInner(root)).toBe(
`<div><div>fallback</div><div>three</div></div>`
)
await deps[1]
await nextTick()
expect(serializeInner(root)).toBe(
`<div><div>two</div><div>three</div></div>`
)
})
// #2214
// Since suspense renders its own root like a component, it should not patch
// its content in optimized mode.

View File

@ -66,9 +66,9 @@ const warnRuntimeUsage = (method: string) =>
* foo?: string
* bar: number
* }>()
* ```
*
* @see {@link https://vuejs.org/api/sfc-script-setup.html#defineprops-defineemits}
* ```
*
* This is only usable inside `<script setup>`, is compiled away in the
* output and should **not** be actually called at runtime.
@ -116,8 +116,9 @@ type BooleanKey<T, K extends keyof T = keyof T> = K extends any
* Example type-based declaration:
* ```ts
* const emit = defineEmits<{
* (event: 'change'): void
* (event: 'update', id: number): void
* // <eventName>: <expected arguments>
* change: []
* update: [value: string] // named tuple syntax
* }>()
*
* emit('change')

View File

@ -38,19 +38,18 @@ export type EmitsOptions = ObjectEmitsOptions | string[]
export type EmitsToProps<T extends EmitsOptions> = T extends string[]
? {
[K in string & `on${Capitalize<T[number]>}`]?: (...args: any[]) => any
[K in `on${Capitalize<T[number]>}`]?: (...args: any[]) => any
}
: T extends ObjectEmitsOptions
? {
[K in string &
`on${Capitalize<string & keyof T>}`]?: K extends `on${infer C}`
? T[Uncapitalize<C>] extends null
? (...args: any[]) => any
: (
...args: T[Uncapitalize<C>] extends (...args: infer P) => any
? P
[K in `on${Capitalize<string & keyof T>}`]?: K extends `on${infer C}`
? (
...args: T[Uncapitalize<C>] extends (...args: infer P) => any
? P
: T[Uncapitalize<C>] extends null
? any[]
: never
) => any
) => any
: never
}
: {}

View File

@ -44,7 +44,7 @@ export type SlotsType<T extends Record<string, any> = Record<string, any>> = {
export type StrictUnwrapSlotsType<
S extends SlotsType,
T = NonNullable<S[typeof SlotSymbol]>
> = [keyof S] extends [never] ? Slots : Readonly<T>
> = [keyof S] extends [never] ? Slots : Readonly<T> & T
export type UnwrapSlotsType<
S extends SlotsType,

View File

@ -465,7 +465,7 @@ function createSuspenseBoundary(
timeout: typeof timeout === 'number' ? timeout : -1,
activeBranch: null,
pendingBranch: null,
isInFallback: true,
isInFallback: !isHydrating,
isHydrating,
isUnmounted: false,
effects: [],
@ -583,6 +583,7 @@ function createSuspenseBoundary(
// invoke @fallback event
triggerEvent(vnode, 'onFallback')
const anchor = next(activeBranch!)
const mountFallback = () => {
if (!suspense.isInFallback) {
return
@ -592,7 +593,7 @@ function createSuspenseBoundary(
null,
fallbackVNode,
container,
next(activeBranch!),
anchor,
parentComponent,
null, // fallback tree will not have suspense context
namespace,

View File

@ -1594,7 +1594,7 @@ function baseCreateRenderer(
pauseTracking()
// props update may have triggered pre-flush watchers.
// flush them before the render update.
flushPreFlushCbs()
flushPreFlushCbs(instance)
resetTracking()
}

View File

@ -139,6 +139,7 @@ export function queuePostFlushCb(cb: SchedulerJobs) {
}
export function flushPreFlushCbs(
instance?: ComponentInternalInstance,
seen?: CountMap,
// if currently flushing, skip the current job itself
i = isFlushing ? flushIndex + 1 : 0
@ -149,6 +150,9 @@ export function flushPreFlushCbs(
for (; i < queue.length; i++) {
const cb = queue[i]
if (cb && cb.pre) {
if (instance && cb.id !== instance.uid) {
continue
}
if (__DEV__ && checkRecursiveUpdates(seen!, cb)) {
continue
}

View File

@ -300,6 +300,13 @@ describe('runtime-dom: props patching', () => {
expect(el.getAttribute('width')).toBe('24px')
})
// # 9762 should fallthrough to `key in el` logic for non embedded tags
test('width and height on custom elements', () => {
const el = document.createElement('foobar')
patchProp(el, 'width', null, '24px')
expect(el.getAttribute('width')).toBe('24px')
})
test('translate attribute', () => {
const el = document.createElement('div')
patchProp(el, 'translate', null, 'no')

View File

@ -37,6 +37,6 @@
"dependencies": {
"@vue/shared": "workspace:*",
"@vue/runtime-core": "workspace:*",
"csstype": "^3.1.2"
"csstype": "^3.1.3"
}
}

View File

@ -1077,6 +1077,7 @@ export interface SVGAttributes extends AriaAttributes, EventHandlers<Events> {
xlinkTitle?: string
xlinkType?: string
xmlns?: string
xmlnsXlink?: string
y1?: Numberish
y2?: Numberish
y?: Numberish

View File

@ -111,15 +111,17 @@ function shouldSetAsProp(
return false
}
// #8780 the width or heigth of embedded tags must be set as attribute
// #8780 the width or height of embedded tags must be set as attribute
if (key === 'width' || key === 'height') {
const tag = el.tagName
return !(
if (
tag === 'IMG' ||
tag === 'VIDEO' ||
tag === 'CANVAS' ||
tag === 'SOURCE'
)
) {
return false
}
}
// native onclick with string value, must be set as attribute

View File

@ -10,7 +10,7 @@
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.4.0",
"vite": "^5.0.0"
"vite": "^5.0.5"
},
"dependencies": {
"@vue/repl": "^3.0.0",

View File

@ -24,7 +24,7 @@ const vueVersion = ref(`@${currentCommit}`)
async function setVueVersion(v: string) {
vueVersion.value = `loading...`
await store.setVueVersion(v)
vueVersion.value = `v${v}`
vueVersion.value = v
}
function resetVueVersion() {

View File

@ -74,8 +74,8 @@ onMounted(() => {
<ul class="versions" :class="{ expanded }">
<li v-if="!versions"><a>loading versions...</a></li>
<li v-for="version of versions">
<a @click="setVersion(version)">v{{ version }}</a>
<li v-for="ver of versions" :class="{ active: ver === version }">
<a @click="setVersion(ver)">v{{ ver }}</a>
</li>
<div @click="expanded = false">
<slot />
@ -111,4 +111,8 @@ onMounted(() => {
border-top: 6px solid #aaa;
margin-left: 8px;
}
.versions .active a {
color: var(--green);
}
</style>

View File

@ -171,4 +171,49 @@ describe('toDisplayString', () => {
}"
`)
})
//#9727
test('Map with Symbol keys', () => {
const m = new Map<any, any>([
[Symbol(), 'foo'],
[Symbol(), 'bar'],
[Symbol('baz'), 'baz']
])
expect(toDisplayString(m)).toMatchInlineSnapshot(`
"{
"Map(3)": {
"Symbol(0) =>": "foo",
"Symbol(1) =>": "bar",
"Symbol(baz) =>": "baz"
}
}"
`)
// confirming the symbol renders Symbol(foo)
expect(toDisplayString(new Map([[Symbol('foo'), 'foo']]))).toContain(
String(Symbol('foo'))
)
})
test('Set with Symbol values', () => {
const s = new Set([Symbol('foo'), Symbol('bar'), Symbol()])
expect(toDisplayString(s)).toMatchInlineSnapshot(`
"{
"Set(3)": [
"Symbol(foo)",
"Symbol(bar)",
"Symbol()"
]
}"
`)
})
test('Object with Symbol values', () => {
expect(toDisplayString({ foo: Symbol('x'), bar: Symbol() }))
.toMatchInlineSnapshot(`
"{
"foo": "Symbol(x)",
"bar": "Symbol()"
}"
`)
})
})

View File

@ -118,6 +118,6 @@ export const isKnownSvgAttr = /*#__PURE__*/ makeMap(
`v-mathematical,values,vector-effect,version,vert-adv-y,vert-origin-x,` +
`vert-origin-y,viewBox,viewTarget,visibility,width,widths,word-spacing,` +
`writing-mode,x,x-height,x1,x2,xChannelSelector,xlink:actuate,xlink:arcrole,` +
`xlink:href,xlink:role,xlink:show,xlink:title,xlink:type,xml:base,xml:lang,` +
`xlink:href,xlink:role,xlink:show,xlink:title,xlink:type,xmlns:xlink,xml:base,xml:lang,` +
`xml:space,y,y1,y2,yChannelSelector,z,zoomAndPan`
)

View File

@ -6,7 +6,8 @@ import {
isPlainObject,
isSet,
objectToString,
isString
isString,
isSymbol
} from './general'
/**
@ -31,17 +32,26 @@ const replacer = (_key: string, val: any): any => {
return replacer(_key, val.value)
} else if (isMap(val)) {
return {
[`Map(${val.size})`]: [...val.entries()].reduce((entries, [key, val]) => {
;(entries as any)[`${key} =>`] = val
return entries
}, {})
[`Map(${val.size})`]: [...val.entries()].reduce(
(entries, [key, val], i) => {
entries[stringifySymbol(key, i) + ' =>'] = val
return entries
},
{} as Record<string, any>
)
}
} else if (isSet(val)) {
return {
[`Set(${val.size})`]: [...val.values()]
[`Set(${val.size})`]: [...val.values()].map(v => stringifySymbol(v))
}
} else if (isSymbol(val)) {
return stringifySymbol(val)
} else if (isObject(val) && !isArray(val) && !isPlainObject(val)) {
// native elements
return String(val)
}
return val
}
const stringifySymbol = (v: unknown, i: number | string = ''): any =>
isSymbol(v) ? `Symbol(${v.description ?? i})` : v

View File

@ -11,7 +11,7 @@
"enableNonBrowserBranches": true
},
"dependencies": {
"monaco-editor": "^0.44.0",
"monaco-editor": "^0.45.0",
"source-map-js": "^1.0.2"
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
import { configDefaults, defineConfig, UserConfig } from 'vitest/config'
import { configDefaults, defineConfig } from 'vitest/config'
import { entries } from './scripts/aliases.js'
import codspeedPlugin from '@codspeed/vitest-plugin'
export default defineConfig({
define: {
@ -21,10 +22,9 @@ export default defineConfig({
resolve: {
alias: entries
},
plugins: [codspeedPlugin()],
test: {
globals: true,
// disable threads on GH actions to speed it up
threads: !process.env.GITHUB_ACTIONS,
setupFiles: 'scripts/setupVitest.ts',
environmentMatchGlobs: [
['packages/{vue,vue-compat,runtime-dom}/**', 'jsdom']
@ -44,4 +44,4 @@ export default defineConfig({
]
}
}
}) as UserConfig
})