Browse Source

Merge remote-tracking branch 'upstream/minor'

三咲智子 Kevin Deng 1 year ago
parent
commit
4be49b2620

+ 21 - 0
CHANGELOG.md

@@ -1,3 +1,24 @@
+## [3.4.30](https://github.com/vuejs/core/compare/v3.4.29...v3.4.30) (2024-06-22)
+
+
+### Bug Fixes
+
+* **compiler-core:** should not remove slot node with `v-else` ([#11150](https://github.com/vuejs/core/issues/11150)) ([e102670](https://github.com/vuejs/core/commit/e102670bde00417c3a5b0262c855b297c0e4169e))
+* **hydration:** fix css vars hydration mismatch false positive on attr-fallthrough ([#11190](https://github.com/vuejs/core/issues/11190)) ([7ad67ce](https://github.com/vuejs/core/commit/7ad67ced26e5f53a47cb42f4834496e4958cb53b)), closes [#11188](https://github.com/vuejs/core/issues/11188)
+* **hydration:** skip prop mismatch check for directives that mutate DOM in created ([3169c91](https://github.com/vuejs/core/commit/3169c914939d02a013b2938aff30dac8525923f8)), closes [#11189](https://github.com/vuejs/core/issues/11189)
+* **reactivity:** fix side effect computed dirty level ([#11183](https://github.com/vuejs/core/issues/11183)) ([3bd79e3](https://github.com/vuejs/core/commit/3bd79e3e5ed960fc42cbf77bc61a97d2c03557c0)), closes [#11181](https://github.com/vuejs/core/issues/11181) [#11169](https://github.com/vuejs/core/issues/11169)
+* **runtime-core:** ensure unmount dynamic components in optimized mode ([#11171](https://github.com/vuejs/core/issues/11171)) ([220fe24](https://github.com/vuejs/core/commit/220fe247484209e62c7f4991902c5335e29c5007)), closes [#11168](https://github.com/vuejs/core/issues/11168)
+* **runtime-core:** update devtool __vnode on patch, avoid memory leak during dev ([a959781](https://github.com/vuejs/core/commit/a959781dd6f609dcb6f16dd7fa47d3b16895e5ca)), closes [#11192](https://github.com/vuejs/core/issues/11192)
+* **runtime-dom:** ensure only symbols are explicitly stringified during attribute patching ([#11182](https://github.com/vuejs/core/issues/11182)) ([a2e35d6](https://github.com/vuejs/core/commit/a2e35d682db15a592f4270bb0cde70a0e7bdc4a6)), closes [#11177](https://github.com/vuejs/core/issues/11177)
+* **runtime-dom:** prevent setting state as attribute for custom elements ([#11165](https://github.com/vuejs/core/issues/11165)) ([8ae4c29](https://github.com/vuejs/core/commit/8ae4c293adcec28f18114cb6016230a86787e6a9)), closes [#11163](https://github.com/vuejs/core/issues/11163)
+
+
+### Performance Improvements
+
+* **reactivity:** cache tracking value ([#11145](https://github.com/vuejs/core/issues/11145)) ([7936dae](https://github.com/vuejs/core/commit/7936daebceab2ae9461c3b8f256e51020fb7d3ed))
+
+
+
 ## [3.4.29](https://github.com/vuejs/core/compare/v3.4.28...v3.4.29) (2024-06-14)
 
 

+ 13 - 13
package.json

@@ -1,7 +1,7 @@
 {
   "private": true,
   "version": "3.0.0-vapor",
-  "packageManager": "pnpm@9.2.0",
+  "packageManager": "pnpm@9.3.0",
   "type": "module",
   "scripts": {
     "dev": "node scripts/dev.js vue vue-vapor",
@@ -67,25 +67,25 @@
     "@rollup/plugin-json": "^6.1.0",
     "@rollup/plugin-node-resolve": "^15.2.3",
     "@rollup/plugin-replace": "5.0.4",
-    "@rollup/plugin-terser": "^0.4.4",
+    "@swc/core": "^1.6.1",
     "@types/hash-sum": "^1.0.2",
     "@types/minimist": "^1.2.5",
     "@types/node": "^20.14.2",
     "@types/semver": "^7.5.8",
-    "@vitest/coverage-istanbul": "^1.5.2",
-    "@vitest/ui": "^1.5.2",
+    "@vitest/coverage-istanbul": "^1.6.0",
+    "@vitest/ui": "^1.6.0",
     "@vue/consolidate": "1.0.0",
     "conventional-changelog-cli": "^4.1.0",
     "enquirer": "^2.4.1",
     "esbuild": "^0.21.5",
     "esbuild-plugin-polyfill-node": "^0.3.0",
-    "eslint": "^9.4.0",
+    "eslint": "^9.5.0",
     "eslint-plugin-import-x": "^0.5.1",
     "eslint-plugin-vitest": "^0.5.4",
     "estree-walker": "^2.0.2",
     "execa": "^9.2.0",
-    "jsdom": "^24.0.0",
-    "lint-staged": "^15.2.5",
+    "jsdom": "^24.1.0",
+    "lint-staged": "^15.2.7",
     "lodash": "^4.17.21",
     "magic-string": "^0.30.10",
     "markdown-table": "^3.0.3",
@@ -93,10 +93,10 @@
     "minimist": "^1.2.8",
     "npm-run-all2": "^6.2.0",
     "picocolors": "^1.0.1",
-    "prettier": "^3.3.1",
+    "prettier": "^3.3.2",
     "pretty-bytes": "^6.1.1",
     "pug": "^3.0.3",
-    "puppeteer": "~22.7.1",
+    "puppeteer": "~22.11.0",
     "rimraf": "^5.0.7",
     "rollup": "^4.18.0",
     "rollup-plugin-dts": "^6.1.1",
@@ -108,11 +108,11 @@
     "terser": "^5.31.1",
     "todomvc-app-css": "^2.4.3",
     "tslib": "^2.6.3",
-    "tsx": "^4.15.1",
+    "tsx": "^4.15.5",
     "typescript": "~5.4.5",
-    "typescript-eslint": "^7.12.0",
-    "vite": "^5.2.13",
-    "vitest": "^1.5.2"
+    "typescript-eslint": "^7.13.0",
+    "vite": "^5.3.1",
+    "vitest": "^1.6.0"
   },
   "pnpm": {
     "peerDependencyRules": {

+ 1 - 0
packages/compiler-core/__tests__/transforms/vSlot.spec.ts

@@ -696,6 +696,7 @@ describe('compiler: transform component slots', () => {
     expect((root as any).children[0].codegenNode.patchFlag).toMatch(
       PatchFlags.DYNAMIC_SLOTS + '',
     )
+    expect((root as any).children[0].children.length).toBe(3)
     expect(generate(root).code).toMatchSnapshot()
   })
 

+ 1 - 3
packages/compiler-core/src/compat/transformFilter.ts

@@ -25,9 +25,7 @@ export const transformFilter: NodeTransform = (node, context) => {
     // filter rewrite is applied before expression transform so only
     // simple expressions are possible at this stage
     rewriteFilter(node.content, context)
-  }
-
-  if (node.type === NodeTypes.ELEMENT) {
+  } else if (node.type === NodeTypes.ELEMENT) {
     node.props.forEach((prop: AttributeNode | DirectiveNode) => {
       if (
         prop.type === NodeTypes.DIRECTIVE &&

+ 1 - 4
packages/compiler-core/src/transforms/vSlot.ts

@@ -226,10 +226,7 @@ export function buildSlots(
           break
         }
       }
-      if (prev && isTemplateNode(prev) && findDir(prev, 'if')) {
-        // remove node
-        children.splice(i, 1)
-        i--
+      if (prev && isTemplateNode(prev) && findDir(prev, /^(else-)?if$/)) {
         __TEST__ && assert(dynamicSlots.length > 0)
         // attach this slot to previous conditional
         let conditional = dynamicSlots[

+ 1 - 1
packages/compiler-sfc/package.json

@@ -63,6 +63,6 @@
     "postcss-modules": "^6.0.0",
     "postcss-selector-parser": "^6.1.0",
     "pug": "^3.0.3",
-    "sass": "^1.77.4"
+    "sass": "^1.77.5"
   }
 }

+ 51 - 0
packages/reactivity/__tests__/computed.spec.ts

@@ -853,6 +853,57 @@ describe('reactivity/computed', () => {
     expect(calls).toMatchObject(['b eval', 'mounted', 'b eval'])
   })
 
+  it('should chained computeds keep reactivity when computed effect happens', async () => {
+    const v = ref('Hello')
+    const c = computed(() => {
+      v.value += ' World'
+      return v.value
+    })
+    const d = computed(() => c.value)
+    const e = computed(() => d.value)
+    const Comp = {
+      setup: () => {
+        return () => d.value + ' | ' + e.value
+      },
+    }
+    const root = nodeOps.createElement('div')
+
+    render(h(Comp), root)
+    await nextTick()
+    expect(serializeInner(root)).toBe('Hello World | Hello World')
+
+    v.value += ' World'
+    await nextTick()
+    expect(serializeInner(root)).toBe(
+      'Hello World World World | Hello World World World',
+    )
+  })
+
+  it('should keep dirty level when side effect computed value changed', () => {
+    const v = ref(0)
+    const c = computed(() => {
+      v.value += 1
+      return v.value
+    })
+    const d = computed(() => {
+      return { d: c.value }
+    })
+
+    const Comp = {
+      setup: () => {
+        return () => {
+          return [d.value.d, d.value.d]
+        }
+      },
+    }
+
+    const root = nodeOps.createElement('div')
+    render(h(Comp), root)
+
+    expect(d.value.d).toBe(1)
+    expect(serializeInner(root)).toBe('11')
+  })
+
   it('debug: onTrigger (ref)', () => {
     let events: DebuggerEvent[] = []
     const onTrigger = vi.fn((e: DebuggerEvent) => {

+ 0 - 1
packages/runtime-core/__tests__/apiInject.spec.ts

@@ -13,7 +13,6 @@ import {
 } from '../src/index'
 import { createApp, nodeOps, render, serialize } from '@vue/runtime-test'
 
-// reference: https://vue-composition-api-rfc.netlify.com/api.html#provide-inject
 describe('api: provide/inject', () => {
   it('string keys', () => {
     const Provider = {

+ 0 - 2
packages/runtime-core/__tests__/apiLifecycle.spec.ts

@@ -24,8 +24,6 @@ import {
   TriggerOpTypes,
 } from '@vue/reactivity'
 
-// reference: https://vue-composition-api-rfc.netlify.com/api.html#lifecycle-hooks
-
 describe('api: lifecycle hooks', () => {
   it('onBeforeMount', () => {
     const root = nodeOps.createElement('div')

+ 0 - 2
packages/runtime-core/__tests__/apiSetupContext.spec.ts

@@ -12,8 +12,6 @@ import {
   watchEffect,
 } from '@vue/runtime-test'
 
-// reference: https://vue-composition-api-rfc.netlify.com/api.html#setup
-
 describe('api: setup context', () => {
   it('should expose return values to template render context', () => {
     const Comp = defineComponent({

+ 0 - 2
packages/runtime-core/__tests__/apiWatch.spec.ts

@@ -37,8 +37,6 @@ import {
   triggerRef,
 } from '@vue/reactivity'
 
-// reference: https://vue-composition-api-rfc.netlify.com/api.html#watch
-
 describe('api: watch', () => {
   it('effect', async () => {
     const state = reactive({ count: 0 })

+ 41 - 0
packages/runtime-core/__tests__/hydration.spec.ts

@@ -3,6 +3,7 @@
  */
 
 import {
+  type ObjectDirective,
   Suspense,
   Teleport,
   Transition,
@@ -1674,5 +1675,45 @@ describe('SSR hydration', () => {
       app.mount(container)
       expect(`Hydration style mismatch`).not.toHaveBeenWarned()
     })
+
+    // #11188
+    test('css vars support fallthrough', () => {
+      const container = document.createElement('div')
+      container.innerHTML = `<div style="padding: 4px;--foo:red;"></div>`
+      const app = createSSRApp({
+        setup() {
+          useCssVars(() => ({
+            foo: 'red',
+          }))
+          return () => h(Child)
+        },
+      })
+      const Child = {
+        setup() {
+          return () => h('div', { style: 'padding: 4px' })
+        },
+      }
+      app.mount(container)
+      expect(`Hydration style mismatch`).not.toHaveBeenWarned()
+    })
+
+    // #11189
+    test('should not warn for directives that mutate DOM in created', () => {
+      const container = document.createElement('div')
+      container.innerHTML = `<div class="test red"></div>`
+      const vColor: ObjectDirective = {
+        created(el, binding) {
+          el.classList.add(binding.value)
+        },
+      }
+      const app = createSSRApp({
+        setup() {
+          return () =>
+            withDirectives(h('div', { class: 'test' }), [[vColor, 'red']])
+        },
+      })
+      app.mount(container)
+      expect(`Hydration style mismatch`).not.toHaveBeenWarned()
+    })
   })
 })

+ 26 - 0
packages/runtime-core/__tests__/rendererOptimizedMode.spec.ts

@@ -487,6 +487,32 @@ describe('renderer: optimized mode', () => {
     expect(spy).toHaveBeenCalledTimes(1)
   })
 
+  test('should call onUnmounted hook for dynamic components receiving an existing vnode w/ component children', async () => {
+    const spy = vi.fn()
+    const show = ref(1)
+    const Child = {
+      setup() {
+        onUnmounted(spy)
+        return () => 'child'
+      },
+    }
+    const foo = h('div', null, h(Child))
+    const app = createApp({
+      render() {
+        return show.value
+          ? (openBlock(),
+            createBlock('div', null, [(openBlock(), createBlock(foo))]))
+          : createCommentVNode('v-if', true)
+      },
+    })
+
+    app.mount(root)
+    show.value = 0
+    await nextTick()
+
+    expect(spy).toHaveBeenCalledTimes(1)
+  })
+
   // #2444
   // `KEYED_FRAGMENT` and `UNKEYED_FRAGMENT` always need to diff its children
   test('non-stable Fragment always need to diff its children', () => {

+ 0 - 2
packages/runtime-core/__tests__/rendererTemplateRef.spec.ts

@@ -10,8 +10,6 @@ import {
   shallowRef,
 } from '@vue/runtime-test'
 
-// reference: https://vue-composition-api-rfc.netlify.com/api.html#template-refs
-
 describe('api: template refs', () => {
   it('string ref mount', () => {
     const root = nodeOps.createElement('div')

+ 0 - 1
packages/runtime-core/src/components/Suspense.ts

@@ -123,7 +123,6 @@ export const SuspenseImpl = {
     }
   },
   hydrate: hydrateSuspense,
-  create: createSuspenseBoundary,
   normalize: normalizeSuspenseChildren,
 }
 

+ 0 - 1
packages/runtime-core/src/components/Teleport.ts

@@ -250,7 +250,6 @@ export const TeleportImpl = {
     vnode: VNode,
     parentComponent: ComponentInternalInstance | null,
     parentSuspense: SuspenseBoundary | null,
-    optimized: boolean,
     { um: unmount, o: { remove: hostRemove } }: RendererInternals,
     doRemove: boolean,
   ) {

+ 33 - 28
packages/runtime-core/src/hydration.ts

@@ -17,6 +17,7 @@ import { warn } from './warning'
 import {
   PatchFlags,
   ShapeFlags,
+  def,
   includeBooleanAttr,
   isBooleanAttr,
   isKnownHtmlAttr,
@@ -141,18 +142,8 @@ export function createHydrationFunctions(
     vnode.el = node
 
     if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
-      if (!('__vnode' in node)) {
-        Object.defineProperty(node, '__vnode', {
-          value: vnode,
-          enumerable: false,
-        })
-      }
-      if (!('__vueParentComponent' in node)) {
-        Object.defineProperty(node, '__vueParentComponent', {
-          value: parentComponent,
-          enumerable: false,
-        })
-      }
+      def(node, '__vnode', vnode, true)
+      def(node, '__vueParentComponent', parentComponent, true)
     }
 
     if (patchFlag === PatchFlags.BAIL) {
@@ -459,6 +450,9 @@ export function createHydrationFunctions(
             // check hydration mismatch
             if (
               (__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
+              // #11189 skip if this node has directives that have created hooks
+              // as it could have mutated the DOM in any possible way
+              !(dirs && dirs.some(d => d.dir.created)) &&
               propHasMismatch(el, key, props[key], vnode, parentComponent)
             ) {
               logMismatchError()
@@ -766,18 +760,8 @@ function propHasMismatch(
       }
     }
 
-    // eslint-disable-next-line no-restricted-syntax
-    const root = instance?.subTree
-    if (
-      vnode === root ||
-      // eslint-disable-next-line no-restricted-syntax
-      (root?.type === Fragment && (root.children as VNode[]).includes(vnode))
-    ) {
-      // eslint-disable-next-line no-restricted-syntax
-      const cssVars = instance?.getCssVars?.()
-      for (const key in cssVars) {
-        expectedMap.set(`--${key}`, String(cssVars[key]))
-      }
+    if (instance) {
+      resolveCssVars(instance, vnode, expectedMap)
     }
 
     if (!isMapEqual(actualMap, expectedMap)) {
@@ -854,10 +838,8 @@ function toStyleMap(str: string): Map<string, string> {
   const styleMap: Map<string, string> = new Map()
   for (const item of str.split(';')) {
     let [key, value] = item.split(':')
-    // eslint-disable-next-line no-restricted-syntax
-    key = key?.trim()
-    // eslint-disable-next-line no-restricted-syntax
-    value = value?.trim()
+    key = key.trim()
+    value = value && value.trim()
     if (key && value) {
       styleMap.set(key, value)
     }
@@ -876,3 +858,26 @@ function isMapEqual(a: Map<string, string>, b: Map<string, string>): boolean {
   }
   return true
 }
+
+function resolveCssVars(
+  instance: ComponentInternalInstance,
+  vnode: VNode,
+  expectedMap: Map<string, string>,
+) {
+  const root = instance.subTree
+  if (
+    instance.getCssVars &&
+    (vnode === root ||
+      (root &&
+        root.type === Fragment &&
+        (root.children as VNode[]).includes(vnode)))
+  ) {
+    const cssVars = instance.getCssVars()
+    for (const key in cssVars) {
+      expectedMap.set(`--${key}`, String(cssVars[key]))
+    }
+  }
+  if (vnode === root && instance.parent) {
+    resolveCssVars(instance.parent, instance.vnode, expectedMap)
+  }
+}

+ 12 - 9
packages/runtime-core/src/renderer.ts

@@ -32,6 +32,7 @@ import {
   NOOP,
   PatchFlags,
   ShapeFlags,
+  def,
   getGlobalThis,
   invokeArrayFns,
   isArray,
@@ -715,15 +716,10 @@ function baseCreateRenderer(
     }
 
     if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
-      Object.defineProperty(el, '__vnode', {
-        value: vnode,
-        enumerable: false,
-      })
-      Object.defineProperty(el, '__vueParentComponent', {
-        value: parentComponent,
-        enumerable: false,
-      })
+      def(el, '__vnode', vnode, true)
+      def(el, '__vueParentComponent', parentComponent, true)
     }
+
     if (dirs) {
       invokeDirectiveHook(vnode, null, parentComponent, 'beforeMount')
     }
@@ -824,6 +820,9 @@ function baseCreateRenderer(
     optimized: boolean,
   ) => {
     const el = (n2.el = n1.el!)
+    if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
+      el.__vnode = n2
+    }
     let { patchFlag, dynamicChildren, dirs } = n2
     // #1426 take the old vnode's patch flag into account since user may clone a
     // compiler-generated vnode, which de-opts to FULL_PROPS
@@ -2126,6 +2125,11 @@ function baseCreateRenderer(
       dirs,
       memoIndex,
     } = vnode
+
+    if (patchFlag === PatchFlags.BAIL) {
+      optimized = false
+    }
+
     // unset ref
     if (ref != null) {
       setRef(ref, null, parentSuspense, vnode, true)
@@ -2169,7 +2173,6 @@ function baseCreateRenderer(
           vnode,
           parentComponent,
           parentSuspense,
-          optimized,
           internals,
           doRemove,
         )

+ 8 - 0
packages/runtime-dom/__tests__/customElement.spec.ts

@@ -9,6 +9,7 @@ import {
   inject,
   nextTick,
   ref,
+  render,
   renderSlot,
 } from '../src'
 
@@ -141,6 +142,7 @@ describe('defineCustomElement', () => {
         foo: [String, null],
         bar: Object,
         bazQux: null,
+        value: null,
       },
       render() {
         return [
@@ -151,6 +153,12 @@ describe('defineCustomElement', () => {
     })
     customElements.define('my-el-props', E)
 
+    test('renders custom element w/ correct object prop value', () => {
+      render(h('my-el-props', { value: { x: 1 } }), container)
+      const el = container.children[0]
+      expect((el as any).value).toEqual({ x: 1 })
+    })
+
     test('props via attribute', async () => {
       // bazQux should map to `baz-qux` attribute
       container.innerHTML = `<my-el-props foo="hello" baz-qux="bye"></my-el-props>`

+ 19 - 0
packages/runtime-dom/__tests__/patchAttrs.spec.ts

@@ -69,4 +69,23 @@ describe('runtime-dom: attrs patching', () => {
     patchProp(el, 'value', null, symbol)
     expect(el.value).toBe(symbol.toString())
   })
+
+  // #11177
+  test('should allow setting value to object, leaving stringification to the element/browser', () => {
+    // normal behavior
+    const el = document.createElement('div')
+    const obj = { toString: () => 'foo' }
+    patchProp(el, 'data-test', null, obj)
+    expect(el.dataset.test).toBe('foo')
+
+    const el2 = document.createElement('div')
+    let testvalue: null | typeof obj = null
+    // simulating a web component that implements its own setAttribute handler
+    el2.setAttribute = (name, value) => {
+      testvalue = value
+    }
+    patchProp(el2, 'data-test', null, obj)
+    expect(el2.dataset.test).toBe(undefined)
+    expect(testvalue).toBe(obj)
+  })
 })

+ 5 - 1
packages/runtime-dom/src/modules/attrs.ts

@@ -2,6 +2,7 @@ import {
   NOOP,
   includeBooleanAttr,
   isSpecialBooleanAttr,
+  isSymbol,
   makeMap,
 } from '@vue/shared'
 import {
@@ -37,7 +38,10 @@ export function patchAttr(
       el.removeAttribute(key)
     } else {
       // attribute value is a string https://html.spec.whatwg.org/multipage/dom.html#attributes
-      el.setAttribute(key, isBoolean ? '' : String(value))
+      el.setAttribute(
+        key,
+        isBoolean ? '' : isSymbol(value) ? String(value) : value,
+      )
     }
   }
 }

+ 5 - 1
packages/runtime-dom/src/patchProp.ts

@@ -53,7 +53,11 @@ export const patchProp: DOMRendererOptions['patchProp'] = (
     )
     // #6007 also set form state as attributes so they work with
     // <input type="reset"> or libs / extensions that expect attributes
-    if (key === 'value' || key === 'checked' || key === 'selected') {
+    // #11163 custom elements may use value as an prop and set it as object
+    if (
+      !el.tagName.includes('-') &&
+      (key === 'value' || key === 'checked' || key === 'selected')
+    ) {
       patchAttr(el, key, nextValue, isSVG, parentComponent, key !== 'value')
     }
   } else {

+ 1 - 1
packages/sfc-playground/package.json

@@ -10,7 +10,7 @@
   },
   "devDependencies": {
     "@vitejs/plugin-vue": "^5.0.5",
-    "vite": "^5.2.13"
+    "vite": "^5.3.1"
   },
   "dependencies": {
     "@vue/repl": "^4.2.1",

+ 1 - 1
packages/sfc-playground/src/download/template/package.json

@@ -12,6 +12,6 @@
   },
   "devDependencies": {
     "@vitejs/plugin-vue": "^5.0.5",
-    "vite": "^5.2.13"
+    "vite": "^5.3.1"
   }
 }

File diff suppressed because it is too large
+ 297 - 215
pnpm-lock.yaml


+ 19 - 8
rollup.config.js

@@ -9,11 +9,11 @@ import pico from 'picocolors'
 import commonJS from '@rollup/plugin-commonjs'
 import polyfillNode from 'rollup-plugin-polyfill-node'
 import { nodeResolve } from '@rollup/plugin-node-resolve'
-import terser from '@rollup/plugin-terser'
 import esbuild from 'rollup-plugin-esbuild'
 import alias from '@rollup/plugin-alias'
 import { entries } from './scripts/aliases.js'
 import { inlineEnums } from './scripts/inline-enums.js'
+import { minify as minifySwc } from '@swc/core'
 
 /**
  * @template T
@@ -366,14 +366,25 @@ function createMinifiedConfig(/** @type {PackageFormat} */ format) {
       file: outputConfigs[format].file.replace(/\.js$/, '.prod.js'),
     },
     [
-      terser({
-        module: /^esm/.test(format),
-        compress: {
-          ecma: 2016,
-          pure_getters: true,
+      {
+        name: 'swc-minify',
+
+        async renderChunk(
+          contents,
+          _,
+          { format, sourcemap, sourcemapExcludeSources },
+        ) {
+          const { code, map } = await minifySwc(contents, {
+            module: format === 'es',
+            compress: true,
+            mangle: true,
+            sourceMap: !!sourcemap,
+            inlineSourcesContent: !sourcemapExcludeSources,
+          })
+
+          return { code, map: map || null }
         },
-        safari10: true,
-      }),
+      },
     ],
   )
 }

+ 1 - 1
scripts/verify-treeshaking.js

@@ -14,7 +14,7 @@ execa('pnpm', ['build', 'vue', '-f', 'global-runtime']).then(() => {
     errors.push(
       'dev build contains unexpected esbuild object spread helper.\n' +
         'This means { ...obj } syntax is used in runtime code. This should be ' +
-        'refactoed to use the `extend` helper to avoid the extra code.',
+        'refactored to use the `extend` helper to avoid the extra code.',
     )
   }
 

Some files were not shown because too many files changed in this diff