Skip to content

Commit

Permalink
Merge pull request #161 from vuejs/main
Browse files Browse the repository at this point in the history
update
  • Loading branch information
Tomxuetao committed Sep 14, 2024
2 parents 0a7f209 + 817dca8 commit ccbcf1f
Show file tree
Hide file tree
Showing 42 changed files with 542 additions and 99 deletions.
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
## [3.5.5](https://github.com/vuejs/core/compare/v3.5.4...v3.5.5) (2024-09-13)


### Bug Fixes

* **compiler-core:** fix handling of delimiterOpen in VPre ([#11915](https://github.com/vuejs/core/issues/11915)) ([706d4ac](https://github.com/vuejs/core/commit/706d4ac1d0210b2d9134b3228280187fe02fc971)), closes [#11913](https://github.com/vuejs/core/issues/11913)
* **compiler-dom:** fix stringify static edge for partially eligible chunks in cached parent ([1d99d61](https://github.com/vuejs/core/commit/1d99d61c1bd77f9ea6743f6214a82add8346a121)), closes [#11879](https://github.com/vuejs/core/issues/11879) [#11890](https://github.com/vuejs/core/issues/11890)
* **compiler-dom:** should ignore leading newline in <textarea> per spec ([3c4bf76](https://github.com/vuejs/core/commit/3c4bf7627649ec1e3220f8c4e4163c20d2afb367))
* **compiler-sfc:** nested css supports atrule and comment ([#11899](https://github.com/vuejs/core/issues/11899)) ([0e7bc71](https://github.com/vuejs/core/commit/0e7bc717e6640644f062957ec5031506f0dab215)), closes [#11896](https://github.com/vuejs/core/issues/11896)
* **custom-element:** handle nested customElement mount w/ shadowRoot false ([#11861](https://github.com/vuejs/core/issues/11861)) ([f2d8019](https://github.com/vuejs/core/commit/f2d801918841e7673ff3f048d0d895592a2f7e23)), closes [#11851](https://github.com/vuejs/core/issues/11851) [#11871](https://github.com/vuejs/core/issues/11871)
* **hmr:** reload async child wrapped in Suspense + KeepAlive ([#11907](https://github.com/vuejs/core/issues/11907)) ([10a2c60](https://github.com/vuejs/core/commit/10a2c6053bd30d160d0214bb3566f540187e6874)), closes [#11868](https://github.com/vuejs/core/issues/11868)
* **hydration:** fix mismatch of leading newline in `<textarea>` and `<pre>` ([a5f3c2e](https://github.com/vuejs/core/commit/a5f3c2eb4d2e7fae93ff93ce865b269f01cc825e)), closes [#11873](https://github.com/vuejs/core/issues/11873) [#11874](https://github.com/vuejs/core/issues/11874)
* **reactivity:** properly clean up deps, fix memory leak ([8ea5d6d](https://github.com/vuejs/core/commit/8ea5d6d6981ab7febda0be43c3c92b18869c3a2a)), closes [#11901](https://github.com/vuejs/core/issues/11901)
* **runtime-core:** properly update async component nested in KeepAlive ([#11917](https://github.com/vuejs/core/issues/11917)) ([7fe6c79](https://github.com/vuejs/core/commit/7fe6c795a1fc7ddcea5ad91a56141561192373ac)), closes [#11916](https://github.com/vuejs/core/issues/11916)
* **TransitionGroup:** not warn unkeyed text children with whitespece preserve ([#11888](https://github.com/vuejs/core/issues/11888)) ([7571f20](https://github.com/vuejs/core/commit/7571f20bc3d1854377a146f41d211e05bb68cd47)), closes [#11885](https://github.com/vuejs/core/issues/11885)



## [3.5.4](https://github.com/vuejs/core/compare/v3.5.3...v3.5.4) (2024-09-10)


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"private": true,
"version": "3.5.4",
"version": "3.5.5",
"packageManager": "[email protected]",
"type": "module",
"scripts": {
Expand Down
16 changes: 16 additions & 0 deletions packages/compiler-core/__tests__/parse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2019,6 +2019,21 @@ describe('compiler: parse', () => {
children: [{ type: NodeTypes.TEXT, content: `{{ number ` }],
},
])

const ast3 = baseParse(`<div v-pre><textarea>{{ foo </textarea></div>`, {
parseMode: 'html',
})
expect((ast3.children[0] as ElementNode).children).toMatchObject([
{
type: NodeTypes.ELEMENT,
children: [
{
type: NodeTypes.TEXT,
content: `{{ foo `,
},
],
},
])
})

test('self-closing v-pre', () => {
Expand Down Expand Up @@ -2354,6 +2369,7 @@ describe('compiler: parse', () => {
test('should remove leading newline character immediately following the pre element start tag', () => {
const ast = parse(`<pre>\n foo bar </pre>`, {
isPreTag: tag => tag === 'pre',
isIgnoreNewlineTag: tag => tag === 'pre',
})
expect(ast.children).toHaveLength(1)
const preElement = ast.children[0] as ElementNode
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-core",
"version": "3.5.4",
"version": "3.5.5",
"description": "@vue/compiler-core",
"main": "index.js",
"module": "dist/compiler-core.esm-bundler.js",
Expand Down
5 changes: 5 additions & 0 deletions packages/compiler-core/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ export interface ParserOptions
* e.g. elements that should preserve whitespace inside, e.g. `<pre>`
*/
isPreTag?: (tag: string) => boolean
/**
* Elements that should ignore the first newline token per parinsg spec
* e.g. `<textarea>` and `<pre>`
*/
isIgnoreNewlineTag?: (tag: string) => boolean
/**
* Platform-specific built-in components e.g. `<Transition>`
*/
Expand Down
23 changes: 13 additions & 10 deletions packages/compiler-core/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const defaultParserOptions: MergedParserOptions = {
getNamespace: () => Namespaces.HTML,
isVoidTag: NO,
isPreTag: NO,
isIgnoreNewlineTag: NO,
isCustomElement: NO,
onError: defaultOnError,
onWarn: defaultOnWarn,
Expand Down Expand Up @@ -633,7 +634,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
}

// refine element type
const { tag, ns } = el
const { tag, ns, children } = el
if (!inVPre) {
if (tag === 'slot') {
el.tagType = ElementTypes.SLOT
Expand All @@ -646,8 +647,18 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {

// whitespace management
if (!tokenizer.inRCDATA) {
el.children = condenseWhitespace(el.children, el.tag)
el.children = condenseWhitespace(children, tag)
}

if (ns === Namespaces.HTML && currentOptions.isIgnoreNewlineTag(tag)) {
// remove leading newline for <textarea> and <pre> per html spec
// https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody
const first = children[0]
if (first && first.type === NodeTypes.TEXT) {
first.content = first.content.replace(/^\r?\n/, '')
}
}

if (ns === Namespaces.HTML && currentOptions.isPreTag(tag)) {
inPre--
}
Expand Down Expand Up @@ -869,14 +880,6 @@ function condenseWhitespace(
}
}
}
if (inPre && tag && currentOptions.isPreTag(tag)) {
// remove leading newline per html spec
// https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element
const first = nodes[0]
if (first && first.type === NodeTypes.TEXT) {
first.content = first.content.replace(/^\r?\n/, '')
}
}
return removedWhitespace ? nodes.filter(Boolean) : nodes
}

Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-core/src/tokenizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ export default class Tokenizer {
// We have to parse entities in <title> and <textarea> tags.
if (!__BROWSER__ && c === CharCodes.Amp) {
this.startEntity()
} else if (c === this.delimiterOpen[0]) {
} else if (!this.inVPre && c === this.delimiterOpen[0]) {
// We also need to handle interpolation
this.state = State.InterpolationOpen
this.delimiterIndex = 0
Expand Down
16 changes: 16 additions & 0 deletions packages/compiler-dom/__tests__/parse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ describe('DOM parser', () => {
})
})

test('<textarea> should remove leading newline', () => {
const ast = parse('<textarea>\nhello</textarea>', parserOptions)
const element = ast.children[0] as ElementNode
const text = element.children[0] as TextNode
expect(element.children.length).toBe(1)
expect(text).toStrictEqual({
type: NodeTypes.TEXT,
content: 'hello',
loc: {
start: { offset: 10, line: 1, column: 11 },
end: { offset: 16, line: 2, column: 6 },
source: '\nhello',
},
})
})

test('should not treat Uppercase component as special tag', () => {
const ast = parse(
'<TextArea>some<div>text</div>and<!--comment--></TextArea>',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`stringify static html > eligible content (elements > 20) + non-eligible content 1`] = `
"const { createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
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 */),
_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)
])))
}"
`;

exports[`stringify static html > escape 1`] = `
"const { toDisplayString: _toDisplayString, normalizeClass: _normalizeClass, createElementVNode: _createElementVNode, createStaticVNode: _createStaticVNode, openBlock: _openBlock, createElementBlock: _createElementBlock } = Vue
Expand Down
14 changes: 14 additions & 0 deletions packages/compiler-dom/__tests__/transforms/stringifyStatic.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,4 +451,18 @@ describe('stringify static html', () => {
expect(ast.cached).toMatchObject([cachedArrayBailedMatcher()])
expect(code).toMatchSnapshot()
})

test('eligible content (elements > 20) + non-eligible content', () => {
const { code } = compileWithStringify(
`<div>${repeat(
`<span/>`,
StringifyThresholds.NODE_COUNT,
)}<div key="1">1</div>${repeat(
`<span/>`,
StringifyThresholds.NODE_COUNT,
)}</div>`,
)

expect(code).toMatchSnapshot()
})
})
2 changes: 1 addition & 1 deletion packages/compiler-dom/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-dom",
"version": "3.5.4",
"version": "3.5.5",
"description": "@vue/compiler-dom",
"main": "index.js",
"module": "dist/compiler-dom.esm-bundler.js",
Expand Down
1 change: 1 addition & 0 deletions packages/compiler-dom/src/parserOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const parserOptions: ParserOptions = {
isVoidTag,
isNativeTag: tag => isHTMLTag(tag) || isSVGTag(tag) || isMathMLTag(tag),
isPreTag: tag => tag === 'pre',
isIgnoreNewlineTag: tag => tag === 'pre' || tag === 'textarea',
decodeEntities: __BROWSER__ ? decodeHtmlBrowser : undefined,

isBuiltInComponent: tag => {
Expand Down
18 changes: 12 additions & 6 deletions packages/compiler-dom/src/transforms/stringifyStatic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import {
type TemplateChildNode,
type TextCallNode,
type TransformContext,
type VNodeCall,
createArrayExpression,
createCallExpression,
isStaticArgOf,
} from '@vue/compiler-core'
Expand Down Expand Up @@ -106,15 +104,23 @@ export const stringifyStatic: HoistTransform = (children, context, parent) => {
String(currentChunk.length),
])

const deleteCount = currentChunk.length - 1

if (isParentCached) {
;((parent.codegenNode as VNodeCall).children as CacheExpression).value =
createArrayExpression([staticCall])
// if the parent is cached, then `children` is also the value of the
// CacheExpression. Just replace the corresponding range in the cached
// list with staticCall.
children.splice(
currentIndex - currentChunk.length,
currentChunk.length,
// @ts-expect-error
staticCall,
)
} else {
// replace the first node's hoisted expression with the static vnode call
;(currentChunk[0].codegenNode as CacheExpression).value = staticCall
if (currentChunk.length > 1) {
// remove merged nodes from children
const deleteCount = currentChunk.length - 1
children.splice(currentIndex - currentChunk.length + 1, deleteCount)
// also adjust index for the remaining cache items
const cacheIndex = context.cached.indexOf(
Expand All @@ -128,9 +134,9 @@ export const stringifyStatic: HoistTransform = (children, context, parent) => {
}
context.cached.splice(cacheIndex - deleteCount + 1, deleteCount)
}
return deleteCount
}
}
return deleteCount
}
return 0
}
Expand Down
32 changes: 32 additions & 0 deletions packages/compiler-sfc/__tests__/compileStyle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,38 @@ describe('SFC scoped CSS', () => {
)
})

test('nesting selector with atrule and comment', () => {
expect(
compileScoped(
`h1 {
color: red;
/*background-color: pink;*/
@media only screen and (max-width: 800px) {
background-color: green;
.bar { color: white }
}
.foo { color: red; }
}`,
),
).toMatch(
`h1 {
&[data-v-test] {
color: red
/*background-color: pink;*/
}
@media only screen and (max-width: 800px) {
&[data-v-test] {
background-color: green
}
.bar[data-v-test] { color: white
}
}
.foo[data-v-test] { color: red;
}
}`,
)
})

test('multiple selectors', () => {
expect(compileScoped(`h1 .foo, .bar, .baz { color: red; }`)).toMatch(
`h1 .foo[data-v-test], .bar[data-v-test], .baz[data-v-test] { color: red;`,
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-sfc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-sfc",
"version": "3.5.4",
"version": "3.5.5",
"description": "@vue/compiler-sfc",
"main": "dist/compiler-sfc.cjs.js",
"module": "dist/compiler-sfc.esm-browser.js",
Expand Down
31 changes: 22 additions & 9 deletions packages/compiler-sfc/src/style/pluginScoped.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,16 +233,12 @@ function rewriteSelector(

if (rule.nodes.some(node => node.type === 'rule')) {
const deep = (rule as any).__deep
const decls = rule.nodes.filter(node => node.type === 'decl')
if (!deep && decls.length) {
for (const decl of decls) {
rule.removeChild(decl)
if (!deep) {
extractAndWrapNodes(rule)
const atruleNodes = rule.nodes.filter(node => node.type === 'atrule')
for (const atnode of atruleNodes) {
extractAndWrapNodes(atnode)
}
const hostRule = new Rule({
nodes: decls,
selector: '&',
})
rule.prepend(hostRule)
}
shouldInject = deep
}
Expand Down Expand Up @@ -286,5 +282,22 @@ function isSpaceCombinator(node: selectorParser.Node) {
return node.type === 'combinator' && /^\s+$/.test(node.value)
}

function extractAndWrapNodes(parentNode: Rule | AtRule) {
if (!parentNode.nodes) return
const nodes = parentNode.nodes.filter(
node => node.type === 'decl' || node.type === 'comment',
)
if (nodes.length) {
for (const node of nodes) {
parentNode.removeChild(node)
}
const wrappedRule = new Rule({
nodes: nodes,
selector: '&',
})
parentNode.prepend(wrappedRule)
}
}

scopedPlugin.postcss = true
export default scopedPlugin
2 changes: 1 addition & 1 deletion packages/compiler-ssr/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vue/compiler-ssr",
"version": "3.5.4",
"version": "3.5.5",
"description": "@vue/compiler-ssr",
"main": "dist/compiler-ssr.cjs.js",
"types": "dist/compiler-ssr.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/reactivity/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@vue/reactivity",
"version": "3.5.4",
"version": "3.5.5",
"description": "@vue/reactivity",
"main": "index.js",
"module": "dist/reactivity.esm-bundler.js",
Expand Down
3 changes: 1 addition & 2 deletions packages/reactivity/src/computed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import {
type DebuggerEvent,
type DebuggerOptions,
EffectFlags,
type Link,
type Subscriber,
activeSub,
refreshComputed,
} from './effect'
import type { Ref } from './ref'
import { warn } from './warning'
import { Dep, globalVersion } from './dep'
import { Dep, type Link, globalVersion } from './dep'
import { ReactiveFlags, TrackOpTypes } from './constants'

declare const ComputedRefSymbol: unique symbol
Expand Down
Loading

0 comments on commit ccbcf1f

Please sign in to comment.