mirror of https://github.com/vuejs/core.git
Compare commits
37 Commits
Author | SHA1 | Date |
---|---|---|
|
eca0e1ccff | |
|
c85f1b5a13 | |
|
7e133dbe01 | |
|
ba391f5fdf | |
|
50a1c30899 | |
|
b8b926cdee | |
|
5f8314cb7f | |
|
15520954f9 | |
|
f3479aac96 | |
|
919c44744b | |
|
cb14b860f1 | |
|
9818456f20 | |
|
52571655f8 | |
|
c0c9c5baea | |
|
532cfae349 | |
|
c91afec9c2 | |
|
4e9e9ceeb1 | |
|
a6e2032f43 | |
|
6c68421e4d | |
|
c7d3207cde | |
|
cdffaf6b9e | |
|
a47832e75e | |
|
e416f84d74 | |
|
1b98aafa05 | |
|
55dad625ac | |
|
47ddf98602 | |
|
e8d8f5f604 | |
|
5ba1afba09 | |
|
73055d8d95 | |
|
4aa7a4aba3 | |
|
4eb46e443f | |
|
10ebcef8c8 | |
|
f05a8d613b | |
|
762fae4b57 | |
|
e53a4ffbe0 | |
|
62f2aa11a2 | |
|
a60f2bd371 |
|
@ -31,4 +31,4 @@ jobs:
|
|||
- name: Run prettier
|
||||
run: pnpm run format
|
||||
|
||||
- uses: autofix-ci/action@551dded8c6cc8a1054039c8bc0b8b48c51dfc6ef
|
||||
- uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27
|
||||
|
|
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -1,10 +1,31 @@
|
|||
## [3.5.17](https://github.com/vuejs/core/compare/v3.5.16...v3.5.17) (2025-06-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compat:** allow v-model built in modifiers on component ([#12654](https://github.com/vuejs/core/issues/12654)) ([cb14b86](https://github.com/vuejs/core/commit/cb14b860f150c4a83bcd52cd26096b7a5aa3a2bf)), closes [#12652](https://github.com/vuejs/core/issues/12652)
|
||||
* **compile-sfc:** handle mapped types work with omit and pick ([#12648](https://github.com/vuejs/core/issues/12648)) ([4eb46e4](https://github.com/vuejs/core/commit/4eb46e443f1878199755cb73d481d318a9714392)), closes [#12647](https://github.com/vuejs/core/issues/12647)
|
||||
* **compiler-core:** do not increase newlines in `InEntity` state ([#13362](https://github.com/vuejs/core/issues/13362)) ([f05a8d6](https://github.com/vuejs/core/commit/f05a8d613bd873b811cfdb9979ccac8382dba322))
|
||||
* **compiler-core:** ignore whitespace when matching adjacent v-if ([#12321](https://github.com/vuejs/core/issues/12321)) ([10ebcef](https://github.com/vuejs/core/commit/10ebcef8c870dbc042b0ea49b1424b2e8f692145)), closes [#9173](https://github.com/vuejs/core/issues/9173)
|
||||
* **compiler-core:** prevent comments from blocking static node hoisting ([#13345](https://github.com/vuejs/core/issues/13345)) ([55dad62](https://github.com/vuejs/core/commit/55dad625acd9e9ddd5a933d5e323ecfdec1a612f)), closes [#13344](https://github.com/vuejs/core/issues/13344)
|
||||
* **compiler-sfc:** improved type resolution for function type aliases ([#13452](https://github.com/vuejs/core/issues/13452)) ([f3479aa](https://github.com/vuejs/core/commit/f3479aac9625f4459e650d1c0a70e73863147903)), closes [#13444](https://github.com/vuejs/core/issues/13444)
|
||||
* **custom-element:** ensure configureApp is applied to async component ([#12607](https://github.com/vuejs/core/issues/12607)) ([5ba1afb](https://github.com/vuejs/core/commit/5ba1afba09c3ea56c1c17484f5d8aeae210ce52a)), closes [#12448](https://github.com/vuejs/core/issues/12448)
|
||||
* **custom-element:** prevent injecting child styles if shadowRoot is false ([#12769](https://github.com/vuejs/core/issues/12769)) ([73055d8](https://github.com/vuejs/core/commit/73055d8d9578d485e3fe846726b50666e1aa56f5)), closes [#12630](https://github.com/vuejs/core/issues/12630)
|
||||
* **reactivity:** add `__v_skip` flag to `Dep` to prevent reactive conversion ([#12804](https://github.com/vuejs/core/issues/12804)) ([e8d8f5f](https://github.com/vuejs/core/commit/e8d8f5f604e821acc46b4200d5b06979c05af1c2)), closes [#12803](https://github.com/vuejs/core/issues/12803)
|
||||
* **runtime-core:** unset old ref during patching when new ref is absent ([#12900](https://github.com/vuejs/core/issues/12900)) ([47ddf98](https://github.com/vuejs/core/commit/47ddf986021dff8de68b0da72787e53a6c19de4c)), closes [#12898](https://github.com/vuejs/core/issues/12898)
|
||||
* **slots:** make cache indexes marker non-enumerable ([#13469](https://github.com/vuejs/core/issues/13469)) ([919c447](https://github.com/vuejs/core/commit/919c44744bba1f0c661c87d2059c3b429611aa7e)), closes [#13468](https://github.com/vuejs/core/issues/13468)
|
||||
* **ssr:** handle initial selected state for select with v-model + v-for/v-if option ([#13487](https://github.com/vuejs/core/issues/13487)) ([1552095](https://github.com/vuejs/core/commit/15520954f9f1c7f834175938a50dba5d4be0e6c4)), closes [#13486](https://github.com/vuejs/core/issues/13486)
|
||||
* **types:** typo of `vOnce` and `vSlot` ([#13343](https://github.com/vuejs/core/issues/13343)) ([762fae4](https://github.com/vuejs/core/commit/762fae4b57ad60602e5c84465a3bff562785b314))
|
||||
|
||||
|
||||
|
||||
## [3.5.16](https://github.com/vuejs/core/compare/v3.5.15...v3.5.16) (2025-05-29)
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "fix(compiler-sfc): add scoping tag to trailing universal selector (#1…" (#13406) ([19f23b1](https://github.com/vuejs/core/commit/19f23b180bb679e38db95d6a10a420abeedc8e1c)), closes [#1](https://github.com/vuejs/core/issues/1) [#13406](https://github.com/vuejs/core/issues/13406)
|
||||
* Revert "fix(compiler-sfc): add error handling for defineModel() without varia…" (#13390) ([42f879f](https://github.com/vuejs/core/commit/42f879fcab48e0e1011967a771b4ad9e8838d760)), closes [#13390](https://github.com/vuejs/core/issues/13390)
|
||||
* Revert "fix(compiler-sfc): add scoping tag to trailing universal selector" (#13406) ([19f23b1](https://github.com/vuejs/core/commit/19f23b180bb679e38db95d6a10a420abeedc8e1c)), closes [#13406](https://github.com/vuejs/core/issues/13406)
|
||||
* Revert "fix(compiler-sfc): add error handling for defineModel() without variable" (#13390) ([42f879f](https://github.com/vuejs/core/commit/42f879fcab48e0e1011967a771b4ad9e8838d760)), closes [#13390](https://github.com/vuejs/core/issues/13390)
|
||||
|
||||
|
||||
|
||||
|
|
14
package.json
14
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"private": true,
|
||||
"version": "3.5.16",
|
||||
"packageManager": "pnpm@10.11.0",
|
||||
"version": "3.5.17",
|
||||
"packageManager": "pnpm@10.12.4",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "node scripts/dev.js",
|
||||
|
@ -65,13 +65,13 @@
|
|||
"@babel/parser": "catalog:",
|
||||
"@babel/types": "catalog:",
|
||||
"@rollup/plugin-alias": "^5.1.1",
|
||||
"@rollup/plugin-commonjs": "^28.0.3",
|
||||
"@rollup/plugin-commonjs": "^28.0.6",
|
||||
"@rollup/plugin-json": "^6.1.0",
|
||||
"@rollup/plugin-node-resolve": "^16.0.1",
|
||||
"@rollup/plugin-replace": "5.0.4",
|
||||
"@swc/core": "^1.11.29",
|
||||
"@swc/core": "^1.12.9",
|
||||
"@types/hash-sum": "^1.0.2",
|
||||
"@types/node": "^22.15.21",
|
||||
"@types/node": "^22.16.0",
|
||||
"@types/semver": "^7.7.0",
|
||||
"@types/serve-handler": "^6.1.4",
|
||||
"@vitest/coverage-v8": "^3.1.4",
|
||||
|
@ -79,7 +79,7 @@
|
|||
"@vue/consolidate": "1.0.0",
|
||||
"conventional-changelog-cli": "^5.0.0",
|
||||
"enquirer": "^2.4.1",
|
||||
"esbuild": "^0.25.4",
|
||||
"esbuild": "^0.25.5",
|
||||
"esbuild-plugin-polyfill-node": "^0.3.0",
|
||||
"eslint": "^9.27.0",
|
||||
"eslint-plugin-import-x": "^4.13.1",
|
||||
|
@ -97,7 +97,7 @@
|
|||
"pug": "^3.0.3",
|
||||
"puppeteer": "~24.9.0",
|
||||
"rimraf": "^6.0.1",
|
||||
"rollup": "^4.41.1",
|
||||
"rollup": "^4.44.1",
|
||||
"rollup-plugin-dts": "^6.2.1",
|
||||
"rollup-plugin-esbuild": "^6.2.1",
|
||||
"rollup-plugin-polyfill-node": "^0.13.0",
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
"vite": "catalog:"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/repl": "^4.5.1",
|
||||
"@vue/repl": "^4.6.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"jszip": "^3.10.1",
|
||||
"vue": "workspace:*"
|
||||
|
|
|
@ -141,6 +141,8 @@ onMounted(() => {
|
|||
:editorOptions="{ autoSaveText: false }"
|
||||
:store="store"
|
||||
:showCompileOutput="true"
|
||||
:showSsrOutput="useSSRMode"
|
||||
:showOpenSourceMap="true"
|
||||
:autoResize="true"
|
||||
:clearConsole="false"
|
||||
:preview-options="{
|
||||
|
|
|
@ -2271,6 +2271,11 @@ describe('compiler: parse', () => {
|
|||
expect(span.loc.start.offset).toBe(0)
|
||||
expect(span.loc.end.offset).toBe(27)
|
||||
})
|
||||
|
||||
test('correct loc when a line in attribute value ends with &', () => {
|
||||
const [span] = baseParse(`<span v-if="foo &&\nbar"></span>`).children
|
||||
expect(span.loc.end.line).toBe(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('decodeEntities option', () => {
|
||||
|
|
|
@ -8,7 +8,7 @@ return function render(_ctx, _cache) {
|
|||
const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||
|
||||
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||
_createElementVNode("div", { key: "foo" }, null, -1 /* HOISTED */)
|
||||
_createElementVNode("div", { key: "foo" }, null, -1 /* CACHED */)
|
||||
])))
|
||||
}
|
||||
}"
|
||||
|
@ -25,11 +25,11 @@ return function render(_ctx, _cache) {
|
|||
_createElementVNode("p", null, [
|
||||
_createElementVNode("span"),
|
||||
_createElementVNode("span")
|
||||
], -1 /* HOISTED */),
|
||||
], -1 /* CACHED */),
|
||||
_createElementVNode("p", null, [
|
||||
_createElementVNode("span"),
|
||||
_createElementVNode("span")
|
||||
], -1 /* HOISTED */)
|
||||
], -1 /* CACHED */)
|
||||
])))
|
||||
}
|
||||
}"
|
||||
|
@ -45,7 +45,7 @@ return function render(_ctx, _cache) {
|
|||
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||
_createElementVNode("div", null, [
|
||||
_createCommentVNode("comment")
|
||||
], -1 /* HOISTED */)
|
||||
], -1 /* CACHED */)
|
||||
])))
|
||||
}
|
||||
}"
|
||||
|
@ -59,9 +59,9 @@ return function render(_ctx, _cache) {
|
|||
const { createElementVNode: _createElementVNode, createTextVNode: _createTextVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||
|
||||
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||
_createElementVNode("span", null, null, -1 /* HOISTED */),
|
||||
_createElementVNode("span", null, null, -1 /* CACHED */),
|
||||
_createTextVNode("foo"),
|
||||
_createElementVNode("div", null, null, -1 /* HOISTED */)
|
||||
_createElementVNode("div", null, null, -1 /* CACHED */)
|
||||
])))
|
||||
}
|
||||
}"
|
||||
|
@ -75,7 +75,7 @@ return function render(_ctx, _cache) {
|
|||
const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||
|
||||
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||
_createElementVNode("span", { class: "inline" }, "hello", -1 /* HOISTED */)
|
||||
_createElementVNode("span", { class: "inline" }, "hello", -1 /* CACHED */)
|
||||
])))
|
||||
}
|
||||
}"
|
||||
|
@ -148,7 +148,7 @@ return function render(_ctx, _cache) {
|
|||
const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||
|
||||
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||
_createElementVNode("span", null, "foo " + _toDisplayString(1) + " " + _toDisplayString(true), -1 /* HOISTED */)
|
||||
_createElementVNode("span", null, "foo " + _toDisplayString(1) + " " + _toDisplayString(true), -1 /* CACHED */)
|
||||
])))
|
||||
}
|
||||
}"
|
||||
|
@ -162,7 +162,7 @@ return function render(_ctx, _cache) {
|
|||
const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||
|
||||
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||
_createElementVNode("span", { foo: 0 }, _toDisplayString(1), -1 /* HOISTED */)
|
||||
_createElementVNode("span", { foo: 0 }, _toDisplayString(1), -1 /* CACHED */)
|
||||
])))
|
||||
}
|
||||
}"
|
||||
|
@ -178,7 +178,7 @@ return function render(_ctx, _cache) {
|
|||
return (_openBlock(), _createElementBlock("div", null, [
|
||||
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(1, (i) => {
|
||||
return (_openBlock(), _createElementBlock("div", null, [...(_cache[0] || (_cache[0] = [
|
||||
_createElementVNode("span", { class: "hi" }, null, -1 /* HOISTED */)
|
||||
_createElementVNode("span", { class: "hi" }, null, -1 /* CACHED */)
|
||||
]))]))
|
||||
}), 256 /* UNKEYED_FRAGMENT */))
|
||||
]))
|
||||
|
@ -216,7 +216,7 @@ return function render(_ctx, _cache) {
|
|||
|
||||
return (_openBlock(), _createElementBlock("div", null, [
|
||||
_withDirectives((_openBlock(), _createElementBlock("svg", null, _cache[0] || (_cache[0] = [
|
||||
_createElementVNode("path", { d: "M2,3H5.5L12" }, null, -1 /* HOISTED */)
|
||||
_createElementVNode("path", { d: "M2,3H5.5L12" }, null, -1 /* CACHED */)
|
||||
]))), [
|
||||
[_directive_foo]
|
||||
])
|
||||
|
@ -402,7 +402,7 @@ return function render(_ctx, _cache) {
|
|||
return (_openBlock(), _createElementBlock("div", null, [
|
||||
ok
|
||||
? (_openBlock(), _createElementBlock("div", _hoisted_1, _cache[0] || (_cache[0] = [
|
||||
_createElementVNode("span", null, null, -1 /* HOISTED */)
|
||||
_createElementVNode("span", null, null, -1 /* CACHED */)
|
||||
])))
|
||||
: _createCommentVNode("v-if", true)
|
||||
]))
|
||||
|
@ -410,6 +410,32 @@ return function render(_ctx, _cache) {
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: cacheStatic transform > should hoist props for root with single element excluding comments 1`] = `
|
||||
"const _Vue = Vue
|
||||
const { createElementVNode: _createElementVNode, createCommentVNode: _createCommentVNode } = _Vue
|
||||
|
||||
const _hoisted_1 = { id: "a" }
|
||||
|
||||
return function render(_ctx, _cache) {
|
||||
with (_ctx) {
|
||||
const { createCommentVNode: _createCommentVNode, createElementVNode: _createElementVNode, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
|
||||
|
||||
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
||||
_createCommentVNode("comment"),
|
||||
_createElementVNode("div", _hoisted_1, _cache[0] || (_cache[0] = [
|
||||
_createElementVNode("div", { id: "b" }, [
|
||||
_createElementVNode("div", { id: "c" }, [
|
||||
_createElementVNode("div", { id: "d" }, [
|
||||
_createElementVNode("div", { id: "e" }, "hello")
|
||||
])
|
||||
])
|
||||
], -1 /* CACHED */)
|
||||
]))
|
||||
], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: cacheStatic transform > should hoist v-for children if static 1`] = `
|
||||
"const _Vue = Vue
|
||||
const { createElementVNode: _createElementVNode } = _Vue
|
||||
|
@ -423,7 +449,7 @@ return function render(_ctx, _cache) {
|
|||
return (_openBlock(), _createElementBlock("div", null, [
|
||||
(_openBlock(true), _createElementBlock(_Fragment, null, _renderList(list, (i) => {
|
||||
return (_openBlock(), _createElementBlock("div", _hoisted_1, _cache[0] || (_cache[0] = [
|
||||
_createElementVNode("span", null, null, -1 /* HOISTED */)
|
||||
_createElementVNode("span", null, null, -1 /* CACHED */)
|
||||
])))
|
||||
}), 256 /* UNKEYED_FRAGMENT */))
|
||||
]))
|
||||
|
|
|
@ -246,6 +246,28 @@ return function render(_ctx, _cache) {
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: transform component slots > with whitespace: 'preserve' > named slot with v-if + v-else 1`] = `
|
||||
"const { resolveComponent: _resolveComponent, withCtx: _withCtx, createSlots: _createSlots, openBlock: _openBlock, createBlock: _createBlock } = Vue
|
||||
|
||||
return function render(_ctx, _cache) {
|
||||
const _component_Comp = _resolveComponent("Comp")
|
||||
|
||||
return (_openBlock(), _createBlock(_component_Comp, null, _createSlots({ _: 2 /* DYNAMIC */ }, [
|
||||
ok
|
||||
? {
|
||||
name: "one",
|
||||
fn: _withCtx(() => ["foo"]),
|
||||
key: "0"
|
||||
}
|
||||
: {
|
||||
name: "two",
|
||||
fn: _withCtx(() => ["baz"]),
|
||||
key: "1"
|
||||
}
|
||||
]), 1024 /* DYNAMIC_SLOTS */))
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: transform component slots > with whitespace: 'preserve' > should not generate whitespace only default slot 1`] = `
|
||||
"const { resolveComponent: _resolveComponent, withCtx: _withCtx, openBlock: _openBlock, createBlock: _createBlock } = Vue
|
||||
|
||||
|
|
|
@ -543,6 +543,32 @@ describe('compiler: cacheStatic transform', () => {
|
|||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('should hoist props for root with single element excluding comments', () => {
|
||||
// deeply nested div to trigger stringification condition
|
||||
const root = transformWithCache(
|
||||
`<!--comment--><div id="a"><div id="b"><div id="c"><div id="d"><div id="e">hello</div></div></div></div></div>`,
|
||||
)
|
||||
expect(root.cached.length).toBe(1)
|
||||
expect(root.hoists).toMatchObject([createObjectMatcher({ id: 'a' })])
|
||||
|
||||
expect((root.codegenNode as VNodeCall).children).toMatchObject([
|
||||
{
|
||||
type: NodeTypes.COMMENT,
|
||||
content: 'comment',
|
||||
},
|
||||
{
|
||||
type: NodeTypes.ELEMENT,
|
||||
codegenNode: {
|
||||
type: NodeTypes.VNODE_CALL,
|
||||
tag: `"div"`,
|
||||
props: { content: `_hoisted_1` },
|
||||
children: { type: NodeTypes.JS_CACHE_EXPRESSION },
|
||||
},
|
||||
},
|
||||
])
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
describe('prefixIdentifiers', () => {
|
||||
test('cache nested static tree with static interpolation', () => {
|
||||
const root = transformWithCache(
|
||||
|
|
|
@ -988,5 +988,19 @@ describe('compiler: transform component slots', () => {
|
|||
|
||||
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('named slot with v-if + v-else', () => {
|
||||
const source = `
|
||||
<Comp>
|
||||
<template #one v-if="ok">foo</template>
|
||||
<template #two v-else>baz</template>
|
||||
</Comp>
|
||||
`
|
||||
const { root } = parseWithSlots(source, {
|
||||
whitespace: 'preserve',
|
||||
})
|
||||
|
||||
expect(generate(root, { prefixIdentifiers: true }).code).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@vue/compiler-core",
|
||||
"version": "3.5.16",
|
||||
"version": "3.5.17",
|
||||
"description": "@vue/compiler-core",
|
||||
"main": "index.js",
|
||||
"module": "dist/compiler-core.esm-bundler.js",
|
||||
|
|
|
@ -647,7 +647,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
|
|||
|
||||
// whitespace management
|
||||
if (!tokenizer.inRCDATA) {
|
||||
el.children = condenseWhitespace(children, tag)
|
||||
el.children = condenseWhitespace(children)
|
||||
}
|
||||
|
||||
if (ns === Namespaces.HTML && currentOptions.isIgnoreNewlineTag(tag)) {
|
||||
|
@ -832,10 +832,7 @@ function isUpperCase(c: number) {
|
|||
}
|
||||
|
||||
const windowsNewlineRE = /\r\n/g
|
||||
function condenseWhitespace(
|
||||
nodes: TemplateChildNode[],
|
||||
tag?: string,
|
||||
): TemplateChildNode[] {
|
||||
function condenseWhitespace(nodes: TemplateChildNode[]): TemplateChildNode[] {
|
||||
const shouldCondense = currentOptions.whitespace !== 'preserve'
|
||||
let removedWhitespace = false
|
||||
for (let i = 0; i < nodes.length; i++) {
|
||||
|
|
|
@ -929,7 +929,7 @@ export default class Tokenizer {
|
|||
this.buffer = input
|
||||
while (this.index < this.buffer.length) {
|
||||
const c = this.buffer.charCodeAt(this.index)
|
||||
if (c === CharCodes.NewLine) {
|
||||
if (c === CharCodes.NewLine && this.state !== State.InEntity) {
|
||||
this.newlines.push(this.index)
|
||||
}
|
||||
switch (this.state) {
|
||||
|
|
|
@ -37,7 +37,7 @@ import {
|
|||
helperNameMap,
|
||||
} from './runtimeHelpers'
|
||||
import { isVSlot } from './utils'
|
||||
import { cacheStatic, isSingleElementRoot } from './transforms/cacheStatic'
|
||||
import { cacheStatic, getSingleElementRoot } from './transforms/cacheStatic'
|
||||
import type { CompilerCompatOptions } from './compat/compatConfig'
|
||||
|
||||
// There are two types of transforms:
|
||||
|
@ -356,12 +356,12 @@ function createRootCodegen(root: RootNode, context: TransformContext) {
|
|||
const { helper } = context
|
||||
const { children } = root
|
||||
if (children.length === 1) {
|
||||
const child = children[0]
|
||||
const singleElementRootChild = getSingleElementRoot(root)
|
||||
// if the single child is an element, turn it into a block.
|
||||
if (isSingleElementRoot(root, child) && child.codegenNode) {
|
||||
if (singleElementRootChild && singleElementRootChild.codegenNode) {
|
||||
// single element root is never hoisted so codegenNode will never be
|
||||
// SimpleExpressionNode
|
||||
const codegenNode = child.codegenNode
|
||||
const codegenNode = singleElementRootChild.codegenNode
|
||||
if (codegenNode.type === NodeTypes.VNODE_CALL) {
|
||||
convertToBlock(codegenNode, context)
|
||||
}
|
||||
|
@ -370,7 +370,7 @@ function createRootCodegen(root: RootNode, context: TransformContext) {
|
|||
// - single <slot/>, IfNode, ForNode: already blocks.
|
||||
// - single text node: always patched.
|
||||
// root codegen falls through via genNode()
|
||||
root.codegenNode = child
|
||||
root.codegenNode = children[0]
|
||||
}
|
||||
} else if (children.length > 1) {
|
||||
// root has multiple nodes - return a fragment block.
|
||||
|
|
|
@ -41,20 +41,19 @@ export function cacheStatic(root: RootNode, context: TransformContext): void {
|
|||
context,
|
||||
// Root node is unfortunately non-hoistable due to potential parent
|
||||
// fallthrough attributes.
|
||||
isSingleElementRoot(root, root.children[0]),
|
||||
!!getSingleElementRoot(root),
|
||||
)
|
||||
}
|
||||
|
||||
export function isSingleElementRoot(
|
||||
export function getSingleElementRoot(
|
||||
root: RootNode,
|
||||
child: TemplateChildNode,
|
||||
): child is PlainElementNode | ComponentNode | TemplateNode {
|
||||
const { children } = root
|
||||
return (
|
||||
children.length === 1 &&
|
||||
child.type === NodeTypes.ELEMENT &&
|
||||
!isSlotOutlet(child)
|
||||
)
|
||||
): PlainElementNode | ComponentNode | TemplateNode | null {
|
||||
const children = root.children.filter(x => x.type !== NodeTypes.COMMENT)
|
||||
return children.length === 1 &&
|
||||
children[0].type === NodeTypes.ELEMENT &&
|
||||
!isSlotOutlet(children[0])
|
||||
? children[0]
|
||||
: null
|
||||
}
|
||||
|
||||
function walk(
|
||||
|
|
|
@ -263,7 +263,7 @@ export function processFor(
|
|||
dir: DirectiveNode,
|
||||
context: TransformContext,
|
||||
processCodegen?: (forNode: ForNode) => (() => void) | undefined,
|
||||
) {
|
||||
): (() => void) | undefined {
|
||||
if (!dir.exp) {
|
||||
context.onError(
|
||||
createCompilerError(ErrorCodes.X_V_FOR_NO_EXPRESSION, dir.loc),
|
||||
|
|
|
@ -222,7 +222,7 @@ export function buildSlots(
|
|||
let prev
|
||||
while (j--) {
|
||||
prev = children[j]
|
||||
if (prev.type !== NodeTypes.COMMENT) {
|
||||
if (prev.type !== NodeTypes.COMMENT && isNonWhitespaceContent(prev)) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ exports[`stringify static html > eligible content (elements > 20) + non-eligible
|
|||
return function render(_ctx, _cache) {
|
||||
return (_openBlock(), _createElementBlock("div", null, _cache[0] || (_cache[0] = [
|
||||
_createStaticVNode("<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>", 20),
|
||||
_createElementVNode("div", { key: "1" }, "1", -1 /* HOISTED */),
|
||||
_createElementVNode("div", { key: "1" }, "1", -1 /* CACHED */),
|
||||
_createStaticVNode("<span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span>", 20)
|
||||
])))
|
||||
}"
|
||||
|
@ -54,7 +54,7 @@ return function render(_ctx, _cache) {
|
|||
_createElementVNode("option", { value: "1" }),
|
||||
_createElementVNode("option", { value: "1" }),
|
||||
_createElementVNode("option", { value: "1" })
|
||||
], -1 /* HOISTED */)
|
||||
], -1 /* CACHED */)
|
||||
])))
|
||||
}"
|
||||
`;
|
||||
|
@ -70,11 +70,27 @@ return function render(_ctx, _cache) {
|
|||
_createElementVNode("option", { value: 1 }),
|
||||
_createElementVNode("option", { value: 1 }),
|
||||
_createElementVNode("option", { value: 1 })
|
||||
], -1 /* HOISTED */)
|
||||
], -1 /* CACHED */)
|
||||
])))
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`stringify static html > should bail for comments 1`] = `
|
||||
"const { createCommentVNode: _createCommentVNode, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||
|
||||
const _hoisted_1 = { class: "a" }
|
||||
|
||||
return function render(_ctx, _cache) {
|
||||
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
||||
_createCommentVNode(" Comment 1 "),
|
||||
_createElementVNode("div", _hoisted_1, [
|
||||
_createCommentVNode(" Comment 2 "),
|
||||
_cache[0] || (_cache[0] = _createStaticVNode("<span class=\\"b\\"></span><span class=\\"b\\"></span><span class=\\"b\\"></span><span class=\\"b\\"></span><span class=\\"b\\"></span>", 5))
|
||||
])
|
||||
], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */))
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`stringify static html > should bail on bindings that are cached but not stringifiable 1`] = `
|
||||
"const { createElementVNode: _createElementVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
|
||||
|
||||
|
@ -87,7 +103,7 @@ return function render(_ctx, _cache) {
|
|||
_createElementVNode("span", { class: "foo" }, "foo"),
|
||||
_createElementVNode("span", { class: "foo" }, "foo"),
|
||||
_createElementVNode("img", { src: _imports_0_ })
|
||||
], -1 /* HOISTED */)
|
||||
], -1 /* CACHED */)
|
||||
])))
|
||||
}"
|
||||
`;
|
||||
|
|
|
@ -491,6 +491,16 @@ describe('stringify static html', () => {
|
|||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('should bail for comments', () => {
|
||||
const { code } = compileWithStringify(
|
||||
`<!-- Comment 1 --><div class="a"><!-- Comment 2 -->${repeat(
|
||||
`<span class="b"/>`,
|
||||
StringifyThresholds.ELEMENT_WITH_BINDING_COUNT,
|
||||
)}</div>`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('should bail for <option> elements with null values', () => {
|
||||
const { ast, code } = compileWithStringify(
|
||||
`<div><select><option :value="null" />${repeat(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@vue/compiler-dom",
|
||||
"version": "3.5.16",
|
||||
"version": "3.5.17",
|
||||
"description": "@vue/compiler-dom",
|
||||
"main": "index.js",
|
||||
"module": "dist/compiler-dom.esm-bundler.js",
|
||||
|
|
|
@ -861,7 +861,7 @@ export default {
|
|||
return (_ctx, _cache) => {
|
||||
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
||||
_createElementVNode("div", null, _toDisplayString(count.value), 1 /* TEXT */),
|
||||
_cache[0] || (_cache[0] = _createElementVNode("div", null, "static", -1 /* HOISTED */))
|
||||
_cache[0] || (_cache[0] = _createElementVNode("div", null, "static", -1 /* CACHED */))
|
||||
], 64 /* STABLE_FRAGMENT */))
|
||||
}
|
||||
}
|
||||
|
@ -884,9 +884,9 @@ export default {
|
|||
|
||||
return (_ctx, _push, _parent, _attrs) => {
|
||||
const _cssVars = { style: {
|
||||
"--xxxxxxxx-count": (count.value),
|
||||
"--xxxxxxxx-style\\\\.color": (style.color),
|
||||
"--xxxxxxxx-height\\\\ \\\\+\\\\ \\\\\\"px\\\\\\"": (height.value + "px")
|
||||
":--xxxxxxxx-count": (count.value),
|
||||
":--xxxxxxxx-style\\\\.color": (style.color),
|
||||
":--xxxxxxxx-height\\\\ \\\\+\\\\ \\\\\\"px\\\\\\"": (height.value + "px")
|
||||
}}
|
||||
_push(\`<!--[--><div\${
|
||||
_ssrRenderAttrs(_cssVars)
|
||||
|
|
|
@ -41,8 +41,8 @@ const _hoisted_1 = _imports_0 + '#fragment'
|
|||
|
||||
export function render(_ctx, _cache) {
|
||||
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
||||
_cache[0] || (_cache[0] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* HOISTED */)),
|
||||
_cache[1] || (_cache[1] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* HOISTED */))
|
||||
_cache[0] || (_cache[0] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* CACHED */)),
|
||||
_cache[1] || (_cache[1] = _createElementVNode("use", { href: _hoisted_1 }, null, -1 /* CACHED */))
|
||||
], 64 /* STABLE_FRAGMENT */))
|
||||
}"
|
||||
`;
|
||||
|
|
|
@ -10,8 +10,8 @@ const _hoisted_2 = _imports_0 + ' 1x, ' + "/foo/logo.png" + ' 2x'
|
|||
|
||||
export function render(_ctx, _cache) {
|
||||
return (_openBlock(), _createElementBlock(_Fragment, null, [
|
||||
_cache[0] || (_cache[0] = _createElementVNode("img", { srcset: _hoisted_1 }, null, -1 /* HOISTED */)),
|
||||
_cache[1] || (_cache[1] = _createElementVNode("img", { srcset: _hoisted_2 }, null, -1 /* HOISTED */))
|
||||
_cache[0] || (_cache[0] = _createElementVNode("img", { srcset: _hoisted_1 }, null, -1 /* CACHED */)),
|
||||
_cache[1] || (_cache[1] = _createElementVNode("img", { srcset: _hoisted_2 }, null, -1 /* CACHED */))
|
||||
], 64 /* STABLE_FRAGMENT */))
|
||||
}"
|
||||
`;
|
||||
|
@ -35,51 +35,51 @@ export function render(_ctx, _cache) {
|
|||
_cache[0] || (_cache[0] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: ""
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[1] || (_cache[1] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_1
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[2] || (_cache[2] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_2
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[3] || (_cache[3] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_3
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[4] || (_cache[4] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_4
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[5] || (_cache[5] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_5
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[6] || (_cache[6] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_6
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[7] || (_cache[7] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_7
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[8] || (_cache[8] = _createElementVNode("img", {
|
||||
src: "/logo.png",
|
||||
srcset: "/logo.png, /logo.png 2x"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[9] || (_cache[9] = _createElementVNode("img", {
|
||||
src: "https://example.com/logo.png",
|
||||
srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[10] || (_cache[10] = _createElementVNode("img", {
|
||||
src: "/logo.png",
|
||||
srcset: _hoisted_8
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[11] || (_cache[11] = _createElementVNode("img", {
|
||||
src: "data:image/png;base64,i",
|
||||
srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
|
||||
}, null, -1 /* HOISTED */))
|
||||
}, null, -1 /* CACHED */))
|
||||
], 64 /* STABLE_FRAGMENT */))
|
||||
}"
|
||||
`;
|
||||
|
@ -92,51 +92,51 @@ export function render(_ctx, _cache) {
|
|||
_cache[0] || (_cache[0] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: ""
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[1] || (_cache[1] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: "/foo/logo.png"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[2] || (_cache[2] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: "/foo/logo.png 2x"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[3] || (_cache[3] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: "/foo/logo.png 2x"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[4] || (_cache[4] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: "/foo/logo.png, /foo/logo.png 2x"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[5] || (_cache[5] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: "/foo/logo.png 2x, /foo/logo.png"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[6] || (_cache[6] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: "/foo/logo.png 2x, /foo/logo.png 3x"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[7] || (_cache[7] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: "/foo/logo.png, /foo/logo.png 2x, /foo/logo.png 3x"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[8] || (_cache[8] = _createElementVNode("img", {
|
||||
src: "/logo.png",
|
||||
srcset: "/logo.png, /logo.png 2x"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[9] || (_cache[9] = _createElementVNode("img", {
|
||||
src: "https://example.com/logo.png",
|
||||
srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[10] || (_cache[10] = _createElementVNode("img", {
|
||||
src: "/logo.png",
|
||||
srcset: "/logo.png, /foo/logo.png 2x"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[11] || (_cache[11] = _createElementVNode("img", {
|
||||
src: "data:image/png;base64,i",
|
||||
srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
|
||||
}, null, -1 /* HOISTED */))
|
||||
}, null, -1 /* CACHED */))
|
||||
], 64 /* STABLE_FRAGMENT */))
|
||||
}"
|
||||
`;
|
||||
|
@ -162,51 +162,51 @@ export function render(_ctx, _cache) {
|
|||
_cache[0] || (_cache[0] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: ""
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[1] || (_cache[1] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_1
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[2] || (_cache[2] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_2
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[3] || (_cache[3] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_3
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[4] || (_cache[4] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_4
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[5] || (_cache[5] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_5
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[6] || (_cache[6] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_6
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[7] || (_cache[7] = _createElementVNode("img", {
|
||||
src: "./logo.png",
|
||||
srcset: _hoisted_7
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[8] || (_cache[8] = _createElementVNode("img", {
|
||||
src: "/logo.png",
|
||||
srcset: _hoisted_8
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[9] || (_cache[9] = _createElementVNode("img", {
|
||||
src: "https://example.com/logo.png",
|
||||
srcset: "https://example.com/logo.png, https://example.com/logo.png 2x"
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[10] || (_cache[10] = _createElementVNode("img", {
|
||||
src: "/logo.png",
|
||||
srcset: _hoisted_9
|
||||
}, null, -1 /* HOISTED */)),
|
||||
}, null, -1 /* CACHED */)),
|
||||
_cache[11] || (_cache[11] = _createElementVNode("img", {
|
||||
src: "data:image/png;base64,i",
|
||||
srcset: "data:image/png;base64,i 1x, data:image/png;base64,i 2x"
|
||||
}, null, -1 /* HOISTED */))
|
||||
}, null, -1 /* CACHED */))
|
||||
], 64 /* STABLE_FRAGMENT */))
|
||||
}"
|
||||
`;
|
||||
|
|
|
@ -652,10 +652,10 @@ describe('SFC compile <script setup>', () => {
|
|||
expect(content).toMatch(`return (_ctx, _push`)
|
||||
expect(content).toMatch(`ssrInterpolate`)
|
||||
expect(content).not.toMatch(`useCssVars`)
|
||||
expect(content).toMatch(`"--${mockId}-count": (count.value)`)
|
||||
expect(content).toMatch(`"--${mockId}-style\\\\.color": (style.color)`)
|
||||
expect(content).toMatch(`":--${mockId}-count": (count.value)`)
|
||||
expect(content).toMatch(`":--${mockId}-style\\\\.color": (style.color)`)
|
||||
expect(content).toMatch(
|
||||
`"--${mockId}-height\\\\ \\\\+\\\\ \\\\\\"px\\\\\\"": (height.value + "px")`,
|
||||
`":--${mockId}-height\\\\ \\\\+\\\\ \\\\\\"px\\\\\\"": (height.value + "px")`,
|
||||
)
|
||||
assertCode(content)
|
||||
})
|
||||
|
|
|
@ -148,27 +148,6 @@ export default /*@__PURE__*/_defineComponent({
|
|||
|
||||
|
||||
|
||||
return { }
|
||||
}
|
||||
|
||||
})"
|
||||
`;
|
||||
|
||||
exports[`defineProps > w/ TSTypeAliasDeclaration 1`] = `
|
||||
"import { defineComponent as _defineComponent } from 'vue'
|
||||
type FunFoo<O> = (item: O) => boolean;
|
||||
type FunBar = FunFoo<number>;
|
||||
|
||||
export default /*@__PURE__*/_defineComponent({
|
||||
props: {
|
||||
foo: { type: Function, required: false, default: () => true },
|
||||
bar: { type: Function, required: false, default: () => true }
|
||||
},
|
||||
setup(__props: any, { expose: __expose }) {
|
||||
__expose();
|
||||
|
||||
|
||||
|
||||
return { }
|
||||
}
|
||||
|
||||
|
|
|
@ -808,30 +808,4 @@ const props = defineProps({ foo: String })
|
|||
expect(content).toMatch(`foo: { default: 5.5, type: Number }`)
|
||||
assertCode(content)
|
||||
})
|
||||
|
||||
test('w/ TSTypeAliasDeclaration', () => {
|
||||
const { content } = compile(`
|
||||
<script setup lang="ts">
|
||||
type FunFoo<O> = (item: O) => boolean;
|
||||
type FunBar = FunFoo<number>;
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
foo?: FunFoo<number>;
|
||||
bar?: FunBar;
|
||||
}>(),
|
||||
{
|
||||
foo: () => true,
|
||||
bar: () => true,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
`)
|
||||
assertCode(content)
|
||||
expect(content).toMatch(
|
||||
`foo: { type: Function, required: false, default: () => true }`,
|
||||
)
|
||||
expect(content).toMatch(
|
||||
`bar: { type: Function, required: false, default: () => true }`,
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -278,6 +278,23 @@ describe('resolveType', () => {
|
|||
})
|
||||
})
|
||||
|
||||
test('utility type: mapped type with Omit and Pick', () => {
|
||||
expect(
|
||||
resolve(`
|
||||
type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>
|
||||
interface Test {
|
||||
foo: string;
|
||||
bar?: string;
|
||||
}
|
||||
type OptionalTest = Optional<Test, 'foo'>
|
||||
defineProps<OptionalTest>()
|
||||
`).props,
|
||||
).toStrictEqual({
|
||||
foo: ['String'],
|
||||
bar: ['String'],
|
||||
})
|
||||
})
|
||||
|
||||
test('utility type: ReadonlyArray', () => {
|
||||
expect(
|
||||
resolve(`
|
||||
|
@ -714,6 +731,38 @@ describe('resolveType', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe('type alias declaration', () => {
|
||||
// #13240
|
||||
test('function type', () => {
|
||||
expect(
|
||||
resolve(`
|
||||
type FunFoo<O> = (item: O) => boolean;
|
||||
type FunBar = FunFoo<number>;
|
||||
defineProps<{
|
||||
foo?: FunFoo<number>;
|
||||
bar?: FunBar;
|
||||
}>()
|
||||
`).props,
|
||||
).toStrictEqual({
|
||||
foo: ['Function'],
|
||||
bar: ['Function'],
|
||||
})
|
||||
})
|
||||
|
||||
test('fallback to Unknown', () => {
|
||||
expect(
|
||||
resolve(`
|
||||
type Brand<T> = T & {};
|
||||
defineProps<{
|
||||
foo: Brand<string>;
|
||||
}>()
|
||||
`).props,
|
||||
).toStrictEqual({
|
||||
foo: [UNKNOWN_TYPE],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('generics', () => {
|
||||
test('generic with type literal', () => {
|
||||
expect(
|
||||
|
|
|
@ -39,6 +39,24 @@ describe('SFC scoped CSS', () => {
|
|||
expect(compileScoped(`h1 .foo { color: red; }`)).toMatch(
|
||||
`h1 .foo[data-v-test] { color: red;`,
|
||||
)
|
||||
|
||||
// #13387
|
||||
expect(
|
||||
compileScoped(`main {
|
||||
width: 100%;
|
||||
> * {
|
||||
max-width: 200px;
|
||||
}
|
||||
}`),
|
||||
).toMatchInlineSnapshot(`
|
||||
"main {
|
||||
&[data-v-test] {
|
||||
width: 100%;
|
||||
}
|
||||
> *[data-v-test] {
|
||||
max-width: 200px;
|
||||
}
|
||||
}"`)
|
||||
})
|
||||
|
||||
test('nesting selector', () => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@vue/compiler-sfc",
|
||||
"version": "3.5.16",
|
||||
"version": "3.5.17",
|
||||
"description": "@vue/compiler-sfc",
|
||||
"main": "dist/compiler-sfc.cjs.js",
|
||||
"module": "dist/compiler-sfc.esm-browser.js",
|
||||
|
@ -49,7 +49,7 @@
|
|||
"@vue/shared": "workspace:*",
|
||||
"estree-walker": "catalog:",
|
||||
"magic-string": "catalog:",
|
||||
"postcss": "^8.5.3",
|
||||
"postcss": "^8.5.6",
|
||||
"source-map-js": "catalog:"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -58,10 +58,10 @@
|
|||
"hash-sum": "^2.0.0",
|
||||
"lru-cache": "10.1.0",
|
||||
"merge-source-map": "^1.1.0",
|
||||
"minimatch": "~10.0.1",
|
||||
"minimatch": "~10.0.3",
|
||||
"postcss-modules": "^6.0.1",
|
||||
"postcss-selector-parser": "^7.1.0",
|
||||
"pug": "^3.0.3",
|
||||
"sass": "^1.89.0"
|
||||
"sass": "^1.89.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -546,26 +546,43 @@ function resolveStringType(
|
|||
ctx: TypeResolveContext,
|
||||
node: Node,
|
||||
scope: TypeScope,
|
||||
typeParameters?: Record<string, Node>,
|
||||
): string[] {
|
||||
switch (node.type) {
|
||||
case 'StringLiteral':
|
||||
return [node.value]
|
||||
case 'TSLiteralType':
|
||||
return resolveStringType(ctx, node.literal, scope)
|
||||
return resolveStringType(ctx, node.literal, scope, typeParameters)
|
||||
case 'TSUnionType':
|
||||
return node.types.map(t => resolveStringType(ctx, t, scope)).flat()
|
||||
return node.types
|
||||
.map(t => resolveStringType(ctx, t, scope, typeParameters))
|
||||
.flat()
|
||||
case 'TemplateLiteral': {
|
||||
return resolveTemplateKeys(ctx, node, scope)
|
||||
}
|
||||
case 'TSTypeReference': {
|
||||
const resolved = resolveTypeReference(ctx, node, scope)
|
||||
if (resolved) {
|
||||
return resolveStringType(ctx, resolved, scope)
|
||||
return resolveStringType(ctx, resolved, scope, typeParameters)
|
||||
}
|
||||
if (node.typeName.type === 'Identifier') {
|
||||
const name = node.typeName.name
|
||||
if (typeParameters && typeParameters[name]) {
|
||||
return resolveStringType(
|
||||
ctx,
|
||||
typeParameters[name],
|
||||
scope,
|
||||
typeParameters,
|
||||
)
|
||||
}
|
||||
const getParam = (index = 0) =>
|
||||
resolveStringType(ctx, node.typeParameters!.params[index], scope)
|
||||
switch (node.typeName.name) {
|
||||
resolveStringType(
|
||||
ctx,
|
||||
node.typeParameters!.params[index],
|
||||
scope,
|
||||
typeParameters,
|
||||
)
|
||||
switch (name) {
|
||||
case 'Extract':
|
||||
return getParam(1)
|
||||
case 'Exclude': {
|
||||
|
@ -671,6 +688,7 @@ function resolveBuiltin(
|
|||
ctx,
|
||||
node.typeParameters!.params[1],
|
||||
scope,
|
||||
typeParameters,
|
||||
)
|
||||
const res: ResolvedElements = { props: {}, calls: t.calls }
|
||||
for (const key of picked) {
|
||||
|
@ -683,6 +701,7 @@ function resolveBuiltin(
|
|||
ctx,
|
||||
node.typeParameters!.params[1],
|
||||
scope,
|
||||
typeParameters,
|
||||
)
|
||||
const res: ResolvedElements = { props: {}, calls: t.calls }
|
||||
for (const key in t.props) {
|
||||
|
@ -1569,13 +1588,14 @@ export function inferRuntimeType(
|
|||
case 'TSTypeReference': {
|
||||
const resolved = resolveTypeReference(ctx, node, scope)
|
||||
if (resolved) {
|
||||
if (resolved.type === 'TSTypeAliasDeclaration') {
|
||||
return inferRuntimeType(
|
||||
ctx,
|
||||
resolved.typeAnnotation,
|
||||
resolved._ownerScope,
|
||||
isKeyOf,
|
||||
)
|
||||
// #13240
|
||||
// Special case for function type aliases to ensure correct runtime behavior
|
||||
// other type aliases still fallback to unknown as before
|
||||
if (
|
||||
resolved.type === 'TSTypeAliasDeclaration' &&
|
||||
resolved.typeAnnotation.type === 'TSFunctionType'
|
||||
) {
|
||||
return ['Function']
|
||||
}
|
||||
return inferRuntimeType(ctx, resolved, resolved._ownerScope, isKeyOf)
|
||||
}
|
||||
|
|
|
@ -23,7 +23,12 @@ export function genCssVarsFromList(
|
|||
return `{\n ${vars
|
||||
.map(
|
||||
key =>
|
||||
`"${isSSR ? `--` : ``}${genVarName(id, key, isProd, isSSR)}": (${key})`,
|
||||
// The `:` prefix here is used in `ssrRenderStyle` to distinguish whether
|
||||
// a custom property comes from `ssrCssVars`. If it does, we need to reset
|
||||
// its value to `initial` on the component instance to avoid unintentionally
|
||||
// inheriting the same property value from a different instance of the same
|
||||
// component in the outer scope.
|
||||
`"${isSSR ? `:--` : ``}${genVarName(id, key, isProd, isSSR)}": (${key})`,
|
||||
)
|
||||
.join(',\n ')}\n}`
|
||||
}
|
||||
|
|
|
@ -166,6 +166,132 @@ describe('ssr: v-model', () => {
|
|||
_push(\`</optgroup></select></div>\`)
|
||||
}"
|
||||
`)
|
||||
|
||||
expect(
|
||||
compileWithWrapper(`
|
||||
<select multiple v-model="model">
|
||||
<optgroup>
|
||||
<option v-for="item in items" :value="item">{{item}}</option>
|
||||
</optgroup>
|
||||
</select>`).code,
|
||||
).toMatchInlineSnapshot(`
|
||||
"const { ssrRenderAttr: _ssrRenderAttr, ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require("vue/server-renderer")
|
||||
|
||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple><optgroup><!--[-->\`)
|
||||
_ssrRenderList(_ctx.items, (item) => {
|
||||
_push(\`<option\${
|
||||
_ssrRenderAttr("value", item)
|
||||
}\${
|
||||
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
|
||||
? _ssrLooseContain(_ctx.model, item)
|
||||
: _ssrLooseEqual(_ctx.model, item))) ? " selected" : ""
|
||||
}>\${
|
||||
_ssrInterpolate(item)
|
||||
}</option>\`)
|
||||
})
|
||||
_push(\`<!--]--></optgroup></select></div>\`)
|
||||
}"
|
||||
`)
|
||||
|
||||
expect(
|
||||
compileWithWrapper(`
|
||||
<select multiple v-model="model">
|
||||
<optgroup>
|
||||
<option v-if="true" :value="item">{{item}}</option>
|
||||
</optgroup>
|
||||
</select>`).code,
|
||||
).toMatchInlineSnapshot(`
|
||||
"const { ssrRenderAttr: _ssrRenderAttr, ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate } = require("vue/server-renderer")
|
||||
|
||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple><optgroup>\`)
|
||||
if (true) {
|
||||
_push(\`<option\${
|
||||
_ssrRenderAttr("value", _ctx.item)
|
||||
}\${
|
||||
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
|
||||
? _ssrLooseContain(_ctx.model, _ctx.item)
|
||||
: _ssrLooseEqual(_ctx.model, _ctx.item))) ? " selected" : ""
|
||||
}>\${
|
||||
_ssrInterpolate(_ctx.item)
|
||||
}</option>\`)
|
||||
} else {
|
||||
_push(\`<!---->\`)
|
||||
}
|
||||
_push(\`</optgroup></select></div>\`)
|
||||
}"
|
||||
`)
|
||||
|
||||
expect(
|
||||
compileWithWrapper(`
|
||||
<select multiple v-model="model">
|
||||
<optgroup>
|
||||
<template v-if="ok">
|
||||
<option v-for="item in items" :value="item">{{item}}</option>
|
||||
</template>
|
||||
</optgroup>
|
||||
</select>`).code,
|
||||
).toMatchInlineSnapshot(`
|
||||
"const { ssrRenderAttr: _ssrRenderAttr, ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require("vue/server-renderer")
|
||||
|
||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple><optgroup>\`)
|
||||
if (_ctx.ok) {
|
||||
_push(\`<!--[-->\`)
|
||||
_ssrRenderList(_ctx.items, (item) => {
|
||||
_push(\`<option\${
|
||||
_ssrRenderAttr("value", item)
|
||||
}\${
|
||||
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
|
||||
? _ssrLooseContain(_ctx.model, item)
|
||||
: _ssrLooseEqual(_ctx.model, item))) ? " selected" : ""
|
||||
}>\${
|
||||
_ssrInterpolate(item)
|
||||
}</option>\`)
|
||||
})
|
||||
_push(\`<!--]-->\`)
|
||||
} else {
|
||||
_push(\`<!---->\`)
|
||||
}
|
||||
_push(\`</optgroup></select></div>\`)
|
||||
}"
|
||||
`)
|
||||
|
||||
expect(
|
||||
compileWithWrapper(`
|
||||
<select multiple v-model="model">
|
||||
<optgroup>
|
||||
<template v-for="item in items" :value="item">
|
||||
<option v-if="item===1" :value="item">{{item}}</option>
|
||||
</template>
|
||||
</optgroup>
|
||||
</select>`).code,
|
||||
).toMatchInlineSnapshot(`
|
||||
"const { ssrRenderAttr: _ssrRenderAttr, ssrIncludeBooleanAttr: _ssrIncludeBooleanAttr, ssrLooseContain: _ssrLooseContain, ssrLooseEqual: _ssrLooseEqual, ssrRenderAttrs: _ssrRenderAttrs, ssrInterpolate: _ssrInterpolate, ssrRenderList: _ssrRenderList } = require("vue/server-renderer")
|
||||
|
||||
return function ssrRender(_ctx, _push, _parent, _attrs) {
|
||||
_push(\`<div\${_ssrRenderAttrs(_attrs)}><select multiple><optgroup><!--[-->\`)
|
||||
_ssrRenderList(_ctx.items, (item) => {
|
||||
_push(\`<!--[-->\`)
|
||||
if (item===1) {
|
||||
_push(\`<option\${
|
||||
_ssrRenderAttr("value", item)
|
||||
}\${
|
||||
(_ssrIncludeBooleanAttr((Array.isArray(_ctx.model))
|
||||
? _ssrLooseContain(_ctx.model, item)
|
||||
: _ssrLooseEqual(_ctx.model, item))) ? " selected" : ""
|
||||
}>\${
|
||||
_ssrInterpolate(item)
|
||||
}</option>\`)
|
||||
} else {
|
||||
_push(\`<!---->\`)
|
||||
}
|
||||
_push(\`<!--]-->\`)
|
||||
})
|
||||
_push(\`<!--]--></optgroup></select></div>\`)
|
||||
}"
|
||||
`)
|
||||
})
|
||||
|
||||
test('<input type="radio">', () => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@vue/compiler-ssr",
|
||||
"version": "3.5.16",
|
||||
"version": "3.5.17",
|
||||
"description": "@vue/compiler-ssr",
|
||||
"main": "dist/compiler-ssr.cjs.js",
|
||||
"types": "dist/compiler-ssr.d.ts",
|
||||
|
|
|
@ -39,6 +39,18 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
|
|||
}
|
||||
}
|
||||
|
||||
const processSelectChildren = (children: TemplateChildNode[]) => {
|
||||
children.forEach(child => {
|
||||
if (child.type === NodeTypes.ELEMENT) {
|
||||
processOption(child as PlainElementNode)
|
||||
} else if (child.type === NodeTypes.FOR) {
|
||||
processSelectChildren(child.children)
|
||||
} else if (child.type === NodeTypes.IF) {
|
||||
child.branches.forEach(b => processSelectChildren(b.children))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function processOption(plainNode: PlainElementNode) {
|
||||
if (plainNode.tag === 'option') {
|
||||
if (plainNode.props.findIndex(p => p.name === 'selected') === -1) {
|
||||
|
@ -65,9 +77,7 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
|
|||
)
|
||||
}
|
||||
} else if (plainNode.tag === 'optgroup') {
|
||||
plainNode.children.forEach(option =>
|
||||
processOption(option as PlainElementNode),
|
||||
)
|
||||
processSelectChildren(plainNode.children)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,18 +173,7 @@ export const ssrTransformModel: DirectiveTransform = (dir, node, context) => {
|
|||
checkDuplicatedValue()
|
||||
node.children = [createInterpolation(model, model.loc)]
|
||||
} else if (node.tag === 'select') {
|
||||
const processChildren = (children: TemplateChildNode[]) => {
|
||||
children.forEach(child => {
|
||||
if (child.type === NodeTypes.ELEMENT) {
|
||||
processOption(child as PlainElementNode)
|
||||
} else if (child.type === NodeTypes.FOR) {
|
||||
processChildren(child.children)
|
||||
} else if (child.type === NodeTypes.IF) {
|
||||
child.branches.forEach(b => processChildren(b.children))
|
||||
}
|
||||
})
|
||||
}
|
||||
processChildren(node.children)
|
||||
processSelectChildren(node.children)
|
||||
} else {
|
||||
context.onError(
|
||||
createDOMCompilerError(
|
||||
|
|
|
@ -8,7 +8,9 @@ import {
|
|||
reactive,
|
||||
readonly,
|
||||
ref,
|
||||
shallowRef,
|
||||
toRaw,
|
||||
triggerRef,
|
||||
} from '../src'
|
||||
|
||||
/**
|
||||
|
@ -520,3 +522,16 @@ describe('reactivity/readonly', () => {
|
|||
expect(r.value).toBe(ro)
|
||||
})
|
||||
})
|
||||
|
||||
test('should be able to trigger with triggerRef', () => {
|
||||
const r = shallowRef({ a: 1 })
|
||||
const ror = readonly(r)
|
||||
let dummy
|
||||
effect(() => {
|
||||
dummy = ror.value.a
|
||||
})
|
||||
r.value.a = 2
|
||||
expect(dummy).toBe(1)
|
||||
triggerRef(ror)
|
||||
expect(dummy).toBe(2)
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@vue/reactivity",
|
||||
"version": "3.5.16",
|
||||
"version": "3.5.17",
|
||||
"description": "@vue/reactivity",
|
||||
"main": "index.js",
|
||||
"module": "dist/reactivity.esm-bundler.js",
|
||||
|
|
|
@ -93,6 +93,12 @@ export class Dep {
|
|||
*/
|
||||
sc: number = 0
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
readonly __v_skip = true
|
||||
// TODO isolatedDeclarations ReactiveFlags.SKIP
|
||||
|
||||
constructor(public computed?: ComputedRefImpl | undefined) {
|
||||
if (__DEV__) {
|
||||
this.subsHead = undefined
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
nodeOps,
|
||||
ref,
|
||||
render,
|
||||
useSlots,
|
||||
} from '@vue/runtime-test'
|
||||
import { createBlock, normalizeVNode } from '../src/vnode'
|
||||
import { createSlots } from '../src/helpers/createSlots'
|
||||
|
@ -42,6 +43,29 @@ describe('component: slots', () => {
|
|||
expect(slots).toMatchObject({})
|
||||
})
|
||||
|
||||
test('initSlots: ensure compiler marker non-enumerable', () => {
|
||||
const Comp = {
|
||||
render() {
|
||||
const slots = useSlots()
|
||||
// Only user-defined slots should be enumerable
|
||||
expect(Object.keys(slots)).toEqual(['foo'])
|
||||
|
||||
// Internal compiler markers must still exist but be non-enumerable
|
||||
expect(slots).toHaveProperty('_')
|
||||
expect(Object.getOwnPropertyDescriptor(slots, '_')!.enumerable).toBe(
|
||||
false,
|
||||
)
|
||||
expect(slots).toHaveProperty('__')
|
||||
expect(Object.getOwnPropertyDescriptor(slots, '__')!.enumerable).toBe(
|
||||
false,
|
||||
)
|
||||
return h('div')
|
||||
},
|
||||
}
|
||||
const slots = { foo: () => {}, _: 1, __: [1] }
|
||||
render(createBlock(Comp, null, slots), nodeOps.createElement('div'))
|
||||
})
|
||||
|
||||
test('initSlots: should normalize object slots (when value is null, string, array)', () => {
|
||||
const { slots } = renderWithSlots({
|
||||
_inner: '_inner',
|
||||
|
|
|
@ -179,6 +179,37 @@ describe('api: template refs', () => {
|
|||
expect(el.value).toBe(null)
|
||||
})
|
||||
|
||||
it('unset old ref when new ref is absent', async () => {
|
||||
const root1 = nodeOps.createElement('div')
|
||||
const root2 = nodeOps.createElement('div')
|
||||
const el1 = ref(null)
|
||||
const el2 = ref(null)
|
||||
const toggle = ref(true)
|
||||
|
||||
const Comp1 = {
|
||||
setup() {
|
||||
return () => (toggle.value ? h('div', { ref: el1 }) : h('div'))
|
||||
},
|
||||
}
|
||||
|
||||
const Comp2 = {
|
||||
setup() {
|
||||
return () => h('div', { ref: toggle.value ? el2 : undefined })
|
||||
},
|
||||
}
|
||||
|
||||
render(h(Comp1), root1)
|
||||
render(h(Comp2), root2)
|
||||
|
||||
expect(el1.value).toBe(root1.children[0])
|
||||
expect(el2.value).toBe(root2.children[0])
|
||||
|
||||
toggle.value = false
|
||||
await nextTick()
|
||||
expect(el1.value).toBe(null)
|
||||
expect(el2.value).toBe(null)
|
||||
})
|
||||
|
||||
test('string ref inside slots', async () => {
|
||||
const root = nodeOps.createElement('div')
|
||||
const spy = vi.fn()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@vue/runtime-core",
|
||||
"version": "3.5.16",
|
||||
"version": "3.5.17",
|
||||
"description": "@vue/runtime-core",
|
||||
"main": "index.js",
|
||||
"module": "dist/runtime-core.esm-bundler.js",
|
||||
|
|
|
@ -585,13 +585,13 @@ export interface ComponentInternalInstance {
|
|||
* For updating css vars on contained teleports
|
||||
* @internal
|
||||
*/
|
||||
ut?: (vars?: Record<string, string>) => void
|
||||
ut?: (vars?: Record<string, unknown>) => void
|
||||
|
||||
/**
|
||||
* dev only. For style v-bind hydration mismatch checks
|
||||
* @internal
|
||||
*/
|
||||
getCssVars?: () => Record<string, string>
|
||||
getCssVars?: () => Record<string, unknown>
|
||||
|
||||
/**
|
||||
* v2 compat only, for caching mutated $options
|
||||
|
|
|
@ -151,10 +151,14 @@ export function emit(
|
|||
}
|
||||
|
||||
let args = rawArgs
|
||||
const isModelListener = event.startsWith('update:')
|
||||
const isCompatModelListener =
|
||||
__COMPAT__ && compatModelEventPrefix + event in props
|
||||
const isModelListener = isCompatModelListener || event.startsWith('update:')
|
||||
const modifiers = isCompatModelListener
|
||||
? props.modelModifiers
|
||||
: isModelListener && getModelModifiers(props, event.slice(7))
|
||||
|
||||
// for v-model update:xxx events, apply modifiers on args
|
||||
const modifiers = isModelListener && getModelModifiers(props, event.slice(7))
|
||||
if (modifiers) {
|
||||
if (modifiers.trim) {
|
||||
args = rawArgs.map(a => (isString(a) ? a.trim() : a))
|
||||
|
|
|
@ -193,6 +193,10 @@ export const initSlots = (
|
|||
): void => {
|
||||
const slots = (instance.slots = createInternalObject())
|
||||
if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
|
||||
const cacheIndexes = (children as RawSlots).__
|
||||
// make cache indexes marker non-enumerable
|
||||
if (cacheIndexes) def(slots, '__', cacheIndexes, true)
|
||||
|
||||
const type = (children as RawSlots)._
|
||||
if (type) {
|
||||
assignSlots(slots, children as Slots, optimized)
|
||||
|
|
|
@ -28,6 +28,7 @@ import {
|
|||
isReservedProp,
|
||||
isString,
|
||||
normalizeClass,
|
||||
normalizeCssVarValue,
|
||||
normalizeStyle,
|
||||
stringifyStyle,
|
||||
} from '@vue/shared'
|
||||
|
@ -945,10 +946,8 @@ function resolveCssVars(
|
|||
) {
|
||||
const cssVars = instance.getCssVars()
|
||||
for (const key in cssVars) {
|
||||
expectedMap.set(
|
||||
`--${getEscapedCssVarName(key, false)}`,
|
||||
String(cssVars[key]),
|
||||
)
|
||||
const value = normalizeCssVarValue(cssVars[key])
|
||||
expectedMap.set(`--${getEscapedCssVarName(key, false)}`, value)
|
||||
}
|
||||
}
|
||||
if (vnode === root && instance.parent) {
|
||||
|
@ -997,6 +996,6 @@ function isMismatchAllowed(
|
|||
if (allowedType === MismatchTypes.TEXT && list.includes('children')) {
|
||||
return true
|
||||
}
|
||||
return allowedAttr.split(',').includes(MismatchTypeString[allowedType])
|
||||
return list.includes(MismatchTypeString[allowedType])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ import { isAsyncWrapper } from './apiAsyncComponent'
|
|||
import { isCompatEnabled } from './compat/compatConfig'
|
||||
import { DeprecationTypes } from './compat/compatConfig'
|
||||
import type { TransitionHooks } from './components/BaseTransition'
|
||||
import type { VueElement } from '@vue/runtime-dom'
|
||||
|
||||
export interface Renderer<HostElement = RendererElement> {
|
||||
render: RootRenderFunction<HostElement>
|
||||
|
@ -484,6 +485,8 @@ function baseCreateRenderer(
|
|||
// set ref
|
||||
if (ref != null && parentComponent) {
|
||||
setRef(ref, n1 && n1.ref, parentSuspense, n2 || n1, !n2)
|
||||
} else if (ref == null && n1 && n1.ref != null) {
|
||||
setRef(n1.ref, null, parentSuspense, n1, true)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1348,7 +1351,11 @@ function baseCreateRenderer(
|
|||
}
|
||||
} else {
|
||||
// custom element style injection
|
||||
if (root.ce) {
|
||||
if (
|
||||
root.ce &&
|
||||
// @ts-expect-error _def is private
|
||||
(root.ce as VueElement)._def.shadowRoot !== false
|
||||
) {
|
||||
root.ce._injectChildStyle(type)
|
||||
}
|
||||
|
||||
|
|
|
@ -916,6 +916,30 @@ describe('defineCustomElement', () => {
|
|||
assertStyles(el, [`div { color: blue; }`, `div { color: red; }`])
|
||||
})
|
||||
|
||||
test("child components should not inject styles to root element's shadow root w/ shadowRoot false", async () => {
|
||||
const Bar = defineComponent({
|
||||
styles: [`div { color: green; }`],
|
||||
render() {
|
||||
return 'bar'
|
||||
},
|
||||
})
|
||||
const Baz = () => h(Bar)
|
||||
const Foo = defineCustomElement(
|
||||
{
|
||||
render() {
|
||||
return [h(Baz)]
|
||||
},
|
||||
},
|
||||
{ shadowRoot: false },
|
||||
)
|
||||
|
||||
customElements.define('my-foo-with-shadowroot-false', Foo)
|
||||
container.innerHTML = `<my-foo-with-shadowroot-false></my-foo-with-shadowroot-false>`
|
||||
const el = container.childNodes[0] as VueElement
|
||||
const style = el.shadowRoot?.querySelector('style')
|
||||
expect(style).toBeUndefined()
|
||||
})
|
||||
|
||||
test('with nonce', () => {
|
||||
const Foo = defineCustomElement(
|
||||
{
|
||||
|
@ -1542,6 +1566,29 @@ describe('defineCustomElement', () => {
|
|||
expect(e.shadowRoot?.innerHTML).toBe('<div>app-injected</div>')
|
||||
})
|
||||
|
||||
// #12448
|
||||
test('work with async component', async () => {
|
||||
const AsyncComp = defineAsyncComponent(() => {
|
||||
return Promise.resolve({
|
||||
render() {
|
||||
const msg: string | undefined = inject('msg')
|
||||
return h('div', {}, msg)
|
||||
},
|
||||
} as any)
|
||||
})
|
||||
const E = defineCustomElement(AsyncComp, {
|
||||
configureApp(app) {
|
||||
app.provide('msg', 'app-injected')
|
||||
},
|
||||
})
|
||||
customElements.define('my-async-element-with-app', E)
|
||||
|
||||
container.innerHTML = `<my-async-element-with-app></my-async-element-with-app>`
|
||||
const e = container.childNodes[0] as VueElement
|
||||
await new Promise(r => setTimeout(r))
|
||||
expect(e.shadowRoot?.innerHTML).toBe('<div>app-injected</div>')
|
||||
})
|
||||
|
||||
test('with hmr reload', async () => {
|
||||
const __hmrId = '__hmrWithApp'
|
||||
const def = defineComponent({
|
||||
|
|
|
@ -465,4 +465,27 @@ describe('useCssVars', () => {
|
|||
render(h(App), root)
|
||||
expect(colorInOnMount).toBe(`red`)
|
||||
})
|
||||
|
||||
test('should set vars as `initial` for nullish values', async () => {
|
||||
// `getPropertyValue` cannot reflect the real value for white spaces and JSDOM also
|
||||
// doesn't 100% reflect the real behavior of browsers, so we only keep the test for
|
||||
// `initial` value here.
|
||||
// The value normalization is tested in packages/shared/__tests__/cssVars.spec.ts.
|
||||
const state = reactive<Record<string, unknown>>({
|
||||
foo: undefined,
|
||||
bar: null,
|
||||
})
|
||||
const root = document.createElement('div')
|
||||
const App = {
|
||||
setup() {
|
||||
useCssVars(() => state)
|
||||
return () => h('div')
|
||||
},
|
||||
}
|
||||
render(h(App), root)
|
||||
await nextTick()
|
||||
const style = (root.children[0] as HTMLElement).style
|
||||
expect(style.getPropertyValue('--foo')).toBe('initial')
|
||||
expect(style.getPropertyValue('--bar')).toBe('initial')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@vue/runtime-dom",
|
||||
"version": "3.5.16",
|
||||
"version": "3.5.17",
|
||||
"description": "@vue/runtime-dom",
|
||||
"main": "index.js",
|
||||
"module": "dist/runtime-dom.esm-bundler.js",
|
||||
|
|
|
@ -404,9 +404,10 @@ export class VueElement
|
|||
|
||||
const asyncDef = (this._def as ComponentOptions).__asyncLoader
|
||||
if (asyncDef) {
|
||||
this._pendingResolve = asyncDef().then(def =>
|
||||
resolve((this._def = def), true),
|
||||
)
|
||||
this._pendingResolve = asyncDef().then((def: InnerComponentDef) => {
|
||||
def.configureApp = this._def.configureApp
|
||||
resolve((this._def = def), true)
|
||||
})
|
||||
} else {
|
||||
resolve(this._def)
|
||||
}
|
||||
|
|
|
@ -10,14 +10,16 @@ import {
|
|||
warn,
|
||||
watch,
|
||||
} from '@vue/runtime-core'
|
||||
import { NOOP, ShapeFlags } from '@vue/shared'
|
||||
import { NOOP, ShapeFlags, normalizeCssVarValue } from '@vue/shared'
|
||||
|
||||
export const CSS_VAR_TEXT: unique symbol = Symbol(__DEV__ ? 'CSS_VAR_TEXT' : '')
|
||||
/**
|
||||
* Runtime helper for SFC's CSS variable injection feature.
|
||||
* @private
|
||||
*/
|
||||
export function useCssVars(getter: (ctx: any) => Record<string, string>): void {
|
||||
export function useCssVars(
|
||||
getter: (ctx: any) => Record<string, unknown>,
|
||||
): void {
|
||||
if (!__BROWSER__ && !__TEST__) return
|
||||
|
||||
const instance = getCurrentInstance()
|
||||
|
@ -64,7 +66,7 @@ export function useCssVars(getter: (ctx: any) => Record<string, string>): void {
|
|||
})
|
||||
}
|
||||
|
||||
function setVarsOnVNode(vnode: VNode, vars: Record<string, string>) {
|
||||
function setVarsOnVNode(vnode: VNode, vars: Record<string, unknown>) {
|
||||
if (__FEATURE_SUSPENSE__ && vnode.shapeFlag & ShapeFlags.SUSPENSE) {
|
||||
const suspense = vnode.suspense!
|
||||
vnode = suspense.activeBranch!
|
||||
|
@ -94,13 +96,14 @@ function setVarsOnVNode(vnode: VNode, vars: Record<string, string>) {
|
|||
}
|
||||
}
|
||||
|
||||
function setVarsOnNode(el: Node, vars: Record<string, string>) {
|
||||
function setVarsOnNode(el: Node, vars: Record<string, unknown>) {
|
||||
if (el.nodeType === 1) {
|
||||
const style = (el as HTMLElement).style
|
||||
let cssText = ''
|
||||
for (const key in vars) {
|
||||
style.setProperty(`--${key}`, vars[key])
|
||||
cssText += `--${key}: ${vars[key]};`
|
||||
const value = normalizeCssVarValue(vars[key])
|
||||
style.setProperty(`--${key}`, value)
|
||||
cssText += `--${key}: ${value};`
|
||||
}
|
||||
;(style as any)[CSS_VAR_TEXT] = cssText
|
||||
}
|
||||
|
|
|
@ -58,8 +58,8 @@ declare module '@vue/runtime-core' {
|
|||
vOn: VOnDirective
|
||||
vBind: VModelDirective
|
||||
vIf: Directive<any, boolean>
|
||||
VOnce: Directive
|
||||
VSlot: Directive
|
||||
vOnce: Directive
|
||||
vSlot: Directive
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -203,4 +203,19 @@ describe('ssr: renderStyle', () => {
|
|||
}),
|
||||
).toBe(`color:"><script;`)
|
||||
})
|
||||
|
||||
test('useCssVars handling', () => {
|
||||
expect(
|
||||
ssrRenderStyle({
|
||||
fontSize: null,
|
||||
':--v1': undefined,
|
||||
':--v2': null,
|
||||
':--v3': '',
|
||||
':--v4': ' ',
|
||||
':--v5': 'foo',
|
||||
':--v6': 0,
|
||||
'--foo': 1,
|
||||
}),
|
||||
).toBe(`--v1:initial;--v2:initial;--v3: ;--v4: ;--v5:foo;--v6:0;--foo:1;`)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@vue/server-renderer",
|
||||
"version": "3.5.16",
|
||||
"version": "3.5.17",
|
||||
"description": "@vue/server-renderer",
|
||||
"main": "index.js",
|
||||
"module": "dist/server-renderer.esm-bundler.js",
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import {
|
||||
escapeHtml,
|
||||
isArray,
|
||||
isObject,
|
||||
isRenderableAttrValue,
|
||||
isSVGTag,
|
||||
stringifyStyle,
|
||||
|
@ -12,6 +14,7 @@ import {
|
|||
isString,
|
||||
makeMap,
|
||||
normalizeClass,
|
||||
normalizeCssVarValue,
|
||||
normalizeStyle,
|
||||
propsToAttrMap,
|
||||
} from '@vue/shared'
|
||||
|
@ -93,6 +96,22 @@ export function ssrRenderStyle(raw: unknown): string {
|
|||
if (isString(raw)) {
|
||||
return escapeHtml(raw)
|
||||
}
|
||||
const styles = normalizeStyle(raw)
|
||||
const styles = normalizeStyle(ssrResetCssVars(raw))
|
||||
return escapeHtml(stringifyStyle(styles))
|
||||
}
|
||||
|
||||
function ssrResetCssVars(raw: unknown) {
|
||||
if (!isArray(raw) && isObject(raw)) {
|
||||
const res: Record<string, unknown> = {}
|
||||
for (const key in raw) {
|
||||
// `:` prefixed keys are coming from `ssrCssVars`
|
||||
if (key.startsWith(':--')) {
|
||||
res[key.slice(1)] = normalizeCssVarValue(raw[key])
|
||||
} else {
|
||||
res[key] = raw[key]
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
return raw
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
import { normalizeCssVarValue } from '../src'
|
||||
|
||||
describe('utils/cssVars', () => {
|
||||
test('should normalize css binding values correctly', () => {
|
||||
expect(normalizeCssVarValue(null)).toBe('initial')
|
||||
expect(normalizeCssVarValue(undefined)).toBe('initial')
|
||||
expect(normalizeCssVarValue('')).toBe(' ')
|
||||
expect(normalizeCssVarValue(' ')).toBe(' ')
|
||||
expect(normalizeCssVarValue('foo')).toBe('foo')
|
||||
expect(normalizeCssVarValue(0)).toBe('0')
|
||||
})
|
||||
|
||||
test('should warn on invalid css binding values', () => {
|
||||
const warning =
|
||||
'[Vue warn] Invalid value used for CSS binding. Expected a string or a finite number but received:'
|
||||
expect(normalizeCssVarValue(NaN)).toBe('NaN')
|
||||
expect(warning).toHaveBeenWarnedTimes(1)
|
||||
expect(normalizeCssVarValue(Infinity)).toBe('Infinity')
|
||||
expect(warning).toHaveBeenWarnedTimes(2)
|
||||
expect(normalizeCssVarValue(-Infinity)).toBe('-Infinity')
|
||||
expect(warning).toHaveBeenWarnedTimes(3)
|
||||
expect(normalizeCssVarValue({})).toBe('[object Object]')
|
||||
expect(warning).toHaveBeenWarnedTimes(4)
|
||||
expect(normalizeCssVarValue([])).toBe('')
|
||||
expect(warning).toHaveBeenWarnedTimes(5)
|
||||
})
|
||||
})
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@vue/shared",
|
||||
"version": "3.5.16",
|
||||
"version": "3.5.17",
|
||||
"description": "internal utils shared across @vue packages",
|
||||
"main": "index.js",
|
||||
"module": "dist/shared.esm-bundler.js",
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* Normalize CSS var value created by `v-bind` in `<style>` block
|
||||
* See https://github.com/vuejs/core/pull/12461#issuecomment-2495804664
|
||||
*/
|
||||
export function normalizeCssVarValue(value: unknown): string {
|
||||
if (value == null) {
|
||||
return 'initial'
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return value === '' ? ' ' : value
|
||||
}
|
||||
|
||||
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
||||
if (__DEV__) {
|
||||
console.warn(
|
||||
'[Vue warn] Invalid value used for CSS binding. Expected a string or a finite number but received:',
|
||||
value,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return String(value)
|
||||
}
|
|
@ -12,3 +12,4 @@ export * from './escapeHtml'
|
|||
export * from './looseEqual'
|
||||
export * from './toDisplayString'
|
||||
export * from './typeUtils'
|
||||
export * from './cssVars'
|
||||
|
|
|
@ -139,6 +139,6 @@ export const PatchFlagNames: Record<PatchFlags, string> = {
|
|||
[PatchFlags.NEED_PATCH]: `NEED_PATCH`,
|
||||
[PatchFlags.DYNAMIC_SLOTS]: `DYNAMIC_SLOTS`,
|
||||
[PatchFlags.DEV_ROOT_FRAGMENT]: `DEV_ROOT_FRAGMENT`,
|
||||
[PatchFlags.CACHED]: `HOISTED`,
|
||||
[PatchFlags.CACHED]: `CACHED`,
|
||||
[PatchFlags.BAIL]: `BAIL`,
|
||||
}
|
||||
|
|
|
@ -82,4 +82,62 @@ describe('COMPONENT_V_MODEL', () => {
|
|||
template: `<input :value="input" @input="$emit('update', $event.target.value)">`,
|
||||
})
|
||||
})
|
||||
|
||||
async function runTestWithModifier(CustomInput: ComponentOptions) {
|
||||
const vm = new Vue({
|
||||
data() {
|
||||
return {
|
||||
text: ' foo ',
|
||||
}
|
||||
},
|
||||
components: {
|
||||
CustomInput,
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<span>{{ text }}</span>
|
||||
<custom-input v-model.trim="text"></custom-input>
|
||||
</div>
|
||||
`,
|
||||
}).$mount() as any
|
||||
|
||||
const input = vm.$el.querySelector('input')
|
||||
const span = vm.$el.querySelector('span')
|
||||
|
||||
expect(input.value).toBe(' foo ')
|
||||
expect(span.textContent).toBe(' foo ')
|
||||
|
||||
expect(
|
||||
(deprecationData[DeprecationTypes.COMPONENT_V_MODEL].message as Function)(
|
||||
CustomInput,
|
||||
),
|
||||
).toHaveBeenWarned()
|
||||
|
||||
input.value = ' bar '
|
||||
triggerEvent(input, 'input')
|
||||
await nextTick()
|
||||
|
||||
expect(input.value).toBe('bar')
|
||||
expect(span.textContent).toBe('bar')
|
||||
}
|
||||
|
||||
test('with model modifiers', async () => {
|
||||
await runTestWithModifier({
|
||||
name: 'CustomInput',
|
||||
props: ['value'],
|
||||
template: `<input :value="value" @input="$emit('input', $event.target.value)">`,
|
||||
})
|
||||
})
|
||||
|
||||
test('with model modifiers and model option', async () => {
|
||||
await runTestWithModifier({
|
||||
name: 'CustomInput',
|
||||
props: ['foo'],
|
||||
model: {
|
||||
prop: 'foo',
|
||||
event: 'bar',
|
||||
},
|
||||
template: `<input :value="foo" @input="$emit('bar', $event.target.value)">`,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@vue/compat",
|
||||
"version": "3.5.16",
|
||||
"version": "3.5.17",
|
||||
"description": "Vue 3 compatibility build for Vue 2",
|
||||
"main": "index.js",
|
||||
"module": "dist/vue.runtime.esm-bundler.js",
|
||||
|
|
|
@ -6,7 +6,7 @@ import type { NativeElements, ReservedProps, VNode } from '@vue/runtime-dom'
|
|||
* when ts compilerOptions.jsx is 'react-jsx' or 'react-jsxdev'
|
||||
* https://www.typescriptlang.org/tsconfig#jsxImportSource
|
||||
*/
|
||||
export { h as jsx, h as jsxDEV, Fragment } from '@vue/runtime-dom'
|
||||
export { h as jsx, h as jsxDEV, Fragment, h as jsxs } from '@vue/runtime-dom'
|
||||
|
||||
export namespace JSX {
|
||||
export interface Element extends VNode {}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "vue",
|
||||
"version": "3.5.16",
|
||||
"version": "3.5.17",
|
||||
"description": "The progressive JavaScript framework for building modern web UI.",
|
||||
"main": "index.js",
|
||||
"module": "dist/vue.runtime.esm-bundler.js",
|
||||
|
|
1031
pnpm-lock.yaml
1031
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -3,8 +3,8 @@ packages:
|
|||
- 'packages-private/*'
|
||||
|
||||
catalog:
|
||||
'@babel/parser': ^7.27.2
|
||||
'@babel/types': ^7.27.1
|
||||
'@babel/parser': ^7.27.5
|
||||
'@babel/types': ^7.27.6
|
||||
'estree-walker': ^2.0.2
|
||||
'magic-string': ^0.30.17
|
||||
'source-map-js': ^1.2.1
|
||||
|
|
|
@ -18,7 +18,6 @@ nr build core --formats cjs
|
|||
|
||||
import fs from 'node:fs'
|
||||
import { parseArgs } from 'node:util'
|
||||
import { existsSync, readFileSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { brotliCompressSync, gzipSync } from 'node:zlib'
|
||||
import pico from 'picocolors'
|
||||
|
@ -163,7 +162,7 @@ async function build(target) {
|
|||
? `packages-private`
|
||||
: `packages`
|
||||
const pkgDir = path.resolve(`${pkgBase}/${target}`)
|
||||
const pkg = JSON.parse(readFileSync(`${pkgDir}/package.json`, 'utf-8'))
|
||||
const pkg = JSON.parse(fs.readFileSync(`${pkgDir}/package.json`, 'utf-8'))
|
||||
|
||||
// if this is a full build (no specific targets), ignore private packages
|
||||
if ((isRelease || !targets.length) && pkg.private) {
|
||||
|
@ -171,7 +170,7 @@ async function build(target) {
|
|||
}
|
||||
|
||||
// if building a specific format, do not remove dist.
|
||||
if (!formats && existsSync(`${pkgDir}/dist`)) {
|
||||
if (!formats && fs.existsSync(`${pkgDir}/dist`)) {
|
||||
fs.rmSync(`${pkgDir}/dist`, { recursive: true })
|
||||
}
|
||||
|
||||
|
@ -234,7 +233,7 @@ async function checkSize(target) {
|
|||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function checkFileSize(filePath) {
|
||||
if (!existsSync(filePath)) {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
return
|
||||
}
|
||||
const file = fs.readFileSync(filePath)
|
||||
|
|
Loading…
Reference in New Issue