├── .git-blame-ignore-revs
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ └── config.yml
├── bug-repro-guidelines.md
├── commit-convention.md
├── contributing.md
├── git-branch-workflow.excalidraw
├── git-branch-workflow.png
├── issue-workflow.png
├── maintenance.md
├── renovate.json5
└── workflows
│ ├── autofix.yml
│ ├── canary-minor.yml
│ ├── canary.yml
│ ├── ci.yml
│ ├── close-cant-reproduce-issues.yml
│ ├── ecosystem-ci-trigger.yml
│ ├── lock-closed-issues.yml
│ ├── release.yml
│ ├── size-data.yml
│ ├── size-report.yml
│ └── test.yml
├── .gitignore
├── .node-version
├── .prettierignore
├── .prettierrc
├── .vscode
├── extensions.json
├── launch.json
└── settings.json
├── BACKERS.md
├── CHANGELOG.md
├── FUNDING.json
├── LICENSE
├── README.md
├── SECURITY.md
├── changelogs
├── CHANGELOG-3.0.md
├── CHANGELOG-3.1.md
├── CHANGELOG-3.2.md
├── CHANGELOG-3.3.md
└── CHANGELOG-3.4.md
├── eslint.config.js
├── netlify.toml
├── package.json
├── packages-private
├── dts-built-test
│ ├── README.md
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ └── tsconfig.json
├── dts-test
│ ├── README.md
│ ├── appDirective.test-d.ts
│ ├── appUse.test-d.ts
│ ├── built.test-d.ts
│ ├── compiler.test-d.ts
│ ├── component.test-d.ts
│ ├── componentInstance.test-d.tsx
│ ├── componentTypeExtensions.test-d.tsx
│ ├── defineComponent.test-d.tsx
│ ├── defineCustomElement.test-d.ts
│ ├── directives.test-d.ts
│ ├── extractProps.test-d.ts
│ ├── functionalComponent.test-d.tsx
│ ├── h.test-d.ts
│ ├── inject.test-d.ts
│ ├── package.json
│ ├── reactivity.test-d.ts
│ ├── ref.test-d.ts
│ ├── setupHelpers.test-d.ts
│ ├── tsconfig.test.json
│ ├── tsx.test-d.tsx
│ ├── utils.d.ts
│ └── watch.test-d.ts
├── sfc-playground
│ ├── README.md
│ ├── index.html
│ ├── package.json
│ ├── public
│ │ └── logo.svg
│ ├── src
│ │ ├── App.vue
│ │ ├── Header.vue
│ │ ├── VersionSelect.vue
│ │ ├── download
│ │ │ ├── download.ts
│ │ │ └── template
│ │ │ │ ├── README.md
│ │ │ │ ├── index.html
│ │ │ │ ├── main.js
│ │ │ │ ├── package.json
│ │ │ │ └── vite.config.js
│ │ ├── icons
│ │ │ ├── Copy.vue
│ │ │ ├── Download.vue
│ │ │ ├── GitHub.vue
│ │ │ ├── Moon.vue
│ │ │ ├── Reload.vue
│ │ │ ├── Share.vue
│ │ │ └── Sun.vue
│ │ ├── main.ts
│ │ ├── vue-dev-proxy-prod.ts
│ │ ├── vue-dev-proxy.ts
│ │ └── vue-server-renderer-dev-proxy.ts
│ ├── vercel.json
│ └── vite.config.ts
├── template-explorer
│ ├── README.md
│ ├── _redirects
│ ├── index.html
│ ├── local.html
│ ├── package.json
│ ├── src
│ │ ├── index.ts
│ │ ├── options.ts
│ │ └── theme.ts
│ └── style.css
└── vite-debug
│ ├── App.vue
│ ├── README.md
│ ├── index.html
│ ├── main.ts
│ ├── package.json
│ ├── tsconfig.json
│ └── vite.config.ts
├── packages
├── compiler-core
│ ├── LICENSE
│ ├── README.md
│ ├── __tests__
│ │ ├── __snapshots__
│ │ │ ├── codegen.spec.ts.snap
│ │ │ ├── compile.spec.ts.snap
│ │ │ ├── parse.spec.ts.snap
│ │ │ └── scopeId.spec.ts.snap
│ │ ├── codegen.spec.ts
│ │ ├── compile.spec.ts
│ │ ├── parse.spec.ts
│ │ ├── scopeId.spec.ts
│ │ ├── testUtils.ts
│ │ ├── transform.spec.ts
│ │ ├── transforms
│ │ │ ├── __snapshots__
│ │ │ │ ├── cacheStatic.spec.ts.snap
│ │ │ │ ├── transformElement.spec.ts.snap
│ │ │ │ ├── transformExpressions.spec.ts.snap
│ │ │ │ ├── transformText.spec.ts.snap
│ │ │ │ ├── vFor.spec.ts.snap
│ │ │ │ ├── vIf.spec.ts.snap
│ │ │ │ ├── vMemo.spec.ts.snap
│ │ │ │ ├── vModel.spec.ts.snap
│ │ │ │ ├── vOnce.spec.ts.snap
│ │ │ │ └── vSlot.spec.ts.snap
│ │ │ ├── cacheStatic.spec.ts
│ │ │ ├── noopDirectiveTransform.spec.ts
│ │ │ ├── transformElement.spec.ts
│ │ │ ├── transformExpressions.spec.ts
│ │ │ ├── transformSlotOutlet.spec.ts
│ │ │ ├── transformText.spec.ts
│ │ │ ├── vBind.spec.ts
│ │ │ ├── vFor.spec.ts
│ │ │ ├── vIf.spec.ts
│ │ │ ├── vMemo.spec.ts
│ │ │ ├── vModel.spec.ts
│ │ │ ├── vOn.spec.ts
│ │ │ ├── vOnce.spec.ts
│ │ │ └── vSlot.spec.ts
│ │ └── utils.spec.ts
│ ├── index.js
│ ├── package.json
│ └── src
│ │ ├── ast.ts
│ │ ├── babelUtils.ts
│ │ ├── codegen.ts
│ │ ├── compat
│ │ ├── compatConfig.ts
│ │ └── transformFilter.ts
│ │ ├── compile.ts
│ │ ├── errors.ts
│ │ ├── index.ts
│ │ ├── options.ts
│ │ ├── parser.ts
│ │ ├── runtimeHelpers.ts
│ │ ├── tokenizer.ts
│ │ ├── transform.ts
│ │ ├── transforms
│ │ ├── cacheStatic.ts
│ │ ├── noopDirectiveTransform.ts
│ │ ├── transformElement.ts
│ │ ├── transformExpression.ts
│ │ ├── transformSlotOutlet.ts
│ │ ├── transformText.ts
│ │ ├── vBind.ts
│ │ ├── vFor.ts
│ │ ├── vIf.ts
│ │ ├── vMemo.ts
│ │ ├── vModel.ts
│ │ ├── vOn.ts
│ │ ├── vOnce.ts
│ │ └── vSlot.ts
│ │ ├── utils.ts
│ │ └── validateExpression.ts
├── compiler-dom
│ ├── LICENSE
│ ├── README.md
│ ├── __tests__
│ │ ├── __snapshots__
│ │ │ └── index.spec.ts.snap
│ │ ├── decoderHtmlBrowser.spec.ts
│ │ ├── index.spec.ts
│ │ ├── parse.spec.ts
│ │ └── transforms
│ │ │ ├── Transition.spec.ts
│ │ │ ├── __snapshots__
│ │ │ ├── Transition.spec.ts.snap
│ │ │ ├── stringifyStatic.spec.ts.snap
│ │ │ ├── vModel.spec.ts.snap
│ │ │ └── vShow.spec.ts.snap
│ │ │ ├── ignoreSideEffectTags.spec.ts
│ │ │ ├── stringifyStatic.spec.ts
│ │ │ ├── transformStyle.spec.ts
│ │ │ ├── vHtml.spec.ts
│ │ │ ├── vModel.spec.ts
│ │ │ ├── vOn.spec.ts
│ │ │ ├── vShow.spec.ts
│ │ │ ├── vText.spec.ts
│ │ │ └── validateHtmlNesting.spec.ts
│ ├── index.js
│ ├── package.json
│ └── src
│ │ ├── decodeHtmlBrowser.ts
│ │ ├── errors.ts
│ │ ├── htmlNesting.ts
│ │ ├── index.ts
│ │ ├── parserOptions.ts
│ │ ├── runtimeHelpers.ts
│ │ └── transforms
│ │ ├── Transition.ts
│ │ ├── ignoreSideEffectTags.ts
│ │ ├── stringifyStatic.ts
│ │ ├── transformStyle.ts
│ │ ├── vHtml.ts
│ │ ├── vModel.ts
│ │ ├── vOn.ts
│ │ ├── vShow.ts
│ │ ├── vText.ts
│ │ └── validateHtmlNesting.ts
├── compiler-sfc
│ ├── LICENSE
│ ├── README.md
│ ├── __tests__
│ │ ├── __snapshots__
│ │ │ ├── compileScript.spec.ts.snap
│ │ │ ├── compileTemplate.spec.ts.snap
│ │ │ ├── cssVars.spec.ts.snap
│ │ │ ├── templateTransformAssetUrl.spec.ts.snap
│ │ │ └── templateTransformSrcset.spec.ts.snap
│ │ ├── compileScript.spec.ts
│ │ ├── compileScript
│ │ │ ├── __snapshots__
│ │ │ │ ├── defineEmits.spec.ts.snap
│ │ │ │ ├── defineExpose.spec.ts.snap
│ │ │ │ ├── defineModel.spec.ts.snap
│ │ │ │ ├── defineOptions.spec.ts.snap
│ │ │ │ ├── defineProps.spec.ts.snap
│ │ │ │ ├── definePropsDestructure.spec.ts.snap
│ │ │ │ ├── defineSlots.spec.ts.snap
│ │ │ │ ├── hoistStatic.spec.ts.snap
│ │ │ │ └── importUsageCheck.spec.ts.snap
│ │ │ ├── defineEmits.spec.ts
│ │ │ ├── defineExpose.spec.ts
│ │ │ ├── defineModel.spec.ts
│ │ │ ├── defineOptions.spec.ts
│ │ │ ├── defineProps.spec.ts
│ │ │ ├── definePropsDestructure.spec.ts
│ │ │ ├── defineSlots.spec.ts
│ │ │ ├── hoistStatic.spec.ts
│ │ │ ├── importUsageCheck.spec.ts
│ │ │ └── resolveType.spec.ts
│ │ ├── compileStyle.spec.ts
│ │ ├── compileTemplate.spec.ts
│ │ ├── cssVars.spec.ts
│ │ ├── fixture
│ │ │ └── import.scss
│ │ ├── parse.spec.ts
│ │ ├── rewriteDefault.spec.ts
│ │ ├── templateTransformAssetUrl.spec.ts
│ │ ├── templateTransformSrcset.spec.ts
│ │ ├── templateUtils.spec.ts
│ │ └── utils.ts
│ ├── package.json
│ └── src
│ │ ├── cache.ts
│ │ ├── compileScript.ts
│ │ ├── compileStyle.ts
│ │ ├── compileTemplate.ts
│ │ ├── index.ts
│ │ ├── parse.ts
│ │ ├── rewriteDefault.ts
│ │ ├── script
│ │ ├── analyzeScriptBindings.ts
│ │ ├── context.ts
│ │ ├── defineEmits.ts
│ │ ├── defineExpose.ts
│ │ ├── defineModel.ts
│ │ ├── defineOptions.ts
│ │ ├── defineProps.ts
│ │ ├── definePropsDestructure.ts
│ │ ├── defineSlots.ts
│ │ ├── importUsageCheck.ts
│ │ ├── normalScript.ts
│ │ ├── resolveType.ts
│ │ ├── topLevelAwait.ts
│ │ └── utils.ts
│ │ ├── shims.d.ts
│ │ ├── style
│ │ ├── cssVars.ts
│ │ ├── pluginScoped.ts
│ │ ├── pluginTrim.ts
│ │ └── preprocessors.ts
│ │ ├── template
│ │ ├── templateUtils.ts
│ │ ├── transformAssetUrl.ts
│ │ └── transformSrcset.ts
│ │ └── warn.ts
├── compiler-ssr
│ ├── LICENSE
│ ├── README.md
│ ├── __tests__
│ │ ├── ssrComponent.spec.ts
│ │ ├── ssrElement.spec.ts
│ │ ├── ssrFallthroughAttrs.spec.ts
│ │ ├── ssrInjectCssVars.spec.ts
│ │ ├── ssrPortal.spec.ts
│ │ ├── ssrScopeId.spec.ts
│ │ ├── ssrSlotOutlet.spec.ts
│ │ ├── ssrSuspense.spec.ts
│ │ ├── ssrText.spec.ts
│ │ ├── ssrTransition.spec.ts
│ │ ├── ssrTransitionGroup.spec.ts
│ │ ├── ssrVFor.spec.ts
│ │ ├── ssrVIf.spec.ts
│ │ ├── ssrVModel.spec.ts
│ │ ├── ssrVShow.spec.ts
│ │ └── utils.ts
│ ├── package.json
│ └── src
│ │ ├── errors.ts
│ │ ├── index.ts
│ │ ├── runtimeHelpers.ts
│ │ ├── ssrCodegenTransform.ts
│ │ └── transforms
│ │ ├── ssrInjectCssVars.ts
│ │ ├── ssrInjectFallthroughAttrs.ts
│ │ ├── ssrTransformComponent.ts
│ │ ├── ssrTransformElement.ts
│ │ ├── ssrTransformSlotOutlet.ts
│ │ ├── ssrTransformSuspense.ts
│ │ ├── ssrTransformTeleport.ts
│ │ ├── ssrTransformTransition.ts
│ │ ├── ssrTransformTransitionGroup.ts
│ │ ├── ssrVFor.ts
│ │ ├── ssrVIf.ts
│ │ ├── ssrVModel.ts
│ │ └── ssrVShow.ts
├── global.d.ts
├── reactivity
│ ├── LICENSE
│ ├── README.md
│ ├── __benchmarks__
│ │ ├── computed.bench.ts
│ │ ├── effect.bench.ts
│ │ ├── reactiveArray.bench.ts
│ │ ├── reactiveMap.bench.ts
│ │ ├── reactiveObject.bench.ts
│ │ └── ref.bench.ts
│ ├── __tests__
│ │ ├── collections
│ │ │ ├── Map.spec.ts
│ │ │ ├── Set.spec.ts
│ │ │ ├── WeakMap.spec.ts
│ │ │ ├── WeakSet.spec.ts
│ │ │ └── shallowReadonly.spec.ts
│ │ ├── computed.spec.ts
│ │ ├── effect.spec.ts
│ │ ├── effectScope.spec.ts
│ │ ├── gc.spec.ts
│ │ ├── reactive.spec.ts
│ │ ├── reactiveArray.spec.ts
│ │ ├── readonly.spec.ts
│ │ ├── ref.spec.ts
│ │ ├── shallowReactive.spec.ts
│ │ └── shallowReadonly.spec.ts
│ ├── index.js
│ ├── package.json
│ └── src
│ │ ├── arrayInstrumentations.ts
│ │ ├── baseHandlers.ts
│ │ ├── collectionHandlers.ts
│ │ ├── computed.ts
│ │ ├── constants.ts
│ │ ├── dep.ts
│ │ ├── effect.ts
│ │ ├── effectScope.ts
│ │ ├── index.ts
│ │ ├── reactive.ts
│ │ ├── ref.ts
│ │ └── warning.ts
├── runtime-core
│ ├── LICENSE
│ ├── README.md
│ ├── __tests__
│ │ ├── apiAsyncComponent.spec.ts
│ │ ├── apiCreateApp.spec.ts
│ │ ├── apiExpose.spec.ts
│ │ ├── apiInject.spec.ts
│ │ ├── apiLifecycle.spec.ts
│ │ ├── apiOptions.spec.ts
│ │ ├── apiSetupContext.spec.ts
│ │ ├── apiSetupHelpers.spec.ts
│ │ ├── apiWatch.bench.ts
│ │ ├── apiWatch.spec.ts
│ │ ├── componentEmits.spec.ts
│ │ ├── componentProps.spec.ts
│ │ ├── componentPublicInstance.spec.ts
│ │ ├── componentSlots.spec.ts
│ │ ├── components
│ │ │ ├── BaseTransition.spec.ts
│ │ │ ├── KeepAlive.spec.ts
│ │ │ ├── Suspense.spec.ts
│ │ │ └── Teleport.spec.ts
│ │ ├── directives.spec.ts
│ │ ├── errorHandling.spec.ts
│ │ ├── h.spec.ts
│ │ ├── helpers
│ │ │ ├── createSlots.spec.ts
│ │ │ ├── renderList.spec.ts
│ │ │ ├── renderSlot.spec.ts
│ │ │ ├── resolveAssets.spec.ts
│ │ │ ├── toHandlers.spec.ts
│ │ │ ├── useId.spec.ts
│ │ │ ├── useModel.spec.ts
│ │ │ ├── useTemplateRef.spec.ts
│ │ │ └── withMemo.spec.ts
│ │ ├── hmr.spec.ts
│ │ ├── hydration.spec.ts
│ │ ├── misc.spec.ts
│ │ ├── rendererAttrsFallthrough.spec.ts
│ │ ├── rendererChildren.spec.ts
│ │ ├── rendererComponent.spec.ts
│ │ ├── rendererElement.spec.ts
│ │ ├── rendererFragment.spec.ts
│ │ ├── rendererOptimizedMode.spec.ts
│ │ ├── rendererTemplateRef.spec.ts
│ │ ├── scheduler.spec.ts
│ │ ├── scopeId.spec.ts
│ │ ├── vnode.spec.ts
│ │ └── vnodeHooks.spec.ts
│ ├── index.js
│ ├── package.json
│ ├── src
│ │ ├── apiAsyncComponent.ts
│ │ ├── apiComputed.ts
│ │ ├── apiCreateApp.ts
│ │ ├── apiDefineComponent.ts
│ │ ├── apiInject.ts
│ │ ├── apiLifecycle.ts
│ │ ├── apiSetupHelpers.ts
│ │ ├── apiWatch.ts
│ │ ├── compat
│ │ │ ├── attrsFallthrough.ts
│ │ │ ├── compatConfig.ts
│ │ │ ├── component.ts
│ │ │ ├── componentAsync.ts
│ │ │ ├── componentFunctional.ts
│ │ │ ├── componentVModel.ts
│ │ │ ├── customDirective.ts
│ │ │ ├── data.ts
│ │ │ ├── global.ts
│ │ │ ├── globalConfig.ts
│ │ │ ├── instance.ts
│ │ │ ├── instanceChildren.ts
│ │ │ ├── instanceEventEmitter.ts
│ │ │ ├── instanceListeners.ts
│ │ │ ├── props.ts
│ │ │ ├── renderFn.ts
│ │ │ └── renderHelpers.ts
│ │ ├── component.ts
│ │ ├── componentEmits.ts
│ │ ├── componentOptions.ts
│ │ ├── componentProps.ts
│ │ ├── componentPublicInstance.ts
│ │ ├── componentRenderContext.ts
│ │ ├── componentRenderUtils.ts
│ │ ├── componentSlots.ts
│ │ ├── components
│ │ │ ├── BaseTransition.ts
│ │ │ ├── KeepAlive.ts
│ │ │ ├── Suspense.ts
│ │ │ └── Teleport.ts
│ │ ├── customFormatter.ts
│ │ ├── devtools.ts
│ │ ├── directives.ts
│ │ ├── enums.ts
│ │ ├── errorHandling.ts
│ │ ├── featureFlags.ts
│ │ ├── h.ts
│ │ ├── helpers
│ │ │ ├── createSlots.ts
│ │ │ ├── renderList.ts
│ │ │ ├── renderSlot.ts
│ │ │ ├── resolveAssets.ts
│ │ │ ├── toHandlers.ts
│ │ │ ├── useId.ts
│ │ │ ├── useModel.ts
│ │ │ ├── useSsrContext.ts
│ │ │ ├── useTemplateRef.ts
│ │ │ └── withMemo.ts
│ │ ├── hmr.ts
│ │ ├── hydration.ts
│ │ ├── hydrationStrategies.ts
│ │ ├── index.ts
│ │ ├── internalObject.ts
│ │ ├── profiling.ts
│ │ ├── renderer.ts
│ │ ├── rendererTemplateRef.ts
│ │ ├── scheduler.ts
│ │ ├── vnode.ts
│ │ └── warning.ts
│ └── types
│ │ ├── globalComponents.d.ts
│ │ └── scriptSetupHelpers.d.ts
├── runtime-dom
│ ├── LICENSE
│ ├── README.md
│ ├── __tests__
│ │ ├── createApp.spec.ts
│ │ ├── customElement.spec.ts
│ │ ├── customizedBuiltIn.spec.ts
│ │ ├── directives
│ │ │ ├── vCloak.spec.ts
│ │ │ ├── vModel.spec.ts
│ │ │ ├── vOn.spec.ts
│ │ │ └── vShow.spec.ts
│ │ ├── helpers
│ │ │ ├── useCssModule.spec.ts
│ │ │ └── useCssVars.spec.ts
│ │ ├── nodeOps.spec.ts
│ │ ├── patchAttrs.spec.ts
│ │ ├── patchClass.spec.ts
│ │ ├── patchEvents.spec.ts
│ │ ├── patchProps.spec.ts
│ │ ├── patchStyle.spec.ts
│ │ └── rendererStaticNode.spec.ts
│ ├── index.js
│ ├── package.json
│ └── src
│ │ ├── apiCustomElement.ts
│ │ ├── components
│ │ ├── Transition.ts
│ │ └── TransitionGroup.ts
│ │ ├── directives
│ │ ├── vModel.ts
│ │ ├── vOn.ts
│ │ └── vShow.ts
│ │ ├── helpers
│ │ ├── useCssModule.ts
│ │ └── useCssVars.ts
│ │ ├── index.ts
│ │ ├── jsx.ts
│ │ ├── modules
│ │ ├── attrs.ts
│ │ ├── class.ts
│ │ ├── events.ts
│ │ ├── props.ts
│ │ └── style.ts
│ │ ├── nodeOps.ts
│ │ └── patchProp.ts
├── runtime-test
│ ├── LICENSE
│ ├── README.md
│ ├── __tests__
│ │ └── testRuntime.spec.ts
│ ├── index.js
│ ├── package.json
│ └── src
│ │ ├── index.ts
│ │ ├── nodeOps.ts
│ │ ├── patchProp.ts
│ │ ├── serialize.ts
│ │ └── triggerEvent.ts
├── server-renderer
│ ├── LICENSE
│ ├── README.md
│ ├── __tests__
│ │ ├── createBuffer.bench.ts
│ │ ├── render.spec.ts
│ │ ├── ssrAttrFallthrough.spec.ts
│ │ ├── ssrCompilerOptions.spec.ts
│ │ ├── ssrComputed.spec.ts
│ │ ├── ssrDirectives.spec.ts
│ │ ├── ssrDynamicComponent.spec.ts
│ │ ├── ssrInterpolate.spec.ts
│ │ ├── ssrRenderAttrs.spec.ts
│ │ ├── ssrRenderList.spec.ts
│ │ ├── ssrScopeId.spec.ts
│ │ ├── ssrSlot.spec.ts
│ │ ├── ssrSuspense.spec.ts
│ │ ├── ssrTeleport.spec.ts
│ │ ├── ssrVModelHelpers.spec.ts
│ │ ├── ssrWatch.spec.ts
│ │ ├── unrollBuffer.bench.ts
│ │ └── webStream.spec.ts
│ ├── index.js
│ ├── package.json
│ └── src
│ │ ├── helpers
│ │ ├── ssrCompile.ts
│ │ ├── ssrGetDirectiveProps.ts
│ │ ├── ssrInterpolate.ts
│ │ ├── ssrRenderAttrs.ts
│ │ ├── ssrRenderComponent.ts
│ │ ├── ssrRenderList.ts
│ │ ├── ssrRenderSlot.ts
│ │ ├── ssrRenderSuspense.ts
│ │ ├── ssrRenderTeleport.ts
│ │ └── ssrVModelHelpers.ts
│ │ ├── index.ts
│ │ ├── internal.ts
│ │ ├── render.ts
│ │ ├── renderToStream.ts
│ │ └── renderToString.ts
├── shared
│ ├── LICENSE
│ ├── README.md
│ ├── __tests__
│ │ ├── __snapshots__
│ │ │ └── codeframe.spec.ts.snap
│ │ ├── codeframe.spec.ts
│ │ ├── escapeHtml.spec.ts
│ │ ├── looseEqual.spec.ts
│ │ ├── normalizeProp.spec.ts
│ │ └── toDisplayString.spec.ts
│ ├── index.js
│ ├── package.json
│ └── src
│ │ ├── codeframe.ts
│ │ ├── domAttrConfig.ts
│ │ ├── domTagConfig.ts
│ │ ├── escapeHtml.ts
│ │ ├── general.ts
│ │ ├── globalsAllowList.ts
│ │ ├── index.ts
│ │ ├── looseEqual.ts
│ │ ├── makeMap.ts
│ │ ├── normalizeProp.ts
│ │ ├── patchFlags.ts
│ │ ├── shapeFlags.ts
│ │ ├── slotFlags.ts
│ │ ├── toDisplayString.ts
│ │ └── typeUtils.ts
├── vue-compat
│ ├── LICENSE
│ ├── README.md
│ ├── __tests__
│ │ ├── compiler.spec.ts
│ │ ├── componentAsync.spec.ts
│ │ ├── componentFunctional.spec.ts
│ │ ├── componentVModel.spec.ts
│ │ ├── filters.spec.ts
│ │ ├── global.spec.ts
│ │ ├── globalConfig.spec.ts
│ │ ├── instance.spec.ts
│ │ ├── misc.spec.ts
│ │ ├── options.spec.ts
│ │ ├── renderFn.spec.ts
│ │ └── utils.ts
│ ├── index.js
│ ├── package.json
│ └── src
│ │ ├── createCompatVue.ts
│ │ ├── dev.ts
│ │ ├── esm-index.ts
│ │ ├── esm-runtime.ts
│ │ ├── index.ts
│ │ └── runtime.ts
└── vue
│ ├── LICENSE
│ ├── README.md
│ ├── __tests__
│ ├── customElementCasing.spec.ts
│ ├── e2e
│ │ ├── Transition.spec.ts
│ │ ├── TransitionGroup.spec.ts
│ │ ├── commits.mock.ts
│ │ ├── commits.spec.ts
│ │ ├── e2eUtils.ts
│ │ ├── grid.spec.ts
│ │ ├── hydration-strat-custom.html
│ │ ├── hydration-strat-idle.html
│ │ ├── hydration-strat-interaction.html
│ │ ├── hydration-strat-media.html
│ │ ├── hydration-strat-visible.html
│ │ ├── hydrationStrategies.spec.ts
│ │ ├── markdown.spec.ts
│ │ ├── ssr-custom-element.html
│ │ ├── ssr-custom-element.spec.ts
│ │ ├── svg.spec.ts
│ │ ├── todomvc.spec.ts
│ │ ├── transition.html
│ │ ├── tree.spec.ts
│ │ ├── trusted-types.html
│ │ └── trusted-types.spec.ts
│ ├── index.spec.ts
│ ├── mathmlNamespace.spec.ts
│ ├── runtimeCompilerOptions.spec.ts
│ └── svgNamespace.spec.ts
│ ├── compiler-sfc
│ ├── index.browser.js
│ ├── index.browser.mjs
│ ├── index.d.mts
│ ├── index.d.ts
│ ├── index.js
│ ├── index.mjs
│ ├── package.json
│ └── register-ts.js
│ ├── examples
│ ├── classic
│ │ ├── commits.html
│ │ ├── grid.html
│ │ ├── markdown.html
│ │ ├── svg.html
│ │ ├── todomvc.html
│ │ └── tree.html
│ ├── composition
│ │ ├── commits.html
│ │ ├── grid.html
│ │ ├── markdown.html
│ │ ├── svg.html
│ │ ├── todomvc.html
│ │ └── tree.html
│ └── transition
│ │ ├── list.html
│ │ └── modal.html
│ ├── index.js
│ ├── index.mjs
│ ├── jsx-runtime
│ ├── index.d.ts
│ ├── index.js
│ ├── index.mjs
│ └── package.json
│ ├── jsx.d.ts
│ ├── package.json
│ ├── server-renderer
│ ├── index.d.mts
│ ├── index.d.ts
│ ├── index.js
│ ├── index.mjs
│ └── package.json
│ └── src
│ ├── dev.ts
│ ├── index.ts
│ └── runtime.ts
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── rollup.config.js
├── rollup.dts.config.js
├── scripts
├── aliases.js
├── build.js
├── dev.js
├── inline-enums.js
├── pre-dev-sfc.js
├── release.js
├── setup-vitest.ts
├── size-report.ts
├── usage-size.ts
├── utils.js
├── verify-commit.js
└── verify-treeshaking.js
├── tsconfig.build-browser.json
├── tsconfig.build-node.json
├── tsconfig.json
├── vitest.config.ts
├── vitest.e2e.config.ts
├── vitest.unit.config.ts
└── vitest.workspace.ts
/.git-blame-ignore-revs:
--------------------------------------------------------------------------------
1 | # update prettier & eslint config (#9162)
2 | bfe6b459d3a0ce6168611ee1ac7e6e789709df9d
3 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: yyx990803
2 | open_collective: vuejs
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 | - name: Feature Request
4 | url: https://github.com/vuejs/rfcs/discussions
5 | about: Suggest new features for consideration
6 | - name: Discord Chat
7 | url: https://chat.vuejs.org
8 | about: Ask questions and discuss with other Vue users in real time.
9 | - name: Questions & Discussions
10 | url: https://github.com/vuejs/core/discussions
11 | about: Use GitHub discussions for message-board style questions and discussions.
12 | - name: Patreon
13 | url: https://www.patreon.com/evanyou
14 | about: Love Vue.js? Please consider supporting us via Patreon.
15 | - name: Open Collective
16 | url: https://opencollective.com/vuejs/donate
17 | about: Love Vue.js? Please consider supporting us via Open Collective.
18 |
--------------------------------------------------------------------------------
/.github/git-branch-workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yyx990803/core/ca41b9202a26672273dce659a34f1351bfc97a68/.github/git-branch-workflow.png
--------------------------------------------------------------------------------
/.github/issue-workflow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yyx990803/core/ca41b9202a26672273dce659a34f1351bfc97a68/.github/issue-workflow.png
--------------------------------------------------------------------------------
/.github/workflows/autofix.yml:
--------------------------------------------------------------------------------
1 | name: autofix.ci
2 |
3 | on:
4 | pull_request:
5 | permissions:
6 | contents: read
7 |
8 | jobs:
9 | autofix:
10 | runs-on: ubuntu-latest
11 | env:
12 | PUPPETEER_SKIP_DOWNLOAD: 'true'
13 | steps:
14 | - uses: actions/checkout@v4
15 |
16 | - name: Install pnpm
17 | uses: pnpm/action-setup@v4.0.0
18 |
19 | - name: Install Node.js
20 | uses: actions/setup-node@v4
21 | with:
22 | node-version-file: '.node-version'
23 | registry-url: 'https://registry.npmjs.org'
24 | cache: 'pnpm'
25 |
26 | - run: pnpm install
27 |
28 | - name: Run eslint
29 | run: pnpm run lint --fix
30 |
31 | - name: Run prettier
32 | run: pnpm run format
33 |
34 | - uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c
35 |
--------------------------------------------------------------------------------
/.github/workflows/canary-minor.yml:
--------------------------------------------------------------------------------
1 | name: canary minor release
2 | on:
3 | # Runs every Monday at 1 AM UTC (9:00 AM in Singapore)
4 | schedule:
5 | - cron: 0 1 * * MON
6 | workflow_dispatch:
7 |
8 | jobs:
9 | canary:
10 | # prevents this action from running on forks
11 | if: github.repository == 'vuejs/core'
12 | runs-on: ubuntu-latest
13 | environment: Release
14 | steps:
15 | - uses: actions/checkout@v4
16 | with:
17 | ref: minor
18 |
19 | - name: Install pnpm
20 | uses: pnpm/action-setup@v4.0.0
21 |
22 | - name: Install Node.js
23 | uses: actions/setup-node@v4
24 | with:
25 | node-version-file: '.node-version'
26 | registry-url: 'https://registry.npmjs.org'
27 | cache: 'pnpm'
28 |
29 | - run: pnpm install
30 |
31 | - run: pnpm release --canary --publish --tag minor
32 | env:
33 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
34 |
--------------------------------------------------------------------------------
/.github/workflows/canary.yml:
--------------------------------------------------------------------------------
1 | name: canary release
2 | on:
3 | # Runs every Monday at 1 AM UTC (9:00 AM in Singapore)
4 | schedule:
5 | - cron: 0 1 * * MON
6 | workflow_dispatch:
7 |
8 | jobs:
9 | canary:
10 | # prevents this action from running on forks
11 | if: github.repository == 'vuejs/core'
12 | runs-on: ubuntu-latest
13 | environment: Release
14 | steps:
15 | - uses: actions/checkout@v4
16 |
17 | - name: Install pnpm
18 | uses: pnpm/action-setup@v4.0.0
19 |
20 | - name: Install Node.js
21 | uses: actions/setup-node@v4
22 | with:
23 | node-version-file: '.node-version'
24 | registry-url: 'https://registry.npmjs.org'
25 | cache: 'pnpm'
26 |
27 | - run: pnpm install
28 |
29 | - run: pnpm release --canary --publish
30 | env:
31 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
32 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: 'ci'
2 | on:
3 | push:
4 | branches:
5 | - '**'
6 | tags:
7 | - '!**'
8 | pull_request:
9 | branches:
10 | - main
11 | - minor
12 |
13 | jobs:
14 | test:
15 | if: ${{ ! startsWith(github.event.head_commit.message, 'release:') && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository) }}
16 | uses: ./.github/workflows/test.yml
17 |
18 | continuous-release:
19 | runs-on: ubuntu-latest
20 | steps:
21 | - name: Checkout
22 | uses: actions/checkout@v4
23 |
24 | - name: Install pnpm
25 | uses: pnpm/action-setup@v4
26 |
27 | - name: Install Node.js
28 | uses: actions/setup-node@v4
29 | with:
30 | node-version-file: '.node-version'
31 | registry-url: 'https://registry.npmjs.org'
32 | cache: 'pnpm'
33 |
34 | - name: Install deps
35 | run: pnpm install
36 |
37 | - name: Build
38 | run: pnpm build --withTypes
39 |
40 | - name: Release
41 | run: pnpx pkg-pr-new publish --compact --pnpm './packages/*'
42 |
--------------------------------------------------------------------------------
/.github/workflows/close-cant-reproduce-issues.yml:
--------------------------------------------------------------------------------
1 | name: Auto close issues with "can't reproduce" label
2 |
3 | on:
4 | schedule:
5 | - cron: '0 0 * * *'
6 |
7 | permissions:
8 | issues: write
9 |
10 | jobs:
11 | close-issues:
12 | if: github.repository == 'vuejs/core'
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: can't reproduce
16 | uses: actions-cool/issues-helper@v3
17 | with:
18 | actions: 'close-issues'
19 | token: ${{ secrets.GITHUB_TOKEN }}
20 | labels: "can't reproduce"
21 | inactive-day: 3
22 |
--------------------------------------------------------------------------------
/.github/workflows/lock-closed-issues.yml:
--------------------------------------------------------------------------------
1 | name: Lock Closed Issues
2 |
3 | on:
4 | schedule:
5 | - cron: '0 0 * * *'
6 |
7 | permissions:
8 | issues: write
9 |
10 | jobs:
11 | action:
12 | if: github.repository == 'vuejs/core'
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: dessant/lock-threads@v5
16 | with:
17 | github-token: ${{ secrets.GITHUB_TOKEN }}
18 | issue-inactive-days: '14'
19 | issue-lock-reason: ''
20 | process-only: 'issues'
21 |
--------------------------------------------------------------------------------
/.github/workflows/size-data.yml:
--------------------------------------------------------------------------------
1 | name: size data
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | - minor
8 | pull_request:
9 | branches:
10 | - main
11 | - minor
12 |
13 | permissions:
14 | contents: read
15 |
16 | env:
17 | PUPPETEER_SKIP_DOWNLOAD: 'true'
18 |
19 | jobs:
20 | upload:
21 | runs-on: ubuntu-latest
22 |
23 | steps:
24 | - uses: actions/checkout@v4
25 |
26 | - name: Install pnpm
27 | uses: pnpm/action-setup@v4.0.0
28 |
29 | - name: Install Node.js
30 | uses: actions/setup-node@v4
31 | with:
32 | node-version-file: '.node-version'
33 | cache: pnpm
34 |
35 | - name: Install dependencies
36 | run: pnpm install
37 |
38 | - run: pnpm run size
39 |
40 | - name: Save PR number & base branch
41 | if: ${{github.event_name == 'pull_request'}}
42 | run: |
43 | echo ${{ github.event.number }} > ./temp/size/number.txt
44 | echo ${{ github.base_ref }} > ./temp/size/base.txt
45 |
46 | - name: Upload Size Data
47 | uses: actions/upload-artifact@v4
48 | with:
49 | name: size-data
50 | path: temp/size
51 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | .DS_Store
3 | node_modules
4 | coverage
5 | temp
6 | explorations
7 | TODOs.md
8 | *.log
9 | .idea
10 | .eslintcache
11 | dts-build/packages
12 | *.tsbuildinfo
13 | *.tgz
14 |
--------------------------------------------------------------------------------
/.node-version:
--------------------------------------------------------------------------------
1 | 20
2 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | dist
2 | pnpm-lock.yaml
3 | CHANGELOG*.md
4 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "arrowParens": "avoid"
5 | }
6 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["vitest.explorer"]
3 | }
4 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "type": "node",
9 | "request": "launch",
10 | "name": "Vitest - Debug Current Test File",
11 | "autoAttachChildProcesses": true,
12 | "skipFiles": ["/**", "**/node_modules/**"],
13 | "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs",
14 | "args": ["run", "${relativeFile}"],
15 | "smartStep": true,
16 | "console": "integratedTerminal"
17 | }
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use the project's typescript version
3 | "typescript.tsdk": "node_modules/typescript/lib",
4 |
5 | "cSpell.enabledLanguageIds": ["markdown", "plaintext", "text", "yml"],
6 |
7 | // Use prettier to format typescript, javascript and JSON files
8 | "[typescript]": {
9 | "editor.defaultFormatter": "esbenp.prettier-vscode"
10 | },
11 | "[javascript]": {
12 | "editor.defaultFormatter": "esbenp.prettier-vscode"
13 | },
14 | "[json]": {
15 | "editor.defaultFormatter": "esbenp.prettier-vscode"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/BACKERS.md:
--------------------------------------------------------------------------------
1 | Sponsors & Backers
2 |
3 | Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of the awesome sponsors and backers listed in this file. If you'd like to join them, please consider [ sponsoring Vue's development](https://vuejs.org/sponsor/).
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/FUNDING.json:
--------------------------------------------------------------------------------
1 | {
2 | "drips": {
3 | "ethereum": {
4 | "ownedBy": "0x5393BdeA2a020769256d9f337B0fc81a2F64850A"
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You and Vue contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Reporting a Vulnerability
2 |
3 | To report a vulnerability, please email security@vuejs.org.
4 |
5 | While the discovery of new vulnerabilities is rare, we also recommend always using the latest versions of Vue and its official companion libraries to ensure your application remains as secure as possible.
6 |
7 | Please note that we do not consider XSS via template expressions a valid attack vector, because it can only happen if the user intentionally uses untrusted content as template compilation source. This is similar to knowingly pasting untrusted scripts into a browser console. We explicitly warn users against using untrusted content as template compilation source in our documentation.
8 |
9 | ## Security Hall of Fame
10 |
11 | We would like to thank the following security researchers for responsibly disclosing security issues to us.
12 |
13 | - Jeet Pal - [@jeetpal2007](https://github.com/jeetpal2007) | [Email](mailto:jeetpal2007@gmail.com) | [LinkedIn](https://in.linkedin.com/in/jeet-pal-22601a290)
14 | - Mix - [@mnixry](https://github.com/mnixry)
15 | - Aviv Keller - [@RedYetiDev](https://github.com/redyetidev) | [LinkedIn](https://www.linkedin.com/in/redyetidev)
16 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build.environment]
2 | NODE_VERSION = "18"
3 | NPM_FLAGS = "--version" # prevent Netlify npm install
4 |
--------------------------------------------------------------------------------
/packages-private/dts-built-test/README.md:
--------------------------------------------------------------------------------
1 | # dts built-package test
2 |
3 | This package is private and for testing only. It is used to verify edge cases for external libraries that build their types using Vue core types - e.g. Vuetify as in [#8376](https://github.com/vuejs/core/issues/8376).
4 |
5 | When running the `build-dts` task, this package's types are built alongside other packages. Then, during `test-dts-only` it is imported and used in [`packages-private/dts-test/built.test-d.ts`](https://github.com/vuejs/core/blob/main/packages-private/dts-test/built.test-d.ts) to verify that the built types work correctly.
6 |
--------------------------------------------------------------------------------
/packages-private/dts-built-test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dts-built-test",
3 | "private": true,
4 | "version": "0.0.0",
5 | "types": "dist/index.d.ts",
6 | "dependencies": {
7 | "@vue/shared": "workspace:*",
8 | "@vue/reactivity": "workspace:*",
9 | "vue": "workspace:*"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages-private/dts-built-test/src/index.ts:
--------------------------------------------------------------------------------
1 | import { defineComponent } from 'vue'
2 |
3 | const _CustomPropsNotErased = defineComponent({
4 | props: {},
5 | setup() {},
6 | })
7 |
8 | // #8376
9 | export const CustomPropsNotErased =
10 | _CustomPropsNotErased as typeof _CustomPropsNotErased & {
11 | foo: string
12 | }
13 |
--------------------------------------------------------------------------------
/packages-private/dts-built-test/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "outDir": "dist",
5 | "jsx": "preserve",
6 | "module": "esnext",
7 | "strict": true,
8 | "moduleResolution": "Bundler",
9 | "lib": ["esnext", "dom"],
10 | "declaration": true,
11 | "emitDeclarationOnly": true
12 | },
13 | "include": ["./src"]
14 | }
15 |
--------------------------------------------------------------------------------
/packages-private/dts-test/README.md:
--------------------------------------------------------------------------------
1 | # dts-test
2 |
3 | Tests TypeScript types to ensure the types remain as expected.
4 |
5 | - This directory is included in the root `tsconfig.json`, where package imports are aliased to `src` directories, so in IDEs and the `pnpm check` script the types are validated against source code.
6 |
7 | - When running `tsc` with `packages-private/dts-test/tsconfig.test.json`, packages are resolved using normal `node` resolution, so the types are validated against actual **built** types. This requires the types to be built first via `pnpm build-dts`.
8 |
--------------------------------------------------------------------------------
/packages-private/dts-test/appDirective.test-d.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import { expectType } from './utils'
3 |
4 | const app = createApp({})
5 |
6 | app.directive('custom', {
7 | mounted(el, binding) {
8 | expectType(el)
9 | expectType(binding.value)
10 |
11 | // @ts-expect-error not any
12 | expectType(binding.value)
13 | },
14 | })
15 |
--------------------------------------------------------------------------------
/packages-private/dts-test/built.test-d.ts:
--------------------------------------------------------------------------------
1 | import { CustomPropsNotErased } from 'dts-built-test/src/index'
2 | import { describe, expectType } from './utils'
3 |
4 | declare module 'vue' {
5 | interface ComponentCustomProps {
6 | custom?: number
7 | }
8 | }
9 |
10 | // #8376 - custom props should not be erased
11 | describe('Custom Props not erased', () => {
12 | expectType(new CustomPropsNotErased().$props.custom)
13 | })
14 |
--------------------------------------------------------------------------------
/packages-private/dts-test/compiler.test-d.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Comment,
3 | Fragment,
4 | Static,
5 | Suspense,
6 | Teleport,
7 | Text,
8 | type VNode,
9 | createBlock,
10 | defineComponent,
11 | } from 'vue'
12 | import { expectType } from './utils'
13 |
14 | expectType(createBlock(Teleport))
15 | expectType(createBlock(Text))
16 | expectType(createBlock(Static))
17 | expectType(createBlock(Comment))
18 | expectType(createBlock(Fragment))
19 | expectType(createBlock(Suspense))
20 | expectType(createBlock(defineComponent({})))
21 |
--------------------------------------------------------------------------------
/packages-private/dts-test/directives.test-d.ts:
--------------------------------------------------------------------------------
1 | import { type Directive, type ObjectDirective, vModelText } from 'vue'
2 | import { describe, expectType } from './utils'
3 |
4 | type ExtractBinding = T extends (
5 | el: any,
6 | binding: infer B,
7 | vnode: any,
8 | prev: any,
9 | ) => any
10 | ? B
11 | : never
12 |
13 | declare function testDirective<
14 | Value,
15 | Modifiers extends string = string,
16 | Arg extends string = string,
17 | >(): ExtractBinding>
18 |
19 | describe('vmodel', () => {
20 | expectType>(
21 | vModelText,
22 | )
23 | // @ts-expect-error
24 | expectType>(vModelText)
25 | })
26 |
27 | describe('custom', () => {
28 | expectType<{
29 | value: number
30 | oldValue: number | null
31 | arg?: 'Arg'
32 | modifiers: Record<'a' | 'b', boolean>
33 | }>(testDirective())
34 |
35 | expectType<{
36 | value: number
37 | oldValue: number | null
38 | arg?: 'Arg'
39 | modifiers: Record<'a' | 'b', boolean>
40 | // @ts-expect-error
41 | }>(testDirective())
42 |
43 | expectType<{
44 | value: number
45 | oldValue: number | null
46 | arg?: 'Arg'
47 | modifiers: Record<'a' | 'b', boolean>
48 | // @ts-expect-error
49 | }>(testDirective())
50 |
51 | expectType<{
52 | value: number
53 | oldValue: number | null
54 | arg?: 'Arg'
55 | modifiers: Record<'a' | 'b', boolean>
56 | // @ts-expect-error
57 | }>(testDirective())
58 | })
59 |
--------------------------------------------------------------------------------
/packages-private/dts-test/extractProps.test-d.ts:
--------------------------------------------------------------------------------
1 | import type { ExtractPropTypes, ExtractPublicPropTypes } from 'vue'
2 | import { type Prettify, expectType } from './utils'
3 |
4 | const propsOptions = {
5 | foo: {
6 | default: 1,
7 | },
8 | bar: {
9 | type: String,
10 | required: true,
11 | },
12 | baz: Boolean,
13 | qux: Array,
14 | } as const
15 |
16 | // internal facing props
17 | declare const props: Prettify>
18 |
19 | expectType(props.foo)
20 | expectType(props.bar)
21 | expectType(props.baz)
22 | expectType(props.qux)
23 |
24 | // external facing props
25 | declare const publicProps: Prettify>
26 |
27 | expectType(publicProps.foo)
28 | expectType(publicProps.bar)
29 | expectType(publicProps.baz)
30 | expectType(publicProps.qux)
31 |
--------------------------------------------------------------------------------
/packages-private/dts-test/inject.test-d.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type InjectionKey,
3 | type Ref,
4 | createApp,
5 | defineComponent,
6 | inject,
7 | provide,
8 | ref,
9 | } from 'vue'
10 | import { expectType } from './utils'
11 |
12 | // non-symbol keys
13 | provide('foo', 123)
14 | provide(123, 123)
15 |
16 | const key: InjectionKey = Symbol()
17 |
18 | provide(key, 1)
19 | // @ts-expect-error
20 | provide(key, 'foo')
21 | // @ts-expect-error
22 | provide(key, null)
23 |
24 | expectType(inject(key))
25 | expectType(inject(key, 1))
26 | expectType(inject(key, () => 1, true /* treatDefaultAsFactory */))
27 |
28 | expectType<() => number>(inject('foo', () => 1))
29 | expectType<() => number>(inject('foo', () => 1, false))
30 | expectType(inject('foo', () => 1, true))
31 |
32 | // #8201
33 | type Cube = {
34 | size: number
35 | }
36 |
37 | const injectionKeyRef = Symbol('key') as InjectionKey[>
38 |
39 | // @ts-expect-error
40 | provide(injectionKeyRef, ref({}))
41 |
42 | // naive-ui: explicit provide type parameter
43 | provide]('cube', { size: 123 })
44 | provide(123, { size: 123 })
45 | provide(injectionKeyRef, { size: 123 })
46 |
47 | // @ts-expect-error
48 | provide('cube', { size: 'foo' })
49 | // @ts-expect-error
50 | provide(123, { size: 'foo' })
51 |
52 | // #10602
53 | const app = createApp({})
54 | // @ts-expect-error
55 | app.provide(injectionKeyRef, ref({}))
56 |
57 | defineComponent({
58 | provide: {
59 | [injectionKeyRef]: { size: 'foo' },
60 | },
61 | })
62 |
--------------------------------------------------------------------------------
/packages-private/dts-test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dts-test",
3 | "private": true,
4 | "version": "0.0.0",
5 | "dependencies": {
6 | "vue": "workspace:*",
7 | "dts-built-test": "workspace:*"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/packages-private/dts-test/tsconfig.test.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "noEmit": true,
4 | "jsx": "preserve",
5 | "module": "esnext",
6 | "strict": true,
7 | "moduleResolution": "node",
8 | "lib": ["esnext", "dom"]
9 | },
10 | "include": ["./*"]
11 | }
12 |
--------------------------------------------------------------------------------
/packages-private/dts-test/utils.d.ts:
--------------------------------------------------------------------------------
1 | // This directory contains a number of d.ts assertions
2 | // use \@ts-expect-error where errors are expected.
3 |
4 | // register global JSX
5 | import 'vue/jsx'
6 |
7 | export function describe(_name: string, _fn: () => void): void
8 | export function test(_name: string, _fn: () => any): void
9 |
10 | export function expectType(value: T): void
11 | export function expectAssignable(value: T2): void
12 |
13 | export type IsUnion = (
14 | T extends any ? (U extends T ? false : true) : never
15 | ) extends false
16 | ? false
17 | : true
18 |
19 | export type IsAny = 0 extends 1 & T ? true : false
20 |
21 | export type Prettify = { [K in keyof T]: T[K] } & {}
22 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/README.md:
--------------------------------------------------------------------------------
1 | # SFC Playground
2 |
3 | This is continuously deployed at [https://play.vuejs.org](https://play.vuejs.org).
4 |
5 | ## Run Locally in Dev
6 |
7 | In repo root:
8 |
9 | ```sh
10 | pnpm dev-sfc
11 | ```
12 |
13 | ## Build for Prod
14 |
15 | In repo root
16 |
17 | ```sh
18 | pnpm build-sfc-playground
19 | ```
20 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Vue SFC Playground
9 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue/sfc-playground",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "serve": "vite preview"
10 | },
11 | "devDependencies": {
12 | "@vitejs/plugin-vue": "catalog:",
13 | "vite": "catalog:"
14 | },
15 | "dependencies": {
16 | "@vue/repl": "^4.3.1",
17 | "file-saver": "^2.0.5",
18 | "jszip": "^3.10.1",
19 | "vue": "workspace:*"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/public/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/download/download.ts:
--------------------------------------------------------------------------------
1 | import { saveAs } from 'file-saver'
2 |
3 | import index from './template/index.html?raw'
4 | import main from './template/main.js?raw'
5 | import pkg from './template/package.json?raw'
6 | import config from './template/vite.config.js?raw'
7 | import readme from './template/README.md?raw'
8 | import type { ReplStore } from '@vue/repl'
9 |
10 | export async function downloadProject(store: ReplStore) {
11 | if (!confirm('Download project files?')) {
12 | return
13 | }
14 |
15 | const { default: JSZip } = await import('jszip')
16 | const zip = new JSZip()
17 |
18 | // basic structure
19 | zip.file('index.html', index)
20 | zip.file('package.json', pkg)
21 | zip.file('vite.config.js', config)
22 | zip.file('README.md', readme)
23 |
24 | // project src
25 | const src = zip.folder('src')!
26 | src.file('main.js', main)
27 |
28 | const files = store.getFiles()
29 | for (const file in files) {
30 | if (file !== 'import-map.json' && file !== 'tsconfig.json') {
31 | src.file(file, files[file])
32 | } else {
33 | zip.file(file, files[file])
34 | }
35 | }
36 |
37 | const blob = await zip.generateAsync({ type: 'blob' })
38 | saveAs(blob, 'vue-project.zip')
39 | }
40 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/download/template/README.md:
--------------------------------------------------------------------------------
1 | # Vite Vue Starter
2 |
3 | This is a project template using [Vite](https://vitejs.dev/). It requires [Node.js](https://nodejs.org) version 18+ or 20+.
4 |
5 | To start:
6 |
7 | ```sh
8 | npm install
9 | npm run dev
10 |
11 | # if using yarn:
12 | yarn
13 | yarn dev
14 |
15 | # if using pnpm:
16 | pnpm install
17 | pnpm run dev
18 | ```
19 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/download/template/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite App
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/download/template/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 |
4 | createApp(App).mount('#app')
5 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/download/template/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-vue-starter",
3 | "version": "0.0.0",
4 | "type": "module",
5 | "scripts": {
6 | "dev": "vite",
7 | "build": "vite build",
8 | "serve": "vite preview"
9 | },
10 | "dependencies": {
11 | "vue": "^3.4.0"
12 | },
13 | "devDependencies": {
14 | "@vitejs/plugin-vue": "^5.1.2",
15 | "vite": "^5.4.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/download/template/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [vue()],
7 | })
8 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/icons/Copy.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/icons/Download.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
23 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/icons/GitHub.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/icons/Moon.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/icons/Reload.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/icons/Share.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/icons/Sun.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
15 |
19 |
23 |
27 |
31 |
35 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 |
4 | // @ts-expect-error Custom window property
5 | window.VUE_DEVTOOLS_CONFIG = {
6 | defaultSelectedAppId: 'repl',
7 | }
8 |
9 | createApp(App).mount('#app')
10 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/vue-dev-proxy-prod.ts:
--------------------------------------------------------------------------------
1 | // serve vue to the iframe sandbox during dev.
2 | export * from 'vue/dist/vue.runtime.esm-browser.prod.js'
3 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/vue-dev-proxy.ts:
--------------------------------------------------------------------------------
1 | // serve vue to the iframe sandbox during dev.
2 | export * from 'vue'
3 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/src/vue-server-renderer-dev-proxy.ts:
--------------------------------------------------------------------------------
1 | // serve vue/server-renderer to the iframe sandbox during dev.
2 | export * from 'vue/server-renderer'
3 |
--------------------------------------------------------------------------------
/packages-private/sfc-playground/vercel.json:
--------------------------------------------------------------------------------
1 | {
2 | "github": {
3 | "silent": true
4 | },
5 | "headers": [
6 | {
7 | "source": "/assets/(.*)",
8 | "headers": [
9 | {
10 | "key": "Cache-Control",
11 | "value": "max-age=31536000, immutable"
12 | }
13 | ]
14 | }
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/packages-private/template-explorer/README.md:
--------------------------------------------------------------------------------
1 | ## Template Explorer
2 |
3 | Live explorer for template compilation output.
4 |
5 | To run:
6 |
7 | - `npm run dev-compiler` in repo root
8 | - When the compilation is done, in another terminal run `npm run open`
9 |
10 | Note: `index.html` uses CDN for dependencies and is continuously deployed at [https://template-explorer.vuejs.org](https://template-explorer.vuejs.org). For local development, use the scripts above.
11 |
--------------------------------------------------------------------------------
/packages-private/template-explorer/_redirects:
--------------------------------------------------------------------------------
1 | https://vue-next-template-explorer.netlify.app https://template-explorer.vuejs.org 301!
2 | https://vue-next-template-explorer.netlify.app/* https://template-explorer.vuejs.org/:splat 301!
3 |
--------------------------------------------------------------------------------
/packages-private/template-explorer/index.html:
--------------------------------------------------------------------------------
1 | Vue Template Explorer
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
25 |
--------------------------------------------------------------------------------
/packages-private/template-explorer/local.html:
--------------------------------------------------------------------------------
1 | Vue Template Explorer
2 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
21 |
22 |
25 |
--------------------------------------------------------------------------------
/packages-private/template-explorer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue/template-explorer",
3 | "private": true,
4 | "version": "0.0.0",
5 | "buildOptions": {
6 | "formats": [
7 | "global"
8 | ],
9 | "compat": true,
10 | "env": "development",
11 | "enableNonBrowserBranches": true
12 | },
13 | "dependencies": {
14 | "monaco-editor": "^0.50.0",
15 | "source-map-js": "^1.2.0"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages-private/vite-debug/App.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | {{ count }}
9 |
10 |
11 |
16 |
--------------------------------------------------------------------------------
/packages-private/vite-debug/README.md:
--------------------------------------------------------------------------------
1 | This package is used for debugging issues that are related to `@vitejs/plugin-vue`, or can only be reproduced in a Vite-based setup. It aims to be as close to production as possible so Vue packages are resolved to the dist files instead of source.
2 |
--------------------------------------------------------------------------------
/packages-private/vite-debug/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/packages-private/vite-debug/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 |
4 | const app = createApp(App)
5 |
6 | app.mount('#app')
7 |
--------------------------------------------------------------------------------
/packages-private/vite-debug/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vite-debug",
3 | "private": true,
4 | "type": "module",
5 | "scripts": {
6 | "dev": "vite",
7 | "build": "vite build",
8 | "serve": "vite preview"
9 | },
10 | "devDependencies": {
11 | "@vitejs/plugin-vue": "catalog:",
12 | "vite": "catalog:",
13 | "vue": "workspace:*"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/packages-private/vite-debug/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "esnext",
4 | "moduleResolution": "bundler"
5 | },
6 | "include": ["./*"]
7 | }
8 |
--------------------------------------------------------------------------------
/packages-private/vite-debug/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 |
4 | export default defineConfig({
5 | plugins: [vue()],
6 | })
7 |
--------------------------------------------------------------------------------
/packages/compiler-core/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/compiler-core/README.md:
--------------------------------------------------------------------------------
1 | # @vue/compiler-core
2 |
--------------------------------------------------------------------------------
/packages/compiler-core/__tests__/transforms/noopDirectiveTransform.spec.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type ElementNode,
3 | type VNodeCall,
4 | noopDirectiveTransform,
5 | baseParse as parse,
6 | transform,
7 | } from '../../src'
8 | import { transformElement } from '../../src/transforms/transformElement'
9 |
10 | describe('compiler: noop directive transform', () => {
11 | test('should add no props to DOM', () => {
12 | const ast = parse(`
`)
13 | transform(ast, {
14 | nodeTransforms: [transformElement],
15 | directiveTransforms: {
16 | noop: noopDirectiveTransform,
17 | },
18 | })
19 | const node = ast.children[0] as ElementNode
20 | // As v-noop adds no properties the codegen should be identical to
21 | // rendering a div with no props or reactive data (so just the tag as the arg)
22 | expect((node.codegenNode as VNodeCall).props).toBeUndefined()
23 | })
24 | })
25 |
--------------------------------------------------------------------------------
/packages/compiler-core/__tests__/transforms/vMemo.spec.ts:
--------------------------------------------------------------------------------
1 | import { baseCompile } from '../../src'
2 |
3 | describe('compiler: v-memo transform', () => {
4 | function compile(content: string) {
5 | return baseCompile(`${content}
`, {
6 | mode: 'module',
7 | prefixIdentifiers: true,
8 | }).code
9 | }
10 |
11 | test('on root element', () => {
12 | expect(
13 | baseCompile(`
`, {
14 | mode: 'module',
15 | prefixIdentifiers: true,
16 | }).code,
17 | ).toMatchSnapshot()
18 | })
19 |
20 | test('on normal element', () => {
21 | expect(compile(`
`)).toMatchSnapshot()
22 | })
23 |
24 | test('on component', () => {
25 | expect(compile(` `)).toMatchSnapshot()
26 | })
27 |
28 | test('on v-if', () => {
29 | expect(
30 | compile(
31 | `foo bar
32 | `,
33 | ),
34 | ).toMatchSnapshot()
35 | })
36 |
37 | test('on v-for', () => {
38 | expect(
39 | compile(
40 | `
41 | foobar
42 |
`,
43 | ),
44 | ).toMatchSnapshot()
45 | })
46 |
47 | test('on template v-for', () => {
48 | expect(
49 | compile(
50 | `
51 | foobar
52 | `,
53 | ),
54 | ).toMatchSnapshot()
55 | })
56 | })
57 |
--------------------------------------------------------------------------------
/packages/compiler-core/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | if (process.env.NODE_ENV === 'production') {
4 | module.exports = require('./dist/compiler-core.cjs.prod.js')
5 | } else {
6 | module.exports = require('./dist/compiler-core.cjs.js')
7 | }
8 |
--------------------------------------------------------------------------------
/packages/compiler-core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue/compiler-core",
3 | "version": "3.5.0-beta.2",
4 | "description": "@vue/compiler-core",
5 | "main": "index.js",
6 | "module": "dist/compiler-core.esm-bundler.js",
7 | "types": "dist/compiler-core.d.ts",
8 | "files": [
9 | "index.js",
10 | "dist"
11 | ],
12 | "exports": {
13 | ".": {
14 | "types": "./dist/compiler-core.d.ts",
15 | "node": {
16 | "production": "./dist/compiler-core.cjs.prod.js",
17 | "development": "./dist/compiler-core.cjs.js",
18 | "default": "./index.js"
19 | },
20 | "module": "./dist/compiler-core.esm-bundler.js",
21 | "import": "./dist/compiler-core.esm-bundler.js",
22 | "require": "./index.js"
23 | },
24 | "./*": "./*"
25 | },
26 | "buildOptions": {
27 | "name": "VueCompilerCore",
28 | "compat": true,
29 | "formats": [
30 | "esm-bundler",
31 | "cjs"
32 | ]
33 | },
34 | "repository": {
35 | "type": "git",
36 | "url": "git+https://github.com/vuejs/core.git",
37 | "directory": "packages/compiler-core"
38 | },
39 | "keywords": [
40 | "vue"
41 | ],
42 | "author": "Evan You",
43 | "license": "MIT",
44 | "bugs": {
45 | "url": "https://github.com/vuejs/core/issues"
46 | },
47 | "homepage": "https://github.com/vuejs/core/tree/main/packages/compiler-core#readme",
48 | "dependencies": {
49 | "@babel/parser": "catalog:",
50 | "@vue/shared": "workspace:*",
51 | "entities": "^4.5.0",
52 | "estree-walker": "catalog:",
53 | "source-map-js": "catalog:"
54 | },
55 | "devDependencies": {
56 | "@babel/types": "catalog:"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/packages/compiler-core/src/transforms/noopDirectiveTransform.ts:
--------------------------------------------------------------------------------
1 | import type { DirectiveTransform } from '../transform'
2 |
3 | export const noopDirectiveTransform: DirectiveTransform = () => ({ props: [] })
4 |
--------------------------------------------------------------------------------
/packages/compiler-core/src/transforms/vMemo.ts:
--------------------------------------------------------------------------------
1 | import type { NodeTransform } from '../transform'
2 | import { findDir } from '../utils'
3 | import {
4 | ElementTypes,
5 | type MemoExpression,
6 | NodeTypes,
7 | type PlainElementNode,
8 | convertToBlock,
9 | createCallExpression,
10 | createFunctionExpression,
11 | } from '../ast'
12 | import { WITH_MEMO } from '../runtimeHelpers'
13 |
14 | const seen = new WeakSet()
15 |
16 | export const transformMemo: NodeTransform = (node, context) => {
17 | if (node.type === NodeTypes.ELEMENT) {
18 | const dir = findDir(node, 'memo')
19 | if (!dir || seen.has(node)) {
20 | return
21 | }
22 | seen.add(node)
23 | return () => {
24 | const codegenNode =
25 | node.codegenNode ||
26 | (context.currentNode as PlainElementNode).codegenNode
27 | if (codegenNode && codegenNode.type === NodeTypes.VNODE_CALL) {
28 | // non-component sub tree should be turned into a block
29 | if (node.tagType !== ElementTypes.COMPONENT) {
30 | convertToBlock(codegenNode, context)
31 | }
32 | node.codegenNode = createCallExpression(context.helper(WITH_MEMO), [
33 | dir.exp!,
34 | createFunctionExpression(undefined, codegenNode),
35 | `_cache`,
36 | String(context.cached.length),
37 | ]) as MemoExpression
38 | // increment cache count
39 | context.cached.push(null)
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/packages/compiler-core/src/transforms/vOnce.ts:
--------------------------------------------------------------------------------
1 | import type { NodeTransform } from '../transform'
2 | import { findDir } from '../utils'
3 | import { type ElementNode, type ForNode, type IfNode, NodeTypes } from '../ast'
4 | import { SET_BLOCK_TRACKING } from '../runtimeHelpers'
5 |
6 | const seen = new WeakSet()
7 |
8 | export const transformOnce: NodeTransform = (node, context) => {
9 | if (node.type === NodeTypes.ELEMENT && findDir(node, 'once', true)) {
10 | if (seen.has(node) || context.inVOnce || context.inSSR) {
11 | return
12 | }
13 | seen.add(node)
14 | context.inVOnce = true
15 | context.helper(SET_BLOCK_TRACKING)
16 | return () => {
17 | context.inVOnce = false
18 | const cur = context.currentNode as ElementNode | IfNode | ForNode
19 | if (cur.codegenNode) {
20 | cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */)
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/packages/compiler-dom/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/compiler-dom/README.md:
--------------------------------------------------------------------------------
1 | # @vue/compiler-dom
2 |
--------------------------------------------------------------------------------
/packages/compiler-dom/__tests__/__snapshots__/index.spec.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`compile > should contain standard transforms 1`] = `
4 | "const _Vue = Vue
5 |
6 | return function render(_ctx, _cache) {
7 | with (_ctx) {
8 | const { toDisplayString: _toDisplayString, createElementVNode: _createElementVNode, normalizeStyle: _normalizeStyle, Fragment: _Fragment, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
9 |
10 | return (_openBlock(), _createElementBlock(_Fragment, null, [
11 | _createElementVNode("div", {
12 | textContent: _toDisplayString(text)
13 | }, null, 8 /* PROPS */, ["textContent"]),
14 | _createElementVNode("div", { innerHTML: html }, null, 8 /* PROPS */, ["innerHTML"]),
15 | _createElementVNode("div", null, "test"),
16 | _createElementVNode("div", { style: {"color":"red"} }, "red"),
17 | _createElementVNode("div", {
18 | style: _normalizeStyle({color: 'green'})
19 | }, null, 4 /* STYLE */)
20 | ], 64 /* STABLE_FRAGMENT */))
21 | }
22 | }"
23 | `;
24 |
--------------------------------------------------------------------------------
/packages/compiler-dom/__tests__/index.spec.ts:
--------------------------------------------------------------------------------
1 | import { compile } from '../src'
2 |
3 | describe('compile', () => {
4 | it('should contain standard transforms', () => {
5 | const { code } = compile(`
6 |
7 | test
8 | red
9 |
`)
10 |
11 | expect(code).toMatchSnapshot()
12 | })
13 | })
14 |
--------------------------------------------------------------------------------
/packages/compiler-dom/__tests__/transforms/__snapshots__/vShow.spec.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`compiler: v-show transform > simple expression 1`] = `
4 | "const _Vue = Vue
5 |
6 | return function render(_ctx, _cache) {
7 | with (_ctx) {
8 | const { vShow: _vShow, withDirectives: _withDirectives, openBlock: _openBlock, createElementBlock: _createElementBlock } = _Vue
9 |
10 | return _withDirectives((_openBlock(), _createElementBlock("div", null, null, 512 /* NEED_PATCH */)), [
11 | [_vShow, a]
12 | ])
13 | }
14 | }"
15 | `;
16 |
--------------------------------------------------------------------------------
/packages/compiler-dom/__tests__/transforms/ignoreSideEffectTags.spec.ts:
--------------------------------------------------------------------------------
1 | import { type CompilerError, compile } from '../../src'
2 |
3 | describe('compiler: ignore side effect tags', () => {
4 | it('should ignore script', () => {
5 | let err: CompilerError | undefined
6 | const { code } = compile(``, {
7 | onError(e) {
8 | err = e
9 | },
10 | })
11 | expect(code).not.toMatch('script')
12 | expect(err).toBeDefined()
13 | expect(err!.message).toMatch(`Tags with side effect`)
14 | })
15 |
16 | it('should ignore style', () => {
17 | let err: CompilerError | undefined
18 | const { code } = compile(``, {
19 | onError(e) {
20 | err = e
21 | },
22 | })
23 | expect(code).not.toMatch('style')
24 | expect(err).toBeDefined()
25 | expect(err!.message).toMatch(`Tags with side effect`)
26 | })
27 | })
28 |
--------------------------------------------------------------------------------
/packages/compiler-dom/__tests__/transforms/vShow.spec.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type CompilerOptions,
3 | generate,
4 | baseParse as parse,
5 | transform,
6 | } from '@vue/compiler-core'
7 | import { transformElement } from '../../../compiler-core/src/transforms/transformElement'
8 | import { transformShow } from '../../src/transforms/vShow'
9 | import { DOMErrorCodes } from '../../src/errors'
10 |
11 | function transformWithShow(template: string, options: CompilerOptions = {}) {
12 | const ast = parse(template)
13 | transform(ast, {
14 | nodeTransforms: [transformElement],
15 | directiveTransforms: {
16 | show: transformShow,
17 | },
18 | ...options,
19 | })
20 | return ast
21 | }
22 |
23 | describe('compiler: v-show transform', () => {
24 | test('simple expression', () => {
25 | const ast = transformWithShow(`
`)
26 |
27 | expect(generate(ast).code).toMatchSnapshot()
28 | })
29 |
30 | test('should raise error if has no expression', () => {
31 | const onError = vi.fn()
32 | transformWithShow(`
`, { onError })
33 |
34 | expect(onError).toHaveBeenCalledTimes(1)
35 | expect(onError).toHaveBeenCalledWith(
36 | expect.objectContaining({
37 | code: DOMErrorCodes.X_V_SHOW_NO_EXPRESSION,
38 | }),
39 | )
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/packages/compiler-dom/__tests__/transforms/validateHtmlNesting.spec.ts:
--------------------------------------------------------------------------------
1 | import { type CompilerError, compile } from '../../src'
2 |
3 | describe('validate html nesting', () => {
4 | it('should warn with p > div', () => {
5 | let err: CompilerError | undefined
6 | compile(`
`, {
7 | onWarn: e => (err = e),
8 | })
9 | expect(err).toBeDefined()
10 | expect(err!.message).toMatch(` cannot be child of
`)
11 | })
12 |
13 | it('should not warn with select > hr', () => {
14 | let err: CompilerError | undefined
15 | compile(` `, {
16 | onWarn: e => (err = e),
17 | })
18 | expect(err).toBeUndefined()
19 | })
20 | })
21 |
--------------------------------------------------------------------------------
/packages/compiler-dom/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | if (process.env.NODE_ENV === 'production') {
4 | module.exports = require('./dist/compiler-dom.cjs.prod.js')
5 | } else {
6 | module.exports = require('./dist/compiler-dom.cjs.js')
7 | }
8 |
--------------------------------------------------------------------------------
/packages/compiler-dom/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue/compiler-dom",
3 | "version": "3.5.0-beta.2",
4 | "description": "@vue/compiler-dom",
5 | "main": "index.js",
6 | "module": "dist/compiler-dom.esm-bundler.js",
7 | "types": "dist/compiler-dom.d.ts",
8 | "unpkg": "dist/compiler-dom.global.js",
9 | "jsdelivr": "dist/compiler-dom.global.js",
10 | "files": [
11 | "index.js",
12 | "dist"
13 | ],
14 | "exports": {
15 | ".": {
16 | "types": "./dist/compiler-dom.d.ts",
17 | "node": {
18 | "production": "./dist/compiler-dom.cjs.prod.js",
19 | "development": "./dist/compiler-dom.cjs.js",
20 | "default": "./index.js"
21 | },
22 | "module": "./dist/compiler-dom.esm-bundler.js",
23 | "import": "./dist/compiler-dom.esm-bundler.js",
24 | "require": "./index.js"
25 | },
26 | "./*": "./*"
27 | },
28 | "sideEffects": false,
29 | "buildOptions": {
30 | "name": "VueCompilerDOM",
31 | "compat": true,
32 | "formats": [
33 | "esm-bundler",
34 | "esm-browser",
35 | "cjs",
36 | "global"
37 | ]
38 | },
39 | "repository": {
40 | "type": "git",
41 | "url": "git+https://github.com/vuejs/core.git",
42 | "directory": "packages/compiler-dom"
43 | },
44 | "keywords": [
45 | "vue"
46 | ],
47 | "author": "Evan You",
48 | "license": "MIT",
49 | "bugs": {
50 | "url": "https://github.com/vuejs/core/issues"
51 | },
52 | "homepage": "https://github.com/vuejs/core/tree/main/packages/compiler-dom#readme",
53 | "dependencies": {
54 | "@vue/shared": "workspace:*",
55 | "@vue/compiler-core": "workspace:*"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/packages/compiler-dom/src/decodeHtmlBrowser.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-restricted-globals */
2 |
3 | let decoder: HTMLDivElement
4 |
5 | export function decodeHtmlBrowser(raw: string, asAttr = false): string {
6 | if (!decoder) {
7 | decoder = document.createElement('div')
8 | }
9 | if (asAttr) {
10 | decoder.innerHTML = `
`
11 | return decoder.children[0].getAttribute('foo')!
12 | } else {
13 | decoder.innerHTML = raw
14 | return decoder.textContent!
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packages/compiler-dom/src/runtimeHelpers.ts:
--------------------------------------------------------------------------------
1 | import { registerRuntimeHelpers } from '@vue/compiler-core'
2 |
3 | export const V_MODEL_RADIO: unique symbol = Symbol(__DEV__ ? `vModelRadio` : ``)
4 | export const V_MODEL_CHECKBOX: unique symbol = Symbol(
5 | __DEV__ ? `vModelCheckbox` : ``,
6 | )
7 | export const V_MODEL_TEXT: unique symbol = Symbol(__DEV__ ? `vModelText` : ``)
8 | export const V_MODEL_SELECT: unique symbol = Symbol(
9 | __DEV__ ? `vModelSelect` : ``,
10 | )
11 | export const V_MODEL_DYNAMIC: unique symbol = Symbol(
12 | __DEV__ ? `vModelDynamic` : ``,
13 | )
14 |
15 | export const V_ON_WITH_MODIFIERS: unique symbol = Symbol(
16 | __DEV__ ? `vOnModifiersGuard` : ``,
17 | )
18 | export const V_ON_WITH_KEYS: unique symbol = Symbol(
19 | __DEV__ ? `vOnKeysGuard` : ``,
20 | )
21 |
22 | export const V_SHOW: unique symbol = Symbol(__DEV__ ? `vShow` : ``)
23 |
24 | export const TRANSITION: unique symbol = Symbol(__DEV__ ? `Transition` : ``)
25 | export const TRANSITION_GROUP: unique symbol = Symbol(
26 | __DEV__ ? `TransitionGroup` : ``,
27 | )
28 |
29 | registerRuntimeHelpers({
30 | [V_MODEL_RADIO]: `vModelRadio`,
31 | [V_MODEL_CHECKBOX]: `vModelCheckbox`,
32 | [V_MODEL_TEXT]: `vModelText`,
33 | [V_MODEL_SELECT]: `vModelSelect`,
34 | [V_MODEL_DYNAMIC]: `vModelDynamic`,
35 | [V_ON_WITH_MODIFIERS]: `withModifiers`,
36 | [V_ON_WITH_KEYS]: `withKeys`,
37 | [V_SHOW]: `vShow`,
38 | [TRANSITION]: `Transition`,
39 | [TRANSITION_GROUP]: `TransitionGroup`,
40 | })
41 |
--------------------------------------------------------------------------------
/packages/compiler-dom/src/transforms/ignoreSideEffectTags.ts:
--------------------------------------------------------------------------------
1 | import { ElementTypes, type NodeTransform, NodeTypes } from '@vue/compiler-core'
2 | import { DOMErrorCodes, createDOMCompilerError } from '../errors'
3 |
4 | export const ignoreSideEffectTags: NodeTransform = (node, context) => {
5 | if (
6 | node.type === NodeTypes.ELEMENT &&
7 | node.tagType === ElementTypes.ELEMENT &&
8 | (node.tag === 'script' || node.tag === 'style')
9 | ) {
10 | __DEV__ &&
11 | context.onError(
12 | createDOMCompilerError(
13 | DOMErrorCodes.X_IGNORED_SIDE_EFFECT_TAG,
14 | node.loc,
15 | ),
16 | )
17 | context.removeNode()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/packages/compiler-dom/src/transforms/transformStyle.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ConstantTypes,
3 | type NodeTransform,
4 | NodeTypes,
5 | type SimpleExpressionNode,
6 | type SourceLocation,
7 | createSimpleExpression,
8 | } from '@vue/compiler-core'
9 | import { parseStringStyle } from '@vue/shared'
10 |
11 | // Parse inline CSS strings for static style attributes into an object.
12 | // This is a NodeTransform since it works on the static `style` attribute and
13 | // converts it into a dynamic equivalent:
14 | // style="color: red" -> :style='{ "color": "red" }'
15 | // It is then processed by `transformElement` and included in the generated
16 | // props.
17 | export const transformStyle: NodeTransform = node => {
18 | if (node.type === NodeTypes.ELEMENT) {
19 | node.props.forEach((p, i) => {
20 | if (p.type === NodeTypes.ATTRIBUTE && p.name === 'style' && p.value) {
21 | // replace p with an expression node
22 | node.props[i] = {
23 | type: NodeTypes.DIRECTIVE,
24 | name: `bind`,
25 | arg: createSimpleExpression(`style`, true, p.loc),
26 | exp: parseInlineCSS(p.value.content, p.loc),
27 | modifiers: [],
28 | loc: p.loc,
29 | }
30 | }
31 | })
32 | }
33 | }
34 |
35 | const parseInlineCSS = (
36 | cssText: string,
37 | loc: SourceLocation,
38 | ): SimpleExpressionNode => {
39 | const normalized = parseStringStyle(cssText)
40 | return createSimpleExpression(
41 | JSON.stringify(normalized),
42 | false,
43 | loc,
44 | ConstantTypes.CAN_STRINGIFY,
45 | )
46 | }
47 |
--------------------------------------------------------------------------------
/packages/compiler-dom/src/transforms/vHtml.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type DirectiveTransform,
3 | createObjectProperty,
4 | createSimpleExpression,
5 | } from '@vue/compiler-core'
6 | import { DOMErrorCodes, createDOMCompilerError } from '../errors'
7 |
8 | export const transformVHtml: DirectiveTransform = (dir, node, context) => {
9 | const { exp, loc } = dir
10 | if (!exp) {
11 | context.onError(
12 | createDOMCompilerError(DOMErrorCodes.X_V_HTML_NO_EXPRESSION, loc),
13 | )
14 | }
15 | if (node.children.length) {
16 | context.onError(
17 | createDOMCompilerError(DOMErrorCodes.X_V_HTML_WITH_CHILDREN, loc),
18 | )
19 | node.children.length = 0
20 | }
21 | return {
22 | props: [
23 | createObjectProperty(
24 | createSimpleExpression(`innerHTML`, true, loc),
25 | exp || createSimpleExpression('', true),
26 | ),
27 | ],
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/packages/compiler-dom/src/transforms/vShow.ts:
--------------------------------------------------------------------------------
1 | import type { DirectiveTransform } from '@vue/compiler-core'
2 | import { DOMErrorCodes, createDOMCompilerError } from '../errors'
3 | import { V_SHOW } from '../runtimeHelpers'
4 |
5 | export const transformShow: DirectiveTransform = (dir, node, context) => {
6 | const { exp, loc } = dir
7 | if (!exp) {
8 | context.onError(
9 | createDOMCompilerError(DOMErrorCodes.X_V_SHOW_NO_EXPRESSION, loc),
10 | )
11 | }
12 |
13 | return {
14 | props: [],
15 | needRuntime: context.helper(V_SHOW),
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/packages/compiler-dom/src/transforms/vText.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type DirectiveTransform,
3 | TO_DISPLAY_STRING,
4 | createCallExpression,
5 | createObjectProperty,
6 | createSimpleExpression,
7 | getConstantType,
8 | } from '@vue/compiler-core'
9 | import { DOMErrorCodes, createDOMCompilerError } from '../errors'
10 |
11 | export const transformVText: DirectiveTransform = (dir, node, context) => {
12 | const { exp, loc } = dir
13 | if (!exp) {
14 | context.onError(
15 | createDOMCompilerError(DOMErrorCodes.X_V_TEXT_NO_EXPRESSION, loc),
16 | )
17 | }
18 | if (node.children.length) {
19 | context.onError(
20 | createDOMCompilerError(DOMErrorCodes.X_V_TEXT_WITH_CHILDREN, loc),
21 | )
22 | node.children.length = 0
23 | }
24 | return {
25 | props: [
26 | createObjectProperty(
27 | createSimpleExpression(`textContent`, true),
28 | exp
29 | ? getConstantType(exp, context) > 0
30 | ? exp
31 | : createCallExpression(
32 | context.helperString(TO_DISPLAY_STRING),
33 | [exp],
34 | loc,
35 | )
36 | : createSimpleExpression('', true),
37 | ),
38 | ],
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/packages/compiler-dom/src/transforms/validateHtmlNesting.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type CompilerError,
3 | ElementTypes,
4 | type NodeTransform,
5 | NodeTypes,
6 | } from '@vue/compiler-core'
7 | import { isValidHTMLNesting } from '../htmlNesting'
8 |
9 | export const validateHtmlNesting: NodeTransform = (node, context) => {
10 | if (
11 | node.type === NodeTypes.ELEMENT &&
12 | node.tagType === ElementTypes.ELEMENT &&
13 | context.parent &&
14 | context.parent.type === NodeTypes.ELEMENT &&
15 | context.parent.tagType === ElementTypes.ELEMENT &&
16 | !isValidHTMLNesting(context.parent.tag, node.tag)
17 | ) {
18 | const error = new SyntaxError(
19 | `<${node.tag}> cannot be child of <${context.parent.tag}>, ` +
20 | 'according to HTML specifications. ' +
21 | 'This can cause hydration errors or ' +
22 | 'potentially disrupt future functionality.',
23 | ) as CompilerError
24 | error.loc = node.loc
25 | context.onWarn(error)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/packages/compiler-sfc/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineExpose.spec.ts.snap:
--------------------------------------------------------------------------------
1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2 |
3 | exports[`
8 | `)
9 | assertCode(content)
10 | // should remove defineOptions import and call
11 | expect(content).not.toMatch('defineExpose')
12 | // should generate correct setup signature
13 | expect(content).toMatch(`setup(__props, { expose: __expose }) {`)
14 | // should replace callee
15 | expect(content).toMatch(/\b__expose\(\{ foo: 123 \}\)/)
16 | })
17 |
18 | test('
23 |
24 | `)
25 | assertCode(content)
26 | })
27 |
--------------------------------------------------------------------------------
/packages/compiler-sfc/__tests__/compileScript/defineSlots.spec.ts:
--------------------------------------------------------------------------------
1 | import { assertCode, compileSFCScript as compile } from '../utils'
2 |
3 | describe('defineSlots()', () => {
4 | test('basic usage', () => {
5 | const { content } = compile(`
6 |
11 | `)
12 | assertCode(content)
13 | expect(content).toMatch(`const slots = _useSlots()`)
14 | expect(content).not.toMatch('defineSlots')
15 | })
16 |
17 | test('w/o return value', () => {
18 | const { content } = compile(`
19 |
24 | `)
25 | assertCode(content)
26 | expect(content).not.toMatch('defineSlots')
27 | expect(content).not.toMatch(`_useSlots`)
28 | })
29 |
30 | test('w/o generic params', () => {
31 | const { content } = compile(`
32 |
35 | `)
36 | assertCode(content)
37 | expect(content).toMatch(`const slots = _useSlots()`)
38 | expect(content).not.toMatch('defineSlots')
39 | })
40 | })
41 |
--------------------------------------------------------------------------------
/packages/compiler-sfc/__tests__/fixture/import.scss:
--------------------------------------------------------------------------------
1 | div {
2 | color: red;
3 | }
4 |
--------------------------------------------------------------------------------
/packages/compiler-sfc/__tests__/utils.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type SFCParseOptions,
3 | type SFCScriptCompileOptions,
4 | compileScript,
5 | parse,
6 | } from '../src'
7 | import { parse as babelParse } from '@babel/parser'
8 |
9 | export const mockId = 'xxxxxxxx'
10 |
11 | export function compileSFCScript(
12 | src: string,
13 | options?: Partial
,
14 | parseOptions?: SFCParseOptions,
15 | ) {
16 | const { descriptor, errors } = parse(src, parseOptions)
17 | if (errors.length) {
18 | console.warn(errors[0])
19 | }
20 | return compileScript(descriptor, {
21 | ...options,
22 | id: mockId,
23 | })
24 | }
25 |
26 | export function assertCode(code: string) {
27 | // parse the generated code to make sure it is valid
28 | try {
29 | babelParse(code, {
30 | sourceType: 'module',
31 | plugins: [
32 | 'typescript',
33 | ['importAttributes', { deprecatedAssertSyntax: true }],
34 | ],
35 | })
36 | } catch (e: any) {
37 | console.log(code)
38 | throw e
39 | }
40 | expect(code).toMatchSnapshot()
41 | }
42 |
--------------------------------------------------------------------------------
/packages/compiler-sfc/src/cache.ts:
--------------------------------------------------------------------------------
1 | import { LRUCache } from 'lru-cache'
2 |
3 | export function createCache(
4 | max = 500,
5 | ): Map | LRUCache {
6 | if (__GLOBAL__ || __ESM_BROWSER__) {
7 | return new Map()
8 | }
9 | return new LRUCache({ max })
10 | }
11 |
--------------------------------------------------------------------------------
/packages/compiler-sfc/src/script/defineExpose.ts:
--------------------------------------------------------------------------------
1 | import type { Node } from '@babel/types'
2 | import { isCallOf } from './utils'
3 | import type { ScriptCompileContext } from './context'
4 |
5 | export const DEFINE_EXPOSE = 'defineExpose'
6 |
7 | export function processDefineExpose(
8 | ctx: ScriptCompileContext,
9 | node: Node,
10 | ): boolean {
11 | if (isCallOf(node, DEFINE_EXPOSE)) {
12 | if (ctx.hasDefineExposeCall) {
13 | ctx.error(`duplicate ${DEFINE_EXPOSE}() call`, node)
14 | }
15 | ctx.hasDefineExposeCall = true
16 | return true
17 | }
18 | return false
19 | }
20 |
--------------------------------------------------------------------------------
/packages/compiler-sfc/src/script/defineSlots.ts:
--------------------------------------------------------------------------------
1 | import type { LVal, Node } from '@babel/types'
2 | import { isCallOf } from './utils'
3 | import type { ScriptCompileContext } from './context'
4 |
5 | export const DEFINE_SLOTS = 'defineSlots'
6 |
7 | export function processDefineSlots(
8 | ctx: ScriptCompileContext,
9 | node: Node,
10 | declId?: LVal,
11 | ): boolean {
12 | if (!isCallOf(node, DEFINE_SLOTS)) {
13 | return false
14 | }
15 | if (ctx.hasDefineSlotsCall) {
16 | ctx.error(`duplicate ${DEFINE_SLOTS}() call`, node)
17 | }
18 | ctx.hasDefineSlotsCall = true
19 |
20 | if (node.arguments.length > 0) {
21 | ctx.error(`${DEFINE_SLOTS}() cannot accept arguments`, node)
22 | }
23 |
24 | if (declId) {
25 | ctx.s.overwrite(
26 | ctx.startOffset! + node.start!,
27 | ctx.startOffset! + node.end!,
28 | `${ctx.helper('useSlots')}()`,
29 | )
30 | }
31 |
32 | return true
33 | }
34 |
--------------------------------------------------------------------------------
/packages/compiler-sfc/src/shims.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'merge-source-map' {
2 | export default function merge(oldMap: object, newMap: object): object
3 | }
4 |
--------------------------------------------------------------------------------
/packages/compiler-sfc/src/style/pluginTrim.ts:
--------------------------------------------------------------------------------
1 | import type { PluginCreator } from 'postcss'
2 |
3 | const trimPlugin: PluginCreator<{}> = () => {
4 | return {
5 | postcssPlugin: 'vue-sfc-trim',
6 | Once(root) {
7 | root.walk(({ type, raws }) => {
8 | if (type === 'rule' || type === 'atrule') {
9 | if (raws.before) raws.before = '\n'
10 | if ('after' in raws && raws.after) raws.after = '\n'
11 | }
12 | })
13 | },
14 | }
15 | }
16 |
17 | trimPlugin.postcss = true
18 | export default trimPlugin
19 |
--------------------------------------------------------------------------------
/packages/compiler-sfc/src/template/templateUtils.ts:
--------------------------------------------------------------------------------
1 | import { type UrlWithStringQuery, parse as uriParse } from 'url'
2 | import { isString } from '@vue/shared'
3 |
4 | export function isRelativeUrl(url: string): boolean {
5 | const firstChar = url.charAt(0)
6 | return firstChar === '.' || firstChar === '~' || firstChar === '@'
7 | }
8 |
9 | const externalRE = /^(https?:)?\/\//
10 | export function isExternalUrl(url: string): boolean {
11 | return externalRE.test(url)
12 | }
13 |
14 | const dataUrlRE = /^\s*data:/i
15 | export function isDataUrl(url: string): boolean {
16 | return dataUrlRE.test(url)
17 | }
18 |
19 | /**
20 | * Parses string url into URL object.
21 | */
22 | export function parseUrl(url: string): UrlWithStringQuery {
23 | const firstChar = url.charAt(0)
24 | if (firstChar === '~') {
25 | const secondChar = url.charAt(1)
26 | url = url.slice(secondChar === '/' ? 2 : 1)
27 | }
28 | return parseUriParts(url)
29 | }
30 |
31 | /**
32 | * vuejs/component-compiler-utils#22 Support uri fragment in transformed require
33 | * @param urlString - an url as a string
34 | */
35 | function parseUriParts(urlString: string): UrlWithStringQuery {
36 | // A TypeError is thrown if urlString is not a string
37 | // @see https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost
38 | return uriParse(isString(urlString) ? urlString : '', false, true)
39 | }
40 |
--------------------------------------------------------------------------------
/packages/compiler-sfc/src/warn.ts:
--------------------------------------------------------------------------------
1 | const hasWarned: Record = {}
2 |
3 | export function warnOnce(msg: string): void {
4 | const isNodeProd =
5 | typeof process !== 'undefined' && process.env.NODE_ENV === 'production'
6 | if (!isNodeProd && !__TEST__ && !hasWarned[msg]) {
7 | hasWarned[msg] = true
8 | warn(msg)
9 | }
10 | }
11 |
12 | export function warn(msg: string): void {
13 | console.warn(
14 | `\x1b[1m\x1b[33m[@vue/compiler-sfc]\x1b[0m\x1b[33m ${msg}\x1b[0m\n`,
15 | )
16 | }
17 |
--------------------------------------------------------------------------------
/packages/compiler-ssr/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/compiler-ssr/README.md:
--------------------------------------------------------------------------------
1 | # @vue/compiler-ssr
2 |
--------------------------------------------------------------------------------
/packages/compiler-ssr/__tests__/ssrPortal.spec.ts:
--------------------------------------------------------------------------------
1 | import { compile } from '../src'
2 |
3 | describe('ssr compile: teleport', () => {
4 | test('should work', () => {
5 | expect(compile(`
`).code)
6 | .toMatchInlineSnapshot(`
7 | "const { ssrRenderTeleport: _ssrRenderTeleport } = require("vue/server-renderer")
8 |
9 | return function ssrRender(_ctx, _push, _parent, _attrs) {
10 | _ssrRenderTeleport(_push, (_push) => {
11 | _push(\`
\`)
12 | }, _ctx.target, false, _parent)
13 | }"
14 | `)
15 | })
16 |
17 | test('disabled prop handling', () => {
18 | expect(compile(`
`).code)
19 | .toMatchInlineSnapshot(`
20 | "const { ssrRenderTeleport: _ssrRenderTeleport } = require("vue/server-renderer")
21 |
22 | return function ssrRender(_ctx, _push, _parent, _attrs) {
23 | _ssrRenderTeleport(_push, (_push) => {
24 | _push(\`
\`)
25 | }, _ctx.target, true, _parent)
26 | }"
27 | `)
28 |
29 | expect(
30 | compile(`
`).code,
31 | ).toMatchInlineSnapshot(`
32 | "const { ssrRenderTeleport: _ssrRenderTeleport } = require("vue/server-renderer")
33 |
34 | return function ssrRender(_ctx, _push, _parent, _attrs) {
35 | _ssrRenderTeleport(_push, (_push) => {
36 | _push(\`
\`)
37 | }, _ctx.target, _ctx.foo, _parent)
38 | }"
39 | `)
40 | })
41 | })
42 |
--------------------------------------------------------------------------------
/packages/compiler-ssr/__tests__/ssrTransition.spec.ts:
--------------------------------------------------------------------------------
1 | import { compile } from '../src'
2 |
3 | describe('transition', () => {
4 | test('basic', () => {
5 | expect(compile(`foo
`).code)
6 | .toMatchInlineSnapshot(`
7 | "const { ssrRenderAttrs: _ssrRenderAttrs } = require("vue/server-renderer")
8 |
9 | return function ssrRender(_ctx, _push, _parent, _attrs) {
10 | _push(\`foo
\`)
11 | }"
12 | `)
13 | })
14 |
15 | test('with appear', () => {
16 | expect(compile(`foo
`).code)
17 | .toMatchInlineSnapshot(`
18 | "const { ssrRenderAttrs: _ssrRenderAttrs } = require("vue/server-renderer")
19 |
20 | return function ssrRender(_ctx, _push, _parent, _attrs) {
21 | _push(\`foo
\`)
22 | }"
23 | `)
24 | })
25 | })
26 |
--------------------------------------------------------------------------------
/packages/compiler-ssr/__tests__/utils.ts:
--------------------------------------------------------------------------------
1 | import { compile } from '../src'
2 |
3 | export function getCompiledString(src: string): string {
4 | // Wrap src template in a root div so that it doesn't get injected
5 | // fallthrough attr. This results in less noise in generated snapshots
6 | // but also means this util can only be used for non-root cases.
7 | const { code } = compile(`${src}
`)
8 | const match = code.match(
9 | /_push\(\`([^]*)<\/div>\`\)/,
10 | )
11 |
12 | if (!match) {
13 | throw new Error(`Unexpected compile result:\n${code}`)
14 | }
15 |
16 | return `\`${match[1]}\``
17 | }
18 |
--------------------------------------------------------------------------------
/packages/compiler-ssr/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue/compiler-ssr",
3 | "version": "3.5.0-beta.2",
4 | "description": "@vue/compiler-ssr",
5 | "main": "dist/compiler-ssr.cjs.js",
6 | "types": "dist/compiler-ssr.d.ts",
7 | "files": [
8 | "dist"
9 | ],
10 | "buildOptions": {
11 | "prod": false,
12 | "formats": [
13 | "cjs"
14 | ]
15 | },
16 | "repository": {
17 | "type": "git",
18 | "url": "git+https://github.com/vuejs/core.git",
19 | "directory": "packages/compiler-ssr"
20 | },
21 | "keywords": [
22 | "vue"
23 | ],
24 | "author": "Evan You",
25 | "license": "MIT",
26 | "bugs": {
27 | "url": "https://github.com/vuejs/core/issues"
28 | },
29 | "homepage": "https://github.com/vuejs/core/tree/main/packages/compiler-ssr#readme",
30 | "dependencies": {
31 | "@vue/shared": "workspace:*",
32 | "@vue/compiler-dom": "workspace:*"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/packages/compiler-ssr/src/errors.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type CompilerError,
3 | DOMErrorCodes,
4 | type SourceLocation,
5 | createCompilerError,
6 | } from '@vue/compiler-dom'
7 |
8 | export interface SSRCompilerError extends CompilerError {
9 | code: SSRErrorCodes
10 | }
11 |
12 | export function createSSRCompilerError(
13 | code: SSRErrorCodes,
14 | loc?: SourceLocation,
15 | ) {
16 | return createCompilerError(code, loc, SSRErrorMessages) as SSRCompilerError
17 | }
18 |
19 | export enum SSRErrorCodes {
20 | X_SSR_UNSAFE_ATTR_NAME = 65 /* DOMErrorCodes.__EXTEND_POINT__ */,
21 | X_SSR_NO_TELEPORT_TARGET,
22 | X_SSR_INVALID_AST_NODE,
23 | }
24 |
25 | if (__TEST__) {
26 | // esbuild cannot infer enum increments if first value is from another
27 | // file, so we have to manually keep them in sync. this check ensures it
28 | // errors out if there are collisions.
29 | if (SSRErrorCodes.X_SSR_UNSAFE_ATTR_NAME < DOMErrorCodes.__EXTEND_POINT__) {
30 | throw new Error(
31 | `SSRErrorCodes need to be updated to ${
32 | DOMErrorCodes.__EXTEND_POINT__ + 1
33 | } to match extension point from core DOMErrorCodes.`,
34 | )
35 | }
36 | }
37 |
38 | export const SSRErrorMessages: { [code: number]: string } = {
39 | [SSRErrorCodes.X_SSR_UNSAFE_ATTR_NAME]: `Unsafe attribute name for SSR.`,
40 | [SSRErrorCodes.X_SSR_NO_TELEPORT_TARGET]: `Missing the 'to' prop on teleport element.`,
41 | [SSRErrorCodes.X_SSR_INVALID_AST_NODE]: `Invalid AST node during SSR transform.`,
42 | }
43 |
--------------------------------------------------------------------------------
/packages/compiler-ssr/src/transforms/ssrTransformTransition.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type ComponentNode,
3 | NodeTypes,
4 | type TransformContext,
5 | findProp,
6 | } from '@vue/compiler-dom'
7 | import {
8 | type SSRTransformContext,
9 | processChildren,
10 | } from '../ssrCodegenTransform'
11 |
12 | const wipMap = new WeakMap
()
13 |
14 | export function ssrTransformTransition(
15 | node: ComponentNode,
16 | context: TransformContext,
17 | ) {
18 | return (): void => {
19 | const appear = findProp(node, 'appear', false, true)
20 | wipMap.set(node, !!appear)
21 | }
22 | }
23 |
24 | export function ssrProcessTransition(
25 | node: ComponentNode,
26 | context: SSRTransformContext,
27 | ): void {
28 | // #5351: filter out comment children inside transition
29 | node.children = node.children.filter(c => c.type !== NodeTypes.COMMENT)
30 |
31 | const appear = wipMap.get(node)
32 | if (appear) {
33 | context.pushStringPart(``)
34 | processChildren(node, context, false, true)
35 | context.pushStringPart(` `)
36 | } else {
37 | processChildren(node, context, false, true)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/compiler-ssr/src/transforms/ssrVFor.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type ForNode,
3 | type NodeTransform,
4 | NodeTypes,
5 | createCallExpression,
6 | createForLoopParams,
7 | createFunctionExpression,
8 | createStructuralDirectiveTransform,
9 | processFor,
10 | } from '@vue/compiler-dom'
11 | import {
12 | type SSRTransformContext,
13 | processChildrenAsStatement,
14 | } from '../ssrCodegenTransform'
15 | import { SSR_RENDER_LIST } from '../runtimeHelpers'
16 |
17 | // Plugin for the first transform pass, which simply constructs the AST node
18 | export const ssrTransformFor: NodeTransform =
19 | createStructuralDirectiveTransform('for', processFor)
20 |
21 | // This is called during the 2nd transform pass to construct the SSR-specific
22 | // codegen nodes.
23 | export function ssrProcessFor(
24 | node: ForNode,
25 | context: SSRTransformContext,
26 | disableNestedFragments = false,
27 | ): void {
28 | const needFragmentWrapper =
29 | !disableNestedFragments &&
30 | (node.children.length !== 1 || node.children[0].type !== NodeTypes.ELEMENT)
31 | const renderLoop = createFunctionExpression(
32 | createForLoopParams(node.parseResult),
33 | )
34 | renderLoop.body = processChildrenAsStatement(
35 | node,
36 | context,
37 | needFragmentWrapper,
38 | )
39 | // v-for always renders a fragment unless explicitly disabled
40 | if (!disableNestedFragments) {
41 | context.pushStringPart(``)
42 | }
43 | context.pushStatement(
44 | createCallExpression(context.helper(SSR_RENDER_LIST), [
45 | node.source,
46 | renderLoop,
47 | ]),
48 | )
49 | if (!disableNestedFragments) {
50 | context.pushStringPart(``)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/packages/compiler-ssr/src/transforms/ssrVShow.ts:
--------------------------------------------------------------------------------
1 | import {
2 | DOMErrorCodes,
3 | type DirectiveTransform,
4 | createConditionalExpression,
5 | createDOMCompilerError,
6 | createObjectExpression,
7 | createObjectProperty,
8 | createSimpleExpression,
9 | } from '@vue/compiler-dom'
10 |
11 | export const ssrTransformShow: DirectiveTransform = (dir, node, context) => {
12 | if (!dir.exp) {
13 | context.onError(
14 | createDOMCompilerError(DOMErrorCodes.X_V_SHOW_NO_EXPRESSION),
15 | )
16 | }
17 | return {
18 | props: [
19 | createObjectProperty(
20 | `style`,
21 | createConditionalExpression(
22 | dir.exp!,
23 | createSimpleExpression(`null`, false),
24 | createObjectExpression([
25 | createObjectProperty(
26 | `display`,
27 | createSimpleExpression(`none`, true),
28 | ),
29 | ]),
30 | false /* no newline */,
31 | ),
32 | ),
33 | ],
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/packages/global.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | // Global compile-time constants
4 | declare var __DEV__: boolean
5 | declare var __TEST__: boolean
6 | declare var __BROWSER__: boolean
7 | declare var __GLOBAL__: boolean
8 | declare var __ESM_BUNDLER__: boolean
9 | declare var __ESM_BROWSER__: boolean
10 | declare var __CJS__: boolean
11 | declare var __SSR__: boolean
12 | declare var __COMMIT__: string
13 | declare var __VERSION__: string
14 | declare var __COMPAT__: boolean
15 |
16 | // Feature flags
17 | declare var __FEATURE_OPTIONS_API__: boolean
18 | declare var __FEATURE_PROD_DEVTOOLS__: boolean
19 | declare var __FEATURE_SUSPENSE__: boolean
20 | declare var __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__: boolean
21 |
22 | declare module '*.vue' {}
23 |
24 | declare module 'file-saver' {
25 | export function saveAs(blob: any, name: any): void
26 | }
27 |
28 | declare module 'estree-walker' {
29 | export function walk(
30 | root: T,
31 | options: {
32 | enter?: (node: T, parent: T | null) => any
33 | leave?: (node: T, parent: T | null) => any
34 | exit?: (node: T) => any
35 | } & ThisType<{ skip: () => void }>,
36 | )
37 | }
38 |
39 | declare interface String {
40 | /**
41 | * @deprecated Please use String.prototype.slice instead of String.prototype.substring in the repository.
42 | */
43 | substring(start: number, end?: number): string
44 | }
45 |
--------------------------------------------------------------------------------
/packages/reactivity/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/reactivity/README.md:
--------------------------------------------------------------------------------
1 | # @vue/reactivity
2 |
3 | ## Usage Note
4 |
5 | This package is inlined into Global & Browser ESM builds of user-facing renderers (e.g. `@vue/runtime-dom`), but also published as a package that can be used standalone. The standalone build should not be used alongside a pre-bundled build of a user-facing renderer, as they will have different internal storage for reactivity connections. A user-facing renderer should re-export all APIs from this package.
6 |
7 | For full exposed APIs, see `src/index.ts`.
8 |
9 | ## Credits
10 |
11 | The implementation of this module is inspired by the following prior art in the JavaScript ecosystem:
12 |
13 | - [Meteor Tracker](https://docs.meteor.com/api/tracker.html)
14 | - [nx-js/observer-util](https://github.com/nx-js/observer-util)
15 | - [salesforce/observable-membrane](https://github.com/salesforce/observable-membrane)
16 |
17 | ## Caveats
18 |
19 | - Built-in objects are not observed except for `Array`, `Map`, `WeakMap`, `Set` and `WeakSet`.
20 |
--------------------------------------------------------------------------------
/packages/reactivity/__benchmarks__/reactiveObject.bench.ts:
--------------------------------------------------------------------------------
1 | import { bench } from 'vitest'
2 | import { reactive } from '../src'
3 |
4 | bench('create reactive obj', () => {
5 | reactive({ a: 1 })
6 | })
7 |
8 | {
9 | const r = reactive({ a: 1 })
10 | bench('read reactive obj property', () => {
11 | r.a
12 | })
13 | }
14 |
15 | {
16 | let i = 0
17 | const r = reactive({ a: 1 })
18 | bench('write reactive obj property', () => {
19 | r.a = i++
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/packages/reactivity/__benchmarks__/ref.bench.ts:
--------------------------------------------------------------------------------
1 | import { bench, describe } from 'vitest'
2 | import { ref } from '../src/index'
3 |
4 | describe('ref', () => {
5 | bench('create ref', () => {
6 | ref(100)
7 | })
8 |
9 | {
10 | let i = 0
11 | const v = ref(100)
12 | bench('write ref', () => {
13 | v.value = i++
14 | })
15 | }
16 |
17 | {
18 | const v = ref(100)
19 | bench('read ref', () => {
20 | v.value
21 | })
22 | }
23 |
24 | {
25 | let i = 0
26 | const v = ref(100)
27 | bench('write/read ref', () => {
28 | v.value = i++
29 | v.value
30 | })
31 | }
32 | })
33 |
--------------------------------------------------------------------------------
/packages/reactivity/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | if (process.env.NODE_ENV === 'production') {
4 | module.exports = require('./dist/reactivity.cjs.prod.js')
5 | } else {
6 | module.exports = require('./dist/reactivity.cjs.js')
7 | }
8 |
--------------------------------------------------------------------------------
/packages/reactivity/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue/reactivity",
3 | "version": "3.5.0-beta.2",
4 | "description": "@vue/reactivity",
5 | "main": "index.js",
6 | "module": "dist/reactivity.esm-bundler.js",
7 | "types": "dist/reactivity.d.ts",
8 | "unpkg": "dist/reactivity.global.js",
9 | "jsdelivr": "dist/reactivity.global.js",
10 | "files": [
11 | "index.js",
12 | "dist"
13 | ],
14 | "exports": {
15 | ".": {
16 | "types": "./dist/reactivity.d.ts",
17 | "node": {
18 | "production": "./dist/reactivity.cjs.prod.js",
19 | "development": "./dist/reactivity.cjs.js",
20 | "default": "./index.js"
21 | },
22 | "module": "./dist/reactivity.esm-bundler.js",
23 | "import": "./dist/reactivity.esm-bundler.js",
24 | "require": "./index.js"
25 | },
26 | "./*": "./*"
27 | },
28 | "sideEffects": false,
29 | "repository": {
30 | "type": "git",
31 | "url": "git+https://github.com/vuejs/core.git",
32 | "directory": "packages/reactivity"
33 | },
34 | "buildOptions": {
35 | "name": "VueReactivity",
36 | "formats": [
37 | "esm-bundler",
38 | "esm-browser",
39 | "cjs",
40 | "global"
41 | ]
42 | },
43 | "keywords": [
44 | "vue"
45 | ],
46 | "author": "Evan You",
47 | "license": "MIT",
48 | "bugs": {
49 | "url": "https://github.com/vuejs/core/issues"
50 | },
51 | "homepage": "https://github.com/vuejs/core/tree/main/packages/reactivity#readme",
52 | "dependencies": {
53 | "@vue/shared": "workspace:*"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/packages/reactivity/src/constants.ts:
--------------------------------------------------------------------------------
1 | // using literal strings instead of numbers so that it's easier to inspect
2 | // debugger events
3 |
4 | export enum TrackOpTypes {
5 | GET = 'get',
6 | HAS = 'has',
7 | ITERATE = 'iterate',
8 | }
9 |
10 | export enum TriggerOpTypes {
11 | SET = 'set',
12 | ADD = 'add',
13 | DELETE = 'delete',
14 | CLEAR = 'clear',
15 | }
16 |
17 | export enum ReactiveFlags {
18 | SKIP = '__v_skip',
19 | IS_REACTIVE = '__v_isReactive',
20 | IS_READONLY = '__v_isReadonly',
21 | IS_SHALLOW = '__v_isShallow',
22 | RAW = '__v_raw',
23 | IS_REF = '__v_isRef',
24 | }
25 |
--------------------------------------------------------------------------------
/packages/reactivity/src/warning.ts:
--------------------------------------------------------------------------------
1 | export function warn(msg: string, ...args: any[]): void {
2 | console.warn(`[Vue warn] ${msg}`, ...args)
3 | }
4 |
--------------------------------------------------------------------------------
/packages/runtime-core/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/runtime-core/README.md:
--------------------------------------------------------------------------------
1 | # @vue/runtime-core
2 |
3 | > This package is published only for typing and building custom renderers. It is NOT meant to be used in applications.
4 |
5 | For full exposed APIs, see `src/index.ts`.
6 |
7 | ## Building a Custom Renderer
8 |
9 | ```ts
10 | import { createRenderer } from '@vue/runtime-core'
11 |
12 | const { render, createApp } = createRenderer({
13 | patchProp,
14 | insert,
15 | remove,
16 | createElement,
17 | // ...
18 | })
19 |
20 | // `render` is the low-level API
21 | // `createApp` returns an app instance with configurable context shared
22 | // by the entire app tree.
23 | export { render, createApp }
24 |
25 | export * from '@vue/runtime-core'
26 | ```
27 |
28 | See `@vue/runtime-dom` for how a DOM-targeting renderer is implemented.
29 |
--------------------------------------------------------------------------------
/packages/runtime-core/__tests__/apiWatch.bench.ts:
--------------------------------------------------------------------------------
1 | import { nextTick, ref, watch, watchEffect } from '../src'
2 | import { bench } from 'vitest'
3 |
4 | bench('create watcher', () => {
5 | const v = ref(100)
6 | watch(v, v => {})
7 | })
8 |
9 | {
10 | const v = ref(100)
11 | watch(v, v => {})
12 | let i = 0
13 | bench('update ref to trigger watcher (scheduled but not executed)', () => {
14 | v.value = i++
15 | })
16 | }
17 |
18 | {
19 | const v = ref(100)
20 | watch(v, v => {})
21 | let i = 0
22 | bench('update ref to trigger watcher (executed)', async () => {
23 | v.value = i++
24 | return nextTick()
25 | })
26 | }
27 |
28 | {
29 | bench('create watchEffect', () => {
30 | watchEffect(() => {})
31 | })
32 | }
33 |
34 | {
35 | const v = ref(100)
36 | watchEffect(() => {
37 | v.value
38 | })
39 | let i = 0
40 | bench(
41 | 'update ref to trigger watchEffect (scheduled but not executed)',
42 | () => {
43 | v.value = i++
44 | },
45 | )
46 | }
47 |
48 | {
49 | const v = ref(100)
50 | watchEffect(() => {
51 | v.value
52 | })
53 | let i = 0
54 | bench('update ref to trigger watchEffect (executed)', async () => {
55 | v.value = i++
56 | await nextTick()
57 | })
58 | }
59 |
--------------------------------------------------------------------------------
/packages/runtime-core/__tests__/helpers/toHandlers.spec.ts:
--------------------------------------------------------------------------------
1 | import { toHandlers } from '../../src/helpers/toHandlers'
2 |
3 | describe('toHandlers', () => {
4 | it('should not accept non-objects', () => {
5 | toHandlers(null as any)
6 | toHandlers(undefined as any)
7 |
8 | expect(
9 | 'v-on with no argument expects an object value.',
10 | ).toHaveBeenWarnedTimes(2)
11 | })
12 |
13 | it('should properly change object keys', () => {
14 | const input = () => {}
15 | const change = () => {}
16 |
17 | expect(toHandlers({ input, change })).toStrictEqual({
18 | onInput: input,
19 | onChange: change,
20 | })
21 | })
22 | })
23 |
--------------------------------------------------------------------------------
/packages/runtime-core/__tests__/misc.spec.ts:
--------------------------------------------------------------------------------
1 | import { h, isReactive, nodeOps, reactive, render } from '@vue/runtime-test'
2 |
3 | describe('misc', () => {
4 | test('component public instance should not be observable', () => {
5 | let instance: any
6 | const Comp = {
7 | render() {},
8 | mounted() {
9 | instance = this
10 | },
11 | }
12 | render(h(Comp), nodeOps.createElement('div'))
13 | expect(instance).toBeDefined()
14 | const r = reactive(instance)
15 | expect(r).toBe(instance)
16 | expect(isReactive(r)).toBe(false)
17 | })
18 | })
19 |
--------------------------------------------------------------------------------
/packages/runtime-core/__tests__/rendererElement.spec.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type TestElement,
3 | h,
4 | serializeInner as inner,
5 | nodeOps,
6 | render,
7 | } from '@vue/runtime-test'
8 |
9 | describe('renderer: element', () => {
10 | let root: TestElement
11 |
12 | beforeEach(() => {
13 | root = nodeOps.createElement('div')
14 | })
15 |
16 | it('should create an element', () => {
17 | render(h('div'), root)
18 | expect(inner(root)).toBe('
')
19 | })
20 |
21 | it('should create an element with props', () => {
22 | render(h('div', { id: 'foo', class: 'bar' }), root)
23 | expect(inner(root)).toBe('
')
24 | })
25 |
26 | it('should create an element with direct text children', () => {
27 | render(h('div', ['foo', ' ', 'bar']), root)
28 | expect(inner(root)).toBe('foo bar
')
29 | })
30 |
31 | it('should create an element with direct text children and props', () => {
32 | render(h('div', { id: 'foo' }, ['bar']), root)
33 | expect(inner(root)).toBe('bar
')
34 | })
35 |
36 | it('should update an element tag which is already mounted', () => {
37 | render(h('div', ['foo']), root)
38 | expect(inner(root)).toBe('foo
')
39 |
40 | render(h('span', ['foo']), root)
41 | expect(inner(root)).toBe('foo ')
42 | })
43 |
44 | it('should update element props which is already mounted', () => {
45 | render(h('div', { id: 'bar' }, ['foo']), root)
46 | expect(inner(root)).toBe('foo
')
47 |
48 | render(h('div', { id: 'baz', class: 'bar' }, ['foo']), root)
49 | expect(inner(root)).toBe('foo
')
50 | })
51 | })
52 |
--------------------------------------------------------------------------------
/packages/runtime-core/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | if (process.env.NODE_ENV === 'production') {
4 | module.exports = require('./dist/runtime-core.cjs.prod.js')
5 | } else {
6 | module.exports = require('./dist/runtime-core.cjs.js')
7 | }
8 |
--------------------------------------------------------------------------------
/packages/runtime-core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue/runtime-core",
3 | "version": "3.5.0-beta.2",
4 | "description": "@vue/runtime-core",
5 | "main": "index.js",
6 | "module": "dist/runtime-core.esm-bundler.js",
7 | "types": "dist/runtime-core.d.ts",
8 | "files": [
9 | "index.js",
10 | "dist"
11 | ],
12 | "exports": {
13 | ".": {
14 | "types": "./dist/runtime-core.d.ts",
15 | "node": {
16 | "production": "./dist/runtime-core.cjs.prod.js",
17 | "development": "./dist/runtime-core.cjs.js",
18 | "default": "./index.js"
19 | },
20 | "module": "./dist/runtime-core.esm-bundler.js",
21 | "import": "./dist/runtime-core.esm-bundler.js",
22 | "require": "./index.js"
23 | },
24 | "./*": "./*"
25 | },
26 | "buildOptions": {
27 | "name": "VueRuntimeCore",
28 | "formats": [
29 | "esm-bundler",
30 | "cjs"
31 | ]
32 | },
33 | "sideEffects": false,
34 | "repository": {
35 | "type": "git",
36 | "url": "git+https://github.com/vuejs/core.git",
37 | "directory": "packages/runtime-core"
38 | },
39 | "keywords": [
40 | "vue"
41 | ],
42 | "author": "Evan You",
43 | "license": "MIT",
44 | "bugs": {
45 | "url": "https://github.com/vuejs/core/issues"
46 | },
47 | "homepage": "https://github.com/vuejs/core/tree/main/packages/runtime-core#readme",
48 | "dependencies": {
49 | "@vue/shared": "workspace:*",
50 | "@vue/reactivity": "workspace:*"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/apiComputed.ts:
--------------------------------------------------------------------------------
1 | import { type ComputedRefImpl, computed as _computed } from '@vue/reactivity'
2 | import { getCurrentInstance, isInSSRComponentSetup } from './component'
3 |
4 | export const computed: typeof _computed = (
5 | getterOrOptions: any,
6 | debugOptions?: any,
7 | ) => {
8 | // @ts-expect-error
9 | const c = _computed(getterOrOptions, debugOptions, isInSSRComponentSetup)
10 | if (__DEV__) {
11 | const i = getCurrentInstance()
12 | if (i && i.appContext.config.warnRecursiveComputed) {
13 | ;(c as unknown as ComputedRefImpl)._warnRecursive = true
14 | }
15 | }
16 | return c as any
17 | }
18 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/compat/attrsFallthrough.ts:
--------------------------------------------------------------------------------
1 | import { isOn } from '@vue/shared'
2 | import type { ComponentInternalInstance } from '../component'
3 | import { DeprecationTypes, isCompatEnabled } from './compatConfig'
4 |
5 | export function shouldSkipAttr(
6 | key: string,
7 | instance: ComponentInternalInstance,
8 | ): boolean {
9 | if (key === 'is') {
10 | return true
11 | }
12 | if (
13 | (key === 'class' || key === 'style') &&
14 | isCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, instance)
15 | ) {
16 | return true
17 | }
18 | if (
19 | isOn(key) &&
20 | isCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, instance)
21 | ) {
22 | return true
23 | }
24 | // vue-router
25 | if (key.startsWith('routerView') || key === 'registerRouteInstance') {
26 | return true
27 | }
28 | return false
29 | }
30 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/compat/data.ts:
--------------------------------------------------------------------------------
1 | import { isPlainObject } from '@vue/shared'
2 | import { DeprecationTypes, warnDeprecation } from './compatConfig'
3 |
4 | export function deepMergeData(to: any, from: any): any {
5 | for (const key in from) {
6 | const toVal = to[key]
7 | const fromVal = from[key]
8 | if (key in to && isPlainObject(toVal) && isPlainObject(fromVal)) {
9 | __DEV__ && warnDeprecation(DeprecationTypes.OPTIONS_DATA_MERGE, null, key)
10 | deepMergeData(toVal, fromVal)
11 | } else {
12 | to[key] = fromVal
13 | }
14 | }
15 | return to
16 | }
17 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/compat/instanceChildren.ts:
--------------------------------------------------------------------------------
1 | import { ShapeFlags } from '@vue/shared'
2 | import type { ComponentInternalInstance } from '../component'
3 | import type { ComponentPublicInstance } from '../componentPublicInstance'
4 | import type { VNode } from '../vnode'
5 | import { DeprecationTypes, assertCompatEnabled } from './compatConfig'
6 |
7 | export function getCompatChildren(
8 | instance: ComponentInternalInstance,
9 | ): ComponentPublicInstance[] {
10 | assertCompatEnabled(DeprecationTypes.INSTANCE_CHILDREN, instance)
11 | const root = instance.subTree
12 | const children: ComponentPublicInstance[] = []
13 | if (root) {
14 | walk(root, children)
15 | }
16 | return children
17 | }
18 |
19 | function walk(vnode: VNode, children: ComponentPublicInstance[]) {
20 | if (vnode.component) {
21 | children.push(vnode.component.proxy!)
22 | } else if (vnode.shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
23 | const vnodes = vnode.children as VNode[]
24 | for (let i = 0; i < vnodes.length; i++) {
25 | walk(vnodes[i], children)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/compat/instanceListeners.ts:
--------------------------------------------------------------------------------
1 | import { isOn } from '@vue/shared'
2 | import type { ComponentInternalInstance } from '../component'
3 | import { DeprecationTypes, assertCompatEnabled } from './compatConfig'
4 |
5 | export function getCompatListeners(
6 | instance: ComponentInternalInstance,
7 | ): Record {
8 | assertCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, instance)
9 |
10 | const listeners: Record = {}
11 | const rawProps = instance.vnode.props
12 | if (!rawProps) {
13 | return listeners
14 | }
15 | for (const key in rawProps) {
16 | if (isOn(key)) {
17 | listeners[key[2].toLowerCase() + key.slice(3)] = rawProps[key]
18 | }
19 | }
20 | return listeners
21 | }
22 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/compat/props.ts:
--------------------------------------------------------------------------------
1 | import { isArray } from '@vue/shared'
2 | import { inject } from '../apiInject'
3 | import type { ComponentInternalInstance, Data } from '../component'
4 | import {
5 | type ComponentOptions,
6 | resolveMergedOptions,
7 | } from '../componentOptions'
8 | import { DeprecationTypes, warnDeprecation } from './compatConfig'
9 |
10 | export function createPropsDefaultThis(
11 | instance: ComponentInternalInstance,
12 | rawProps: Data,
13 | propKey: string,
14 | ): object {
15 | return new Proxy(
16 | {},
17 | {
18 | get(_, key: string) {
19 | __DEV__ &&
20 | warnDeprecation(DeprecationTypes.PROPS_DEFAULT_THIS, null, propKey)
21 | // $options
22 | if (key === '$options') {
23 | return resolveMergedOptions(instance)
24 | }
25 | // props
26 | if (key in rawProps) {
27 | return rawProps[key]
28 | }
29 | // injections
30 | const injections = (instance.type as ComponentOptions).inject
31 | if (injections) {
32 | if (isArray(injections)) {
33 | if (injections.includes(key)) {
34 | return inject(key)
35 | }
36 | } else if (key in injections) {
37 | return inject(key)
38 | }
39 | }
40 | },
41 | },
42 | )
43 | }
44 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/enums.ts:
--------------------------------------------------------------------------------
1 | export enum LifecycleHooks {
2 | BEFORE_CREATE = 'bc',
3 | CREATED = 'c',
4 | BEFORE_MOUNT = 'bm',
5 | MOUNTED = 'm',
6 | BEFORE_UPDATE = 'bu',
7 | UPDATED = 'u',
8 | BEFORE_UNMOUNT = 'bum',
9 | UNMOUNTED = 'um',
10 | DEACTIVATED = 'da',
11 | ACTIVATED = 'a',
12 | RENDER_TRIGGERED = 'rtg',
13 | RENDER_TRACKED = 'rtc',
14 | ERROR_CAPTURED = 'ec',
15 | SERVER_PREFETCH = 'sp',
16 | }
17 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/featureFlags.ts:
--------------------------------------------------------------------------------
1 | import { getGlobalThis } from '@vue/shared'
2 |
3 | /**
4 | * This is only called in esm-bundler builds.
5 | * It is called when a renderer is created, in `baseCreateRenderer` so that
6 | * importing runtime-core is side-effects free.
7 | *
8 | * istanbul-ignore-next
9 | */
10 | export function initFeatureFlags(): void {
11 | const needWarn = []
12 |
13 | if (typeof __FEATURE_OPTIONS_API__ !== 'boolean') {
14 | __DEV__ && needWarn.push(`__VUE_OPTIONS_API__`)
15 | getGlobalThis().__VUE_OPTIONS_API__ = true
16 | }
17 |
18 | if (typeof __FEATURE_PROD_DEVTOOLS__ !== 'boolean') {
19 | __DEV__ && needWarn.push(`__VUE_PROD_DEVTOOLS__`)
20 | getGlobalThis().__VUE_PROD_DEVTOOLS__ = false
21 | }
22 |
23 | if (typeof __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__ !== 'boolean') {
24 | __DEV__ && needWarn.push(`__VUE_PROD_HYDRATION_MISMATCH_DETAILS__`)
25 | getGlobalThis().__VUE_PROD_HYDRATION_MISMATCH_DETAILS__ = false
26 | }
27 |
28 | if (__DEV__ && needWarn.length) {
29 | const multi = needWarn.length > 1
30 | console.warn(
31 | `Feature flag${multi ? `s` : ``} ${needWarn.join(', ')} ${
32 | multi ? `are` : `is`
33 | } not explicitly defined. You are running the esm-bundler build of Vue, ` +
34 | `which expects these compile-time feature flags to be globally injected ` +
35 | `via the bundler config in order to get better tree-shaking in the ` +
36 | `production bundle.\n\n` +
37 | `For more details, see https://link.vuejs.org/feature-flags.`,
38 | )
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/helpers/createSlots.ts:
--------------------------------------------------------------------------------
1 | import { isArray } from '@vue/shared'
2 | import type { VNode } from '../vnode'
3 |
4 | // #6651 res can be undefined in SSR in string push mode
5 | type SSRSlot = (...args: any[]) => VNode[] | undefined
6 |
7 | interface CompiledSlotDescriptor {
8 | name: string
9 | fn: SSRSlot
10 | key?: string
11 | }
12 |
13 | /**
14 | * Compiler runtime helper for creating dynamic slots object
15 | * @private
16 | */
17 | export function createSlots(
18 | slots: Record,
19 | dynamicSlots: (
20 | | CompiledSlotDescriptor
21 | | CompiledSlotDescriptor[]
22 | | undefined
23 | )[],
24 | ): Record {
25 | for (let i = 0; i < dynamicSlots.length; i++) {
26 | const slot = dynamicSlots[i]
27 | // array of dynamic slot generated by
28 | if (isArray(slot)) {
29 | for (let j = 0; j < slot.length; j++) {
30 | slots[slot[j].name] = slot[j].fn
31 | }
32 | } else if (slot) {
33 | // conditional single slot generated by
34 | slots[slot.name] = slot.key
35 | ? (...args: any[]) => {
36 | const res = slot.fn(...args)
37 | // attach branch key so each conditional branch is considered a
38 | // different fragment
39 | if (res) (res as any).key = slot.key
40 | return res
41 | }
42 | : slot.fn
43 | }
44 | }
45 | return slots
46 | }
47 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/helpers/toHandlers.ts:
--------------------------------------------------------------------------------
1 | import { isObject, toHandlerKey } from '@vue/shared'
2 | import { warn } from '../warning'
3 |
4 | /**
5 | * For prefixing keys in v-on="obj" with "on"
6 | * @private
7 | */
8 | export function toHandlers(
9 | obj: Record,
10 | preserveCaseIfNecessary?: boolean,
11 | ): Record {
12 | const ret: Record = {}
13 | if (__DEV__ && !isObject(obj)) {
14 | warn(`v-on with no argument expects an object value.`)
15 | return ret
16 | }
17 | for (const key in obj) {
18 | ret[
19 | preserveCaseIfNecessary && /[A-Z]/.test(key)
20 | ? `on:${key}`
21 | : toHandlerKey(key)
22 | ] = obj[key]
23 | }
24 | return ret
25 | }
26 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/helpers/useId.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type ComponentInternalInstance,
3 | getCurrentInstance,
4 | } from '../component'
5 | import { warn } from '../warning'
6 |
7 | export function useId(): string | undefined {
8 | const i = getCurrentInstance()
9 | if (i) {
10 | return (i.appContext.config.idPrefix || 'v') + ':' + i.ids[0] + i.ids[1]++
11 | } else if (__DEV__) {
12 | warn(
13 | `useId() is called when there is no active component ` +
14 | `instance to be associated with.`,
15 | )
16 | }
17 | }
18 |
19 | /**
20 | * There are 3 types of async boundaries:
21 | * - async components
22 | * - components with async setup()
23 | * - components with serverPrefetch
24 | */
25 | export function markAsyncBoundary(instance: ComponentInternalInstance): void {
26 | instance.ids = [instance.ids[0] + instance.ids[2]++ + '-', 0, 0]
27 | }
28 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/helpers/useSsrContext.ts:
--------------------------------------------------------------------------------
1 | import { inject } from '../apiInject'
2 | import { warn } from '../warning'
3 |
4 | export const ssrContextKey: unique symbol = Symbol.for('v-scx')
5 |
6 | export const useSSRContext = >(): T | undefined => {
7 | if (!__GLOBAL__) {
8 | const ctx = inject(ssrContextKey)
9 | if (!ctx) {
10 | __DEV__ &&
11 | warn(
12 | `Server rendering context not provided. Make sure to only call ` +
13 | `useSSRContext() conditionally in the server build.`,
14 | )
15 | }
16 | return ctx
17 | } else if (__DEV__) {
18 | warn(`useSSRContext() is not supported in the global build.`)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/helpers/useTemplateRef.ts:
--------------------------------------------------------------------------------
1 | import { type ShallowRef, readonly, shallowRef } from '@vue/reactivity'
2 | import { getCurrentInstance } from '../component'
3 | import { warn } from '../warning'
4 | import { EMPTY_OBJ } from '@vue/shared'
5 |
6 | export function useTemplateRef(
7 | key: Keys,
8 | ): Readonly> {
9 | const i = getCurrentInstance()
10 | const r = shallowRef(null)
11 | if (i) {
12 | const refs = i.refs === EMPTY_OBJ ? (i.refs = {}) : i.refs
13 |
14 | let desc: PropertyDescriptor | undefined
15 | if (
16 | __DEV__ &&
17 | (desc = Object.getOwnPropertyDescriptor(refs, key)) &&
18 | !desc.configurable
19 | ) {
20 | warn(`useTemplateRef('${key}') already exists.`)
21 | } else {
22 | Object.defineProperty(refs, key, {
23 | enumerable: true,
24 | get: () => r.value,
25 | set: val => (r.value = val),
26 | })
27 | }
28 | } else if (__DEV__) {
29 | warn(
30 | `useTemplateRef() is called when there is no active component ` +
31 | `instance to be associated with.`,
32 | )
33 | }
34 | return (__DEV__ ? readonly(r) : r) as any
35 | }
36 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/helpers/withMemo.ts:
--------------------------------------------------------------------------------
1 | import { hasChanged } from '@vue/shared'
2 | import { type VNode, currentBlock, isBlockTreeEnabled } from '../vnode'
3 |
4 | export function withMemo(
5 | memo: any[],
6 | render: () => VNode,
7 | cache: any[],
8 | index: number,
9 | ): VNode {
10 | const cached = cache[index] as VNode | undefined
11 | if (cached && isMemoSame(cached, memo)) {
12 | return cached
13 | }
14 | const ret = render()
15 |
16 | // shallow clone
17 | ret.memo = memo.slice()
18 | ret.cacheIndex = index
19 |
20 | return (cache[index] = ret)
21 | }
22 |
23 | export function isMemoSame(cached: VNode, memo: any[]): boolean {
24 | const prev: any[] = cached.memo!
25 | if (prev.length != memo.length) {
26 | return false
27 | }
28 |
29 | for (let i = 0; i < prev.length; i++) {
30 | if (hasChanged(prev[i], memo[i])) {
31 | return false
32 | }
33 | }
34 |
35 | // make sure to let parent block track it when returning cached
36 | if (isBlockTreeEnabled > 0 && currentBlock) {
37 | currentBlock.push(cached)
38 | }
39 | return true
40 | }
41 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/internalObject.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Used during vnode props/slots normalization to check if the vnode props/slots
3 | * are the internal attrs / slots object of a component via
4 | * `Object.getPrototypeOf`. This is more performant than defining a
5 | * non-enumerable property. (one of the optimizations done for ssr-benchmark)
6 | */
7 | const internalObjectProto = {}
8 |
9 | export const createInternalObject = (): any =>
10 | Object.create(internalObjectProto)
11 |
12 | export const isInternalObject = (obj: object): boolean =>
13 | Object.getPrototypeOf(obj) === internalObjectProto
14 |
--------------------------------------------------------------------------------
/packages/runtime-core/src/profiling.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-restricted-globals */
2 | import {
3 | type ComponentInternalInstance,
4 | formatComponentName,
5 | } from './component'
6 | import { devtoolsPerfEnd, devtoolsPerfStart } from './devtools'
7 |
8 | let supported: boolean
9 | let perf: Performance
10 |
11 | export function startMeasure(
12 | instance: ComponentInternalInstance,
13 | type: string,
14 | ): void {
15 | if (instance.appContext.config.performance && isSupported()) {
16 | perf.mark(`vue-${type}-${instance.uid}`)
17 | }
18 |
19 | if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
20 | devtoolsPerfStart(instance, type, isSupported() ? perf.now() : Date.now())
21 | }
22 | }
23 |
24 | export function endMeasure(
25 | instance: ComponentInternalInstance,
26 | type: string,
27 | ): void {
28 | if (instance.appContext.config.performance && isSupported()) {
29 | const startTag = `vue-${type}-${instance.uid}`
30 | const endTag = startTag + `:end`
31 | perf.mark(endTag)
32 | perf.measure(
33 | `<${formatComponentName(instance, instance.type)}> ${type}`,
34 | startTag,
35 | endTag,
36 | )
37 | perf.clearMarks(startTag)
38 | perf.clearMarks(endTag)
39 | }
40 |
41 | if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
42 | devtoolsPerfEnd(instance, type, isSupported() ? perf.now() : Date.now())
43 | }
44 | }
45 |
46 | function isSupported() {
47 | if (supported !== undefined) {
48 | return supported
49 | }
50 | if (typeof window !== 'undefined' && window.performance) {
51 | supported = true
52 | perf = window.performance
53 | } else {
54 | supported = false
55 | }
56 | return supported
57 | }
58 |
--------------------------------------------------------------------------------
/packages/runtime-core/types/globalComponents.d.ts:
--------------------------------------------------------------------------------
1 | // Note: this file is auto concatenated to the end of the bundled d.ts during
2 | // build.
3 |
4 | declare module '@vue/runtime-core' {
5 | export interface GlobalComponents {
6 | Teleport: DefineComponent
7 | Suspense: DefineComponent
8 | KeepAlive: DefineComponent
9 | BaseTransition: DefineComponent
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/packages/runtime-core/types/scriptSetupHelpers.d.ts:
--------------------------------------------------------------------------------
1 | // Note: this file is auto concatenated to the end of the bundled d.ts during
2 | // build.
3 | type _defineProps = typeof defineProps
4 | type _defineEmits = typeof defineEmits
5 | type _defineExpose = typeof defineExpose
6 | type _defineOptions = typeof defineOptions
7 | type _defineSlots = typeof defineSlots
8 | type _defineModel = typeof defineModel
9 | type _withDefaults = typeof withDefaults
10 |
11 | declare global {
12 | const defineProps: _defineProps
13 | const defineEmits: _defineEmits
14 | const defineExpose: _defineExpose
15 | const defineOptions: _defineOptions
16 | const defineSlots: _defineSlots
17 | const defineModel: _defineModel
18 | const withDefaults: _withDefaults
19 | }
20 |
--------------------------------------------------------------------------------
/packages/runtime-dom/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/runtime-dom/README.md:
--------------------------------------------------------------------------------
1 | # @vue/runtime-dom
2 |
3 | ```js
4 | import { h, createApp } from '@vue/runtime-dom'
5 |
6 | const RootComponent = {
7 | render() {
8 | return h('div', 'hello world')
9 | },
10 | }
11 |
12 | createApp(RootComponent).mount('#app')
13 | ```
14 |
--------------------------------------------------------------------------------
/packages/runtime-dom/__tests__/createApp.spec.ts:
--------------------------------------------------------------------------------
1 | import { createApp, h } from '../src'
2 |
3 | describe('createApp for dom', () => {
4 | // #2926
5 | test('mount to SVG container', () => {
6 | const root = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
7 | createApp({
8 | render() {
9 | return h('g')
10 | },
11 | }).mount(root)
12 | expect(root.children.length).toBe(1)
13 | expect(root.children[0]).toBeInstanceOf(SVGElement)
14 | })
15 |
16 | // #4398
17 | test('should not mutate original root component options object', () => {
18 | const originalObj = {
19 | data() {
20 | return {
21 | counter: 0,
22 | }
23 | },
24 | }
25 |
26 | const handler = vi.fn(msg => {
27 | expect(msg).toMatch(`Component is missing template or render function`)
28 | })
29 |
30 | const Root = { ...originalObj }
31 |
32 | const app = createApp(Root)
33 | app.config.warnHandler = handler
34 | app.mount(document.createElement('div'))
35 |
36 | // ensure mount is based on a copy of Root object rather than Root object itself
37 | expect(app._component).not.toBe(Root)
38 |
39 | // ensure no mutation happened to Root object
40 | expect(originalObj).toMatchObject(Root)
41 | })
42 | })
43 |
--------------------------------------------------------------------------------
/packages/runtime-dom/__tests__/customizedBuiltIn.spec.ts:
--------------------------------------------------------------------------------
1 | import type { MockInstance } from 'vitest'
2 | import { h, render } from '@vue/runtime-dom'
3 |
4 | describe('customized built-in elements support', () => {
5 | let createElement: MockInstance
6 | afterEach(() => {
7 | createElement.mockRestore()
8 | })
9 |
10 | test('should created element with is option', () => {
11 | const root = document.createElement('div')
12 | createElement = vi.spyOn(document, 'createElement')
13 | render(h('button', { is: 'plastic-button' }), root)
14 | expect(createElement.mock.calls[0]).toMatchObject([
15 | 'button',
16 | { is: 'plastic-button' },
17 | ])
18 | // should also render the attribute
19 | expect(root.innerHTML).toBe(` `)
20 | })
21 | })
22 |
--------------------------------------------------------------------------------
/packages/runtime-dom/__tests__/directives/vCloak.spec.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from '@vue/runtime-dom'
2 |
3 | describe('vCloak', () => {
4 | test('should be removed after compile', () => {
5 | const root = document.createElement('div')
6 | root.setAttribute('v-cloak', '')
7 | createApp({
8 | render() {},
9 | }).mount(root)
10 | expect(root.hasAttribute('v-cloak')).toBe(false)
11 | })
12 | })
13 |
--------------------------------------------------------------------------------
/packages/runtime-dom/__tests__/helpers/useCssModule.spec.ts:
--------------------------------------------------------------------------------
1 | import { h, nodeOps, render } from '@vue/runtime-test'
2 | import { useCssModule } from '../../src/helpers/useCssModule'
3 |
4 | describe('useCssModule', () => {
5 | function mountWithModule(modules: any, name?: string) {
6 | let res
7 | render(
8 | h({
9 | render() {},
10 | __cssModules: modules,
11 | setup() {
12 | res = useCssModule(name)
13 | },
14 | }),
15 | nodeOps.createElement('div'),
16 | )
17 | return res
18 | }
19 |
20 | test('basic usage', () => {
21 | const modules = {
22 | $style: {
23 | red: 'red',
24 | },
25 | }
26 | expect(mountWithModule(modules)).toMatchObject(modules.$style)
27 | })
28 |
29 | test('basic usage', () => {
30 | const modules = {
31 | foo: {
32 | red: 'red',
33 | },
34 | }
35 | expect(mountWithModule(modules, 'foo')).toMatchObject(modules.foo)
36 | })
37 |
38 | test('warn out of setup usage', () => {
39 | useCssModule()
40 | expect('must be called inside setup').toHaveBeenWarned()
41 | })
42 |
43 | test('warn missing injection', () => {
44 | mountWithModule(undefined)
45 | expect('instance does not have CSS modules').toHaveBeenWarned()
46 | })
47 |
48 | test('warn missing injection', () => {
49 | mountWithModule({ $style: { red: 'red' } }, 'foo')
50 | expect('instance does not have CSS module named "foo"').toHaveBeenWarned()
51 | })
52 | })
53 |
--------------------------------------------------------------------------------
/packages/runtime-dom/__tests__/patchClass.spec.ts:
--------------------------------------------------------------------------------
1 | import { patchProp } from '../src/patchProp'
2 | import {
3 | type ElementWithTransition,
4 | vtcKey,
5 | } from '../src/components/Transition'
6 | import { svgNS } from '../src/nodeOps'
7 |
8 | describe('runtime-dom: class patching', () => {
9 | test('basics', () => {
10 | const el = document.createElement('div')
11 | patchProp(el, 'class', null, 'foo')
12 | expect(el.className).toBe('foo')
13 | patchProp(el, 'class', null, null)
14 | expect(el.className).toBe('')
15 | })
16 |
17 | test('transition class', () => {
18 | const el = document.createElement('div') as ElementWithTransition
19 | el[vtcKey] = new Set(['bar', 'baz'])
20 | patchProp(el, 'class', null, 'foo')
21 | expect(el.className).toBe('foo bar baz')
22 | patchProp(el, 'class', null, null)
23 | expect(el.className).toBe('bar baz')
24 | delete el[vtcKey]
25 | patchProp(el, 'class', null, 'foo')
26 | expect(el.className).toBe('foo')
27 | })
28 |
29 | test('svg', () => {
30 | const el = document.createElementNS(svgNS, 'svg')
31 | patchProp(el, 'class', null, 'foo', 'svg')
32 | expect(el.getAttribute('class')).toBe('foo')
33 | })
34 | })
35 |
--------------------------------------------------------------------------------
/packages/runtime-dom/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | if (process.env.NODE_ENV === 'production') {
4 | module.exports = require('./dist/runtime-dom.cjs.prod.js')
5 | } else {
6 | module.exports = require('./dist/runtime-dom.cjs.js')
7 | }
8 |
--------------------------------------------------------------------------------
/packages/runtime-dom/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue/runtime-dom",
3 | "version": "3.5.0-beta.2",
4 | "description": "@vue/runtime-dom",
5 | "main": "index.js",
6 | "module": "dist/runtime-dom.esm-bundler.js",
7 | "types": "dist/runtime-dom.d.ts",
8 | "unpkg": "dist/runtime-dom.global.js",
9 | "files": [
10 | "index.js",
11 | "dist"
12 | ],
13 | "exports": {
14 | ".": {
15 | "types": "./dist/runtime-dom.d.ts",
16 | "node": {
17 | "production": "./dist/runtime-dom.cjs.prod.js",
18 | "development": "./dist/runtime-dom.cjs.js",
19 | "default": "./index.js"
20 | },
21 | "module": "./dist/runtime-dom.esm-bundler.js",
22 | "import": "./dist/runtime-dom.esm-bundler.js",
23 | "require": "./index.js"
24 | },
25 | "./*": "./*"
26 | },
27 | "sideEffects": false,
28 | "buildOptions": {
29 | "name": "VueRuntimeDOM",
30 | "formats": [
31 | "esm-bundler",
32 | "esm-browser",
33 | "cjs",
34 | "global"
35 | ]
36 | },
37 | "repository": {
38 | "type": "git",
39 | "url": "git+https://github.com/vuejs/core.git",
40 | "directory": "packages/runtime-dom"
41 | },
42 | "keywords": [
43 | "vue"
44 | ],
45 | "author": "Evan You",
46 | "license": "MIT",
47 | "bugs": {
48 | "url": "https://github.com/vuejs/core/issues"
49 | },
50 | "homepage": "https://github.com/vuejs/core/tree/main/packages/runtime-dom#readme",
51 | "dependencies": {
52 | "@vue/shared": "workspace:*",
53 | "@vue/runtime-core": "workspace:*",
54 | "@vue/reactivity": "workspace:*",
55 | "csstype": "^3.1.3"
56 | },
57 | "devDependencies": {
58 | "@types/trusted-types": "^2.0.7"
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/packages/runtime-dom/src/helpers/useCssModule.ts:
--------------------------------------------------------------------------------
1 | import { getCurrentInstance, warn } from '@vue/runtime-core'
2 | import { EMPTY_OBJ } from '@vue/shared'
3 |
4 | export function useCssModule(name = '$style'): Record {
5 | /* istanbul ignore else */
6 | if (!__GLOBAL__) {
7 | const instance = getCurrentInstance()!
8 | if (!instance) {
9 | __DEV__ && warn(`useCssModule must be called inside setup()`)
10 | return EMPTY_OBJ
11 | }
12 | const modules = instance.type.__cssModules
13 | if (!modules) {
14 | __DEV__ && warn(`Current instance does not have CSS modules injected.`)
15 | return EMPTY_OBJ
16 | }
17 | const mod = modules[name]
18 | if (!mod) {
19 | __DEV__ &&
20 | warn(`Current instance does not have CSS module named "${name}".`)
21 | return EMPTY_OBJ
22 | }
23 | return mod as Record
24 | } else {
25 | if (__DEV__) {
26 | warn(`useCssModule() is not supported in the global build.`)
27 | }
28 | return EMPTY_OBJ
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/packages/runtime-dom/src/modules/class.ts:
--------------------------------------------------------------------------------
1 | import { type ElementWithTransition, vtcKey } from '../components/Transition'
2 |
3 | // compiler should normalize class + :class bindings on the same element
4 | // into a single binding ['staticClass', dynamic]
5 | export function patchClass(
6 | el: Element,
7 | value: string | null,
8 | isSVG: boolean,
9 | ): void {
10 | // directly setting className should be faster than setAttribute in theory
11 | // if this is an element during a transition, take the temporary transition
12 | // classes into account.
13 | const transitionClasses = (el as ElementWithTransition)[vtcKey]
14 | if (transitionClasses) {
15 | value = (
16 | value ? [value, ...transitionClasses] : [...transitionClasses]
17 | ).join(' ')
18 | }
19 | if (value == null) {
20 | el.removeAttribute('class')
21 | } else if (isSVG) {
22 | el.setAttribute('class', value)
23 | } else {
24 | el.className = value
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/packages/runtime-test/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/runtime-test/README.md:
--------------------------------------------------------------------------------
1 | # @vue/runtime-test
2 |
3 | This is for Vue's own internal tests only - it ensures logic tested using this package is DOM-agnostic, and it runs faster than JSDOM.
4 |
5 | It can also be used as a reference for implementing a custom renderer.
6 |
7 | ```js
8 | import { h, render, nodeOps, dumpOps } from '@vue/runtime-test'
9 |
10 | const App = {
11 | data () {
12 | return {
13 | msg: 'Hello World!'
14 | }
15 | }
16 | render () {
17 | return h('div', this.msg)
18 | }
19 | }
20 |
21 | // root is of type `TestElement` as defined in src/nodeOps.ts
22 | const root = nodeOps.createElement('div')
23 | render(h(App), root)
24 |
25 | const ops = dumpOps()
26 | console.log(ops)
27 | ```
28 |
--------------------------------------------------------------------------------
/packages/runtime-test/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | if (process.env.NODE_ENV === 'production') {
4 | module.exports = require('./dist/runtime-test.cjs.prod.js')
5 | } else {
6 | module.exports = require('./dist/runtime-test.cjs.js')
7 | }
8 |
--------------------------------------------------------------------------------
/packages/runtime-test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue/runtime-test",
3 | "private": true,
4 | "version": "0.0.0",
5 | "description": "@vue/runtime-test",
6 | "main": "index.js",
7 | "module": "dist/runtime-test.esm-bundler.js",
8 | "types": "dist/runtime-test.d.ts",
9 | "files": [
10 | "index.js",
11 | "dist"
12 | ],
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/vuejs/core.git",
16 | "directory": "packages/runtime-test"
17 | },
18 | "keywords": [
19 | "vue"
20 | ],
21 | "author": "Evan You",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/vuejs/core/issues"
25 | },
26 | "homepage": "https://github.com/vuejs/core/tree/main/packages/runtime-test#readme",
27 | "dependencies": {
28 | "@vue/shared": "workspace:*",
29 | "@vue/runtime-core": "workspace:*"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/packages/runtime-test/src/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type CreateAppFunction,
3 | type RootRenderFunction,
4 | type VNode,
5 | createRenderer,
6 | } from '@vue/runtime-core'
7 | import { type TestElement, nodeOps } from './nodeOps'
8 | import { patchProp } from './patchProp'
9 | import { serializeInner } from './serialize'
10 | import { extend } from '@vue/shared'
11 |
12 | const { render: baseRender, createApp: baseCreateApp } = createRenderer(
13 | extend({ patchProp }, nodeOps),
14 | )
15 |
16 | export const render = baseRender as RootRenderFunction
17 | export const createApp = baseCreateApp as CreateAppFunction
18 |
19 | // convenience for one-off render validations
20 | export function renderToString(vnode: VNode) {
21 | const root = nodeOps.createElement('div')
22 | render(vnode, root)
23 | return serializeInner(root)
24 | }
25 |
26 | export * from './triggerEvent'
27 | export * from './serialize'
28 | export * from './nodeOps'
29 | export * from '@vue/runtime-core'
30 |
--------------------------------------------------------------------------------
/packages/runtime-test/src/patchProp.ts:
--------------------------------------------------------------------------------
1 | import { NodeOpTypes, type TestElement, logNodeOp } from './nodeOps'
2 | import { isOn } from '@vue/shared'
3 |
4 | export function patchProp(
5 | el: TestElement,
6 | key: string,
7 | prevValue: any,
8 | nextValue: any,
9 | ) {
10 | logNodeOp({
11 | type: NodeOpTypes.PATCH,
12 | targetNode: el,
13 | propKey: key,
14 | propPrevValue: prevValue,
15 | propNextValue: nextValue,
16 | })
17 | el.props[key] = nextValue
18 | if (isOn(key)) {
19 | const event = key[2] === ':' ? key.slice(3) : key.slice(2).toLowerCase()
20 | ;(el.eventListeners || (el.eventListeners = {}))[event] = nextValue
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packages/runtime-test/src/triggerEvent.ts:
--------------------------------------------------------------------------------
1 | import { isArray } from '@vue/shared'
2 | import type { TestElement } from './nodeOps'
3 |
4 | export function triggerEvent(
5 | el: TestElement,
6 | event: string,
7 | payload: any[] = [],
8 | ) {
9 | const { eventListeners } = el
10 | if (eventListeners) {
11 | const listener = eventListeners[event]
12 | if (listener) {
13 | if (isArray(listener)) {
14 | for (let i = 0; i < listener.length; i++) {
15 | listener[i](...payload)
16 | }
17 | } else {
18 | listener(...payload)
19 | }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packages/server-renderer/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/server-renderer/__tests__/createBuffer.bench.ts:
--------------------------------------------------------------------------------
1 | import { bench, describe } from 'vitest'
2 |
3 | import { createBuffer } from '../src/render'
4 |
5 | describe('createBuffer', () => {
6 | let stringBuffer = createBuffer()
7 |
8 | bench(
9 | 'string only',
10 | () => {
11 | for (let i = 0; i < 10; i += 1) {
12 | stringBuffer.push('hello')
13 | }
14 | },
15 | {
16 | setup() {
17 | stringBuffer = createBuffer()
18 | },
19 | },
20 | )
21 |
22 | let stringNestedBuffer = createBuffer()
23 |
24 | bench(
25 | 'string with nested',
26 | () => {
27 | for (let i = 0; i < 10; i += 1) {
28 | if (i % 3 === 0) {
29 | stringNestedBuffer.push('hello')
30 | } else {
31 | const buffer = createBuffer()
32 | buffer.push('hello')
33 | stringNestedBuffer.push(buffer.getBuffer())
34 | }
35 | }
36 | },
37 | {
38 | setup() {
39 | stringNestedBuffer = createBuffer()
40 | },
41 | },
42 | )
43 |
44 | bench(
45 | 'string with nested async',
46 | () => {
47 | for (let i = 0; i < 10; i += 1) {
48 | if (i % 3 === 0) {
49 | const buffer = createBuffer()
50 | buffer.push('hello')
51 | stringNestedBuffer.push(Promise.resolve(buffer.getBuffer()))
52 | } else {
53 | const buffer = createBuffer()
54 | buffer.push('hello')
55 | stringNestedBuffer.push(buffer.getBuffer())
56 | }
57 | }
58 | },
59 | {
60 | setup() {
61 | stringNestedBuffer = createBuffer()
62 | },
63 | },
64 | )
65 | })
66 |
--------------------------------------------------------------------------------
/packages/server-renderer/__tests__/ssrInterpolate.spec.ts:
--------------------------------------------------------------------------------
1 | import { ssrInterpolate } from '../src/helpers/ssrInterpolate'
2 | import { escapeHtml } from '@vue/shared'
3 |
4 | test('ssr: interpolate', () => {
5 | expect(ssrInterpolate(0)).toBe(`0`)
6 | expect(ssrInterpolate(`foo`)).toBe(`foo`)
7 | expect(ssrInterpolate(``)).toBe(`<div>`)
8 | // should escape interpolated values
9 | expect(ssrInterpolate([1, 2, 3])).toBe(
10 | escapeHtml(JSON.stringify([1, 2, 3], null, 2)),
11 | )
12 | expect(
13 | ssrInterpolate({
14 | foo: 1,
15 | bar: `
`,
16 | }),
17 | ).toBe(
18 | escapeHtml(
19 | JSON.stringify(
20 | {
21 | foo: 1,
22 | bar: `
`,
23 | },
24 | null,
25 | 2,
26 | ),
27 | ),
28 | )
29 | })
30 |
--------------------------------------------------------------------------------
/packages/server-renderer/__tests__/ssrWatch.spec.ts:
--------------------------------------------------------------------------------
1 | import { createSSRApp, defineComponent, h, ref, watch } from 'vue'
2 | import { type SSRContext, renderToString } from '../src'
3 |
4 | describe('ssr: watch', () => {
5 | // #6013
6 | test('should work w/ flush:sync', async () => {
7 | const App = defineComponent(() => {
8 | const count = ref(0)
9 | let msg = ''
10 | watch(
11 | count,
12 | () => {
13 | msg = 'hello world'
14 | },
15 | { flush: 'sync' },
16 | )
17 | count.value = 1
18 | expect(msg).toBe('hello world')
19 | return () => h('div', null, msg)
20 | })
21 |
22 | const app = createSSRApp(App)
23 | const ctx: SSRContext = {}
24 | const html = await renderToString(app, ctx)
25 |
26 | expect(ctx.__watcherHandles!.length).toBe(1)
27 |
28 | expect(html).toMatch('hello world')
29 | })
30 | })
31 |
--------------------------------------------------------------------------------
/packages/server-renderer/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | if (process.env.NODE_ENV === 'production') {
4 | module.exports = require('./dist/server-renderer.cjs.prod.js')
5 | } else {
6 | module.exports = require('./dist/server-renderer.cjs.js')
7 | }
8 |
--------------------------------------------------------------------------------
/packages/server-renderer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue/server-renderer",
3 | "version": "3.5.0-beta.2",
4 | "description": "@vue/server-renderer",
5 | "main": "index.js",
6 | "module": "dist/server-renderer.esm-bundler.js",
7 | "types": "dist/server-renderer.d.ts",
8 | "files": [
9 | "index.js",
10 | "dist"
11 | ],
12 | "exports": {
13 | ".": {
14 | "types": "./dist/server-renderer.d.ts",
15 | "node": {
16 | "production": "./dist/server-renderer.cjs.prod.js",
17 | "development": "./dist/server-renderer.cjs.js",
18 | "default": "./index.js"
19 | },
20 | "module": "./dist/server-renderer.esm-bundler.js",
21 | "import": "./dist/server-renderer.esm-bundler.js",
22 | "require": "./index.js"
23 | },
24 | "./*": "./*"
25 | },
26 | "buildOptions": {
27 | "name": "VueServerRenderer",
28 | "formats": [
29 | "esm-bundler",
30 | "esm-browser",
31 | "cjs"
32 | ]
33 | },
34 | "repository": {
35 | "type": "git",
36 | "url": "git+https://github.com/vuejs/core.git",
37 | "directory": "packages/server-renderer"
38 | },
39 | "keywords": [
40 | "vue"
41 | ],
42 | "author": "Evan You",
43 | "license": "MIT",
44 | "bugs": {
45 | "url": "https://github.com/vuejs/core/issues"
46 | },
47 | "homepage": "https://github.com/vuejs/core/tree/main/packages/server-renderer#readme",
48 | "peerDependencies": {
49 | "vue": "workspace:*"
50 | },
51 | "dependencies": {
52 | "@vue/shared": "workspace:*",
53 | "@vue/compiler-ssr": "workspace:*"
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/packages/server-renderer/src/helpers/ssrGetDirectiveProps.ts:
--------------------------------------------------------------------------------
1 | import { type ComponentPublicInstance, type Directive, ssrUtils } from 'vue'
2 |
3 | export function ssrGetDirectiveProps(
4 | instance: ComponentPublicInstance,
5 | dir: Directive,
6 | value?: any,
7 | arg?: string,
8 | modifiers: Record
= {},
9 | ): Record {
10 | if (typeof dir !== 'function' && dir.getSSRProps) {
11 | return (
12 | dir.getSSRProps(
13 | {
14 | dir,
15 | instance: ssrUtils.getComponentPublicInstance(instance.$),
16 | value,
17 | oldValue: undefined,
18 | arg,
19 | modifiers,
20 | },
21 | null as any,
22 | ) || {}
23 | )
24 | }
25 | return {}
26 | }
27 |
--------------------------------------------------------------------------------
/packages/server-renderer/src/helpers/ssrInterpolate.ts:
--------------------------------------------------------------------------------
1 | import { escapeHtml, toDisplayString } from '@vue/shared'
2 |
3 | export function ssrInterpolate(value: unknown): string {
4 | return escapeHtml(toDisplayString(value))
5 | }
6 |
--------------------------------------------------------------------------------
/packages/server-renderer/src/helpers/ssrRenderComponent.ts:
--------------------------------------------------------------------------------
1 | import {
2 | type Component,
3 | type ComponentInternalInstance,
4 | type Slots,
5 | createVNode,
6 | } from 'vue'
7 | import { type Props, type SSRBuffer, renderComponentVNode } from '../render'
8 | import type { SSRSlots } from './ssrRenderSlot'
9 |
10 | export function ssrRenderComponent(
11 | comp: Component,
12 | props: Props | null = null,
13 | children: Slots | SSRSlots | null = null,
14 | parentComponent: ComponentInternalInstance | null = null,
15 | slotScopeId?: string,
16 | ): SSRBuffer | Promise {
17 | return renderComponentVNode(
18 | createVNode(comp, props, children),
19 | parentComponent,
20 | slotScopeId,
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/packages/server-renderer/src/helpers/ssrRenderList.ts:
--------------------------------------------------------------------------------
1 | import { isArray, isObject, isString } from '@vue/shared'
2 | import { warn } from '@vue/runtime-core'
3 |
4 | export function ssrRenderList(
5 | source: unknown,
6 | renderItem: (value: unknown, key: string | number, index?: number) => void,
7 | ): void {
8 | if (isArray(source) || isString(source)) {
9 | for (let i = 0, l = source.length; i < l; i++) {
10 | renderItem(source[i], i)
11 | }
12 | } else if (typeof source === 'number') {
13 | if (__DEV__ && !Number.isInteger(source)) {
14 | warn(`The v-for range expect an integer value but got ${source}.`)
15 | return
16 | }
17 | for (let i = 0; i < source; i++) {
18 | renderItem(i + 1, i)
19 | }
20 | } else if (isObject(source)) {
21 | if (source[Symbol.iterator as any]) {
22 | const arr = Array.from(source as Iterable)
23 | for (let i = 0, l = arr.length; i < l; i++) {
24 | renderItem(arr[i], i)
25 | }
26 | } else {
27 | const keys = Object.keys(source)
28 | for (let i = 0, l = keys.length; i < l; i++) {
29 | const key = keys[i]
30 | renderItem(source[key], key, i)
31 | }
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/packages/server-renderer/src/helpers/ssrRenderSuspense.ts:
--------------------------------------------------------------------------------
1 | import type { PushFn } from '../render'
2 |
3 | export async function ssrRenderSuspense(
4 | push: PushFn,
5 | { default: renderContent }: Record void) | undefined>,
6 | ): Promise {
7 | if (renderContent) {
8 | renderContent()
9 | } else {
10 | push(``)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/packages/server-renderer/src/helpers/ssrRenderTeleport.ts:
--------------------------------------------------------------------------------
1 | import { type ComponentInternalInstance, ssrContextKey } from 'vue'
2 | import {
3 | type PushFn,
4 | type SSRBufferItem,
5 | type SSRContext,
6 | createBuffer,
7 | } from '../render'
8 |
9 | export function ssrRenderTeleport(
10 | parentPush: PushFn,
11 | contentRenderFn: (push: PushFn) => void,
12 | target: string,
13 | disabled: boolean,
14 | parentComponent: ComponentInternalInstance,
15 | ): void {
16 | parentPush('')
17 |
18 | const context = parentComponent.appContext.provides[
19 | ssrContextKey as any
20 | ] as SSRContext
21 | const teleportBuffers =
22 | context.__teleportBuffers || (context.__teleportBuffers = {})
23 | const targetBuffer = teleportBuffers[target] || (teleportBuffers[target] = [])
24 | // record current index of the target buffer to handle nested teleports
25 | // since the parent needs to be rendered before the child
26 | const bufferIndex = targetBuffer.length
27 |
28 | let teleportContent: SSRBufferItem
29 |
30 | if (disabled) {
31 | contentRenderFn(parentPush)
32 | teleportContent = ``
33 | } else {
34 | const { getBuffer, push } = createBuffer()
35 | push(``)
36 | contentRenderFn(push)
37 | push(``)
38 | teleportContent = getBuffer()
39 | }
40 |
41 | targetBuffer.splice(bufferIndex, 0, teleportContent)
42 | parentPush('')
43 | }
44 |
--------------------------------------------------------------------------------
/packages/server-renderer/src/helpers/ssrVModelHelpers.ts:
--------------------------------------------------------------------------------
1 | import { isArray, looseEqual, looseIndexOf } from '@vue/shared'
2 | import { ssrRenderAttr } from './ssrRenderAttrs'
3 |
4 | export const ssrLooseEqual = looseEqual as (a: unknown, b: unknown) => boolean
5 |
6 | export function ssrLooseContain(arr: unknown[], value: unknown): boolean {
7 | return looseIndexOf(arr, value) > -1
8 | }
9 |
10 | // for
11 | export function ssrRenderDynamicModel(
12 | type: unknown,
13 | model: unknown,
14 | value: unknown,
15 | ): string {
16 | switch (type) {
17 | case 'radio':
18 | return looseEqual(model, value) ? ' checked' : ''
19 | case 'checkbox':
20 | return (isArray(model) ? ssrLooseContain(model, value) : model)
21 | ? ' checked'
22 | : ''
23 | default:
24 | // text types
25 | return ssrRenderAttr('value', model)
26 | }
27 | }
28 |
29 | // for
30 | export function ssrGetDynamicModelProps(
31 | existingProps: any = {},
32 | model: unknown,
33 | ): { checked: true } | { value: any } | null {
34 | const { type, value } = existingProps
35 | switch (type) {
36 | case 'radio':
37 | return looseEqual(model, value) ? { checked: true } : null
38 | case 'checkbox':
39 | return (isArray(model) ? ssrLooseContain(model, value) : model)
40 | ? { checked: true }
41 | : null
42 | default:
43 | // text types
44 | return { value: model }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/packages/server-renderer/src/index.ts:
--------------------------------------------------------------------------------
1 | import { initDirectivesForSSR } from 'vue'
2 | initDirectivesForSSR()
3 |
4 | // public
5 | export type { SSRContext } from './render'
6 | export { renderToString } from './renderToString'
7 | export {
8 | renderToSimpleStream,
9 | renderToNodeStream,
10 | pipeToNodeWritable,
11 | renderToWebStream,
12 | pipeToWebWritable,
13 | type SimpleReadable,
14 | // deprecated
15 | renderToStream,
16 | } from './renderToStream'
17 |
18 | // internal runtime helpers
19 | export * from './internal'
20 |
--------------------------------------------------------------------------------
/packages/server-renderer/src/internal.ts:
--------------------------------------------------------------------------------
1 | // internal runtime helpers
2 | export { renderVNode as ssrRenderVNode } from './render'
3 | export { ssrRenderComponent } from './helpers/ssrRenderComponent'
4 | export { ssrRenderSlot, ssrRenderSlotInner } from './helpers/ssrRenderSlot'
5 | export { ssrRenderTeleport } from './helpers/ssrRenderTeleport'
6 | export {
7 | ssrRenderClass,
8 | ssrRenderStyle,
9 | ssrRenderAttrs,
10 | ssrRenderAttr,
11 | ssrRenderDynamicAttr,
12 | } from './helpers/ssrRenderAttrs'
13 | export { ssrInterpolate } from './helpers/ssrInterpolate'
14 | export { ssrRenderList } from './helpers/ssrRenderList'
15 | export { ssrRenderSuspense } from './helpers/ssrRenderSuspense'
16 | export { ssrGetDirectiveProps } from './helpers/ssrGetDirectiveProps'
17 | export { includeBooleanAttr as ssrIncludeBooleanAttr } from '@vue/shared'
18 |
19 | // v-model helpers
20 | export {
21 | ssrLooseEqual,
22 | ssrLooseContain,
23 | ssrRenderDynamicModel,
24 | ssrGetDynamicModelProps,
25 | } from './helpers/ssrVModelHelpers'
26 |
--------------------------------------------------------------------------------
/packages/shared/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/shared/README.md:
--------------------------------------------------------------------------------
1 | # @vue/shared
2 |
3 | Internal utility functions and constants shared across `@vue` packages.
4 |
--------------------------------------------------------------------------------
/packages/shared/__tests__/escapeHtml.spec.ts:
--------------------------------------------------------------------------------
1 | import { escapeHtml, escapeHtmlComment } from '../src'
2 |
3 | describe('escapeHtml', () => {
4 | test('ssr: escapeHTML', () => {
5 | expect(escapeHtml(`foo`)).toBe(`foo`)
6 | expect(escapeHtml(true)).toBe(`true`)
7 | expect(escapeHtml(false)).toBe(`false`)
8 | expect(escapeHtml(`a && b`)).toBe(`a && b`)
9 | expect(escapeHtml(`"foo"`)).toBe(`"foo"`)
10 | expect(escapeHtml(`'bar'`)).toBe(`'bar'`)
11 | expect(escapeHtml(``)).toBe(`<div>`)
12 | })
13 |
14 | test('ssr: escapeHTMLComment', () => {
15 | const input = ''
16 | const result = escapeHtmlComment(input)
17 | expect(result).toEqual(' Hello World! ')
18 | })
19 |
20 | test('ssr: escapeHTMLComment', () => {
21 | const input = ' Hello World!'
22 | const result = escapeHtmlComment(input)
23 | expect(result).toEqual(' Comment 1 Hello ! Comment 2 World!')
24 | })
25 |
26 | test('should not affect non-comment strings', () => {
27 | const input = 'Hello World'
28 | const result = escapeHtmlComment(input)
29 | expect(result).toEqual(input)
30 | })
31 | })
32 |
--------------------------------------------------------------------------------
/packages/shared/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | if (process.env.NODE_ENV === 'production') {
4 | module.exports = require('./dist/shared.cjs.prod.js')
5 | } else {
6 | module.exports = require('./dist/shared.cjs.js')
7 | }
8 |
--------------------------------------------------------------------------------
/packages/shared/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue/shared",
3 | "version": "3.5.0-beta.2",
4 | "description": "internal utils shared across @vue packages",
5 | "main": "index.js",
6 | "module": "dist/shared.esm-bundler.js",
7 | "types": "dist/shared.d.ts",
8 | "files": [
9 | "index.js",
10 | "dist"
11 | ],
12 | "exports": {
13 | ".": {
14 | "types": "./dist/shared.d.ts",
15 | "node": {
16 | "production": "./dist/shared.cjs.prod.js",
17 | "development": "./dist/shared.cjs.js",
18 | "default": "./index.js"
19 | },
20 | "module": "./dist/shared.esm-bundler.js",
21 | "import": "./dist/shared.esm-bundler.js",
22 | "require": "./index.js"
23 | },
24 | "./*": "./*"
25 | },
26 | "sideEffects": false,
27 | "buildOptions": {
28 | "formats": [
29 | "esm-bundler",
30 | "cjs"
31 | ]
32 | },
33 | "repository": {
34 | "type": "git",
35 | "url": "git+https://github.com/vuejs/core.git",
36 | "directory": "packages/shared"
37 | },
38 | "keywords": [
39 | "vue"
40 | ],
41 | "author": "Evan You",
42 | "license": "MIT",
43 | "bugs": {
44 | "url": "https://github.com/vuejs/core/issues"
45 | },
46 | "homepage": "https://github.com/vuejs/core/tree/main/packages/shared#readme"
47 | }
48 |
--------------------------------------------------------------------------------
/packages/shared/src/escapeHtml.ts:
--------------------------------------------------------------------------------
1 | const escapeRE = /["'&<>]/
2 |
3 | export function escapeHtml(string: unknown): string {
4 | const str = '' + string
5 | const match = escapeRE.exec(str)
6 |
7 | if (!match) {
8 | return str
9 | }
10 |
11 | let html = ''
12 | let escaped: string
13 | let index: number
14 | let lastIndex = 0
15 | for (index = match.index; index < str.length; index++) {
16 | switch (str.charCodeAt(index)) {
17 | case 34: // "
18 | escaped = '"'
19 | break
20 | case 38: // &
21 | escaped = '&'
22 | break
23 | case 39: // '
24 | escaped = '''
25 | break
26 | case 60: // <
27 | escaped = '<'
28 | break
29 | case 62: // >
30 | escaped = '>'
31 | break
32 | default:
33 | continue
34 | }
35 |
36 | if (lastIndex !== index) {
37 | html += str.slice(lastIndex, index)
38 | }
39 |
40 | lastIndex = index + 1
41 | html += escaped
42 | }
43 |
44 | return lastIndex !== index ? html + str.slice(lastIndex, index) : html
45 | }
46 |
47 | // https://www.w3.org/TR/html52/syntax.html#comments
48 | const commentStripRE = /^-?>||--!>| boolean =
9 | /*#__PURE__*/ makeMap(GLOBALS_ALLOWED)
10 |
11 | /** @deprecated use `isGloballyAllowed` instead */
12 | export const isGloballyWhitelisted: (key: string) => boolean = isGloballyAllowed
13 |
--------------------------------------------------------------------------------
/packages/shared/src/index.ts:
--------------------------------------------------------------------------------
1 | export { makeMap } from './makeMap'
2 | export * from './general'
3 | export * from './patchFlags'
4 | export * from './shapeFlags'
5 | export * from './slotFlags'
6 | export * from './globalsAllowList'
7 | export * from './codeframe'
8 | export * from './normalizeProp'
9 | export * from './domTagConfig'
10 | export * from './domAttrConfig'
11 | export * from './escapeHtml'
12 | export * from './looseEqual'
13 | export * from './toDisplayString'
14 | export * from './typeUtils'
15 |
--------------------------------------------------------------------------------
/packages/shared/src/makeMap.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Make a map and return a function for checking if a key
3 | * is in that map.
4 | * IMPORTANT: all calls of this function must be prefixed with
5 | * \/\*#\_\_PURE\_\_\*\/
6 | * So that rollup can tree-shake them if necessary.
7 | */
8 |
9 | /*! #__NO_SIDE_EFFECTS__ */
10 | export function makeMap(
11 | str: string,
12 | expectsLowerCase?: boolean,
13 | ): (key: string) => boolean {
14 | const set = new Set(str.split(','))
15 | return expectsLowerCase
16 | ? val => set.has(val.toLowerCase())
17 | : val => set.has(val)
18 | }
19 |
--------------------------------------------------------------------------------
/packages/shared/src/shapeFlags.ts:
--------------------------------------------------------------------------------
1 | export enum ShapeFlags {
2 | ELEMENT = 1,
3 | FUNCTIONAL_COMPONENT = 1 << 1,
4 | STATEFUL_COMPONENT = 1 << 2,
5 | TEXT_CHILDREN = 1 << 3,
6 | ARRAY_CHILDREN = 1 << 4,
7 | SLOTS_CHILDREN = 1 << 5,
8 | TELEPORT = 1 << 6,
9 | SUSPENSE = 1 << 7,
10 | COMPONENT_SHOULD_KEEP_ALIVE = 1 << 8,
11 | COMPONENT_KEPT_ALIVE = 1 << 9,
12 | COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT,
13 | }
14 |
--------------------------------------------------------------------------------
/packages/shared/src/slotFlags.ts:
--------------------------------------------------------------------------------
1 | export enum SlotFlags {
2 | /**
3 | * Stable slots that only reference slot props or context state. The slot
4 | * can fully capture its own dependencies so when passed down the parent won't
5 | * need to force the child to update.
6 | */
7 | STABLE = 1,
8 | /**
9 | * Slots that reference scope variables (v-for or an outer slot prop), or
10 | * has conditional structure (v-if, v-for). The parent will need to force
11 | * the child to update because the slot does not fully capture its dependencies.
12 | */
13 | DYNAMIC = 2,
14 | /**
15 | * `
` being forwarded into a child component. Whether the parent needs
16 | * to update the child is dependent on what kind of slots the parent itself
17 | * received. This has to be refined at runtime, when the child's vnode
18 | * is being created (in `normalizeChildren`)
19 | */
20 | FORWARDED = 3,
21 | }
22 |
23 | /**
24 | * Dev only
25 | */
26 | export const slotFlagsText: Record
= {
27 | [SlotFlags.STABLE]: 'STABLE',
28 | [SlotFlags.DYNAMIC]: 'DYNAMIC',
29 | [SlotFlags.FORWARDED]: 'FORWARDED',
30 | }
31 |
--------------------------------------------------------------------------------
/packages/vue-compat/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/vue-compat/__tests__/utils.ts:
--------------------------------------------------------------------------------
1 | export function triggerEvent(
2 | target: Element,
3 | event: string,
4 | process?: (e: any) => any,
5 | ) {
6 | const e = new Event(event, {
7 | bubbles: true,
8 | cancelable: true,
9 | })
10 | if (process) process(e)
11 | target.dispatchEvent(e)
12 | return e
13 | }
14 |
--------------------------------------------------------------------------------
/packages/vue-compat/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | if (process.env.NODE_ENV === 'production') {
4 | module.exports = require('./dist/vue.cjs.prod.js')
5 | } else {
6 | module.exports = require('./dist/vue.cjs.js')
7 | }
8 |
--------------------------------------------------------------------------------
/packages/vue-compat/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@vue/compat",
3 | "version": "3.5.0-beta.2",
4 | "description": "Vue 3 compatibility build for Vue 2",
5 | "main": "index.js",
6 | "module": "dist/vue.runtime.esm-bundler.js",
7 | "unpkg": "dist/vue.global.js",
8 | "jsdelivr": "dist/vue.global.js",
9 | "files": [
10 | "index.js",
11 | "dist"
12 | ],
13 | "exports": {
14 | ".": {
15 | "types": "./dist/vue.d.ts",
16 | "node": {
17 | "production": "./dist/vue.cjs.prod.js",
18 | "development": "./dist/vue.cjs.js",
19 | "default": "./index.js"
20 | },
21 | "module": "./dist/vue.esm-bundler.js",
22 | "import": "./dist/vue.esm-bundler.js",
23 | "require": "./index.js"
24 | },
25 | "./*": "./*"
26 | },
27 | "buildOptions": {
28 | "name": "Vue",
29 | "filename": "vue",
30 | "compat": true,
31 | "formats": [
32 | "esm-bundler",
33 | "esm-bundler-runtime",
34 | "cjs",
35 | "global",
36 | "global-runtime",
37 | "esm-browser",
38 | "esm-browser-runtime"
39 | ]
40 | },
41 | "repository": {
42 | "type": "git",
43 | "url": "git+https://github.com/vuejs/core.git"
44 | },
45 | "keywords": [
46 | "vue"
47 | ],
48 | "author": "Evan You",
49 | "license": "MIT",
50 | "bugs": {
51 | "url": "https://github.com/vuejs/core/issues"
52 | },
53 | "homepage": "https://github.com/vuejs/core/tree/main/packages/vue-compat#readme",
54 | "dependencies": {
55 | "@babel/parser": "catalog:",
56 | "estree-walker": "catalog:",
57 | "source-map-js": "catalog:"
58 | },
59 | "peerDependencies": {
60 | "vue": "workspace:*"
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/packages/vue-compat/src/createCompatVue.ts:
--------------------------------------------------------------------------------
1 | // This entry exports the runtime only, and is built as
2 | // `dist/vue.esm-bundler.js` which is used by default for bundlers.
3 | import { initDev } from './dev'
4 | import {
5 | type CompatVue,
6 | DeprecationTypes,
7 | KeepAlive,
8 | Transition,
9 | TransitionGroup,
10 | compatUtils,
11 | createApp,
12 | vModelDynamic,
13 | vShow,
14 | } from '@vue/runtime-dom'
15 | import { extend } from '@vue/shared'
16 |
17 | if (__DEV__) {
18 | initDev()
19 | }
20 |
21 | import * as runtimeDom from '@vue/runtime-dom'
22 |
23 | function wrappedCreateApp(...args: any[]) {
24 | // @ts-expect-error
25 | const app = createApp(...args)
26 | if (compatUtils.isCompatEnabled(DeprecationTypes.RENDER_FUNCTION, null)) {
27 | // register built-in components so that they can be resolved via strings
28 | // in the legacy h() call. The __compat__ prefix is to ensure that v3 h()
29 | // doesn't get affected.
30 | app.component('__compat__transition', Transition)
31 | app.component('__compat__transition-group', TransitionGroup)
32 | app.component('__compat__keep-alive', KeepAlive)
33 | // built-in directives. No need for prefix since there's no render fn API
34 | // for resolving directives via string in v3.
35 | app._context.directives.show = vShow
36 | app._context.directives.model = vModelDynamic
37 | }
38 | return app
39 | }
40 |
41 | export function createCompatVue(): CompatVue {
42 | const Vue = compatUtils.createCompatVue(createApp, wrappedCreateApp)
43 | extend(Vue, runtimeDom)
44 | return Vue
45 | }
46 |
--------------------------------------------------------------------------------
/packages/vue-compat/src/dev.ts:
--------------------------------------------------------------------------------
1 | import { initCustomFormatter } from '@vue/runtime-dom'
2 |
3 | export function initDev(): void {
4 | if (__BROWSER__) {
5 | if (!__ESM_BUNDLER__) {
6 | console.info(
7 | `You are running a development build of Vue.\n` +
8 | `Make sure to use the production build (*.prod.js) when deploying for production.`,
9 | )
10 | }
11 |
12 | initCustomFormatter()
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/packages/vue-compat/src/esm-index.ts:
--------------------------------------------------------------------------------
1 | import Vue from './index'
2 |
3 | export default Vue
4 | export * from '@vue/runtime-dom'
5 |
6 | const configureCompat: typeof Vue.configureCompat = Vue.configureCompat
7 | export { configureCompat }
8 |
--------------------------------------------------------------------------------
/packages/vue-compat/src/esm-runtime.ts:
--------------------------------------------------------------------------------
1 | import Vue from './runtime'
2 |
3 | export default Vue
4 | export * from '@vue/runtime-dom'
5 |
6 | const configureCompat: typeof Vue.configureCompat = Vue.configureCompat
7 | export { configureCompat }
8 |
--------------------------------------------------------------------------------
/packages/vue-compat/src/runtime.ts:
--------------------------------------------------------------------------------
1 | // This entry exports the runtime only, and is built as
2 | // `dist/vue.esm-bundler.js` which is used by default for bundlers.
3 | import { createCompatVue } from './createCompatVue'
4 | import { type CompatVue, warn } from '@vue/runtime-core'
5 |
6 | const Vue: CompatVue = createCompatVue()
7 |
8 | Vue.compile = (() => {
9 | if (__DEV__) {
10 | warn(
11 | `Runtime compilation is not supported in this build of Vue.` +
12 | (__ESM_BUNDLER__
13 | ? ` Configure your bundler to alias "vue" to "@vue/compat/dist/vue.esm-bundler.js".`
14 | : __ESM_BROWSER__
15 | ? ` Use "vue.esm-browser.js" instead.`
16 | : __GLOBAL__
17 | ? ` Use "vue.global.js" instead.`
18 | : ``) /* should not happen */,
19 | )
20 | }
21 | }) as any
22 |
23 | export default Vue
24 |
--------------------------------------------------------------------------------
/packages/vue/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2018-present, Yuxi (Evan) You
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/packages/vue/__tests__/customElementCasing.spec.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from '../src'
2 |
3 | // https://github.com/vuejs/docs/pull/1890
4 | // https://github.com/vuejs/core/issues/5401
5 | // https://github.com/vuejs/docs/issues/1708
6 | test('custom element event casing', () => {
7 | customElements.define(
8 | 'custom-event-casing',
9 | class Foo extends HTMLElement {
10 | connectedCallback() {
11 | this.dispatchEvent(new Event('camelCase'))
12 | this.dispatchEvent(new Event('CAPScase'))
13 | this.dispatchEvent(new Event('PascalCase'))
14 | }
15 | },
16 | )
17 |
18 | const container = document.createElement('div')
19 | document.body.appendChild(container)
20 |
21 | const handler = vi.fn()
22 | const handler2 = vi.fn()
23 | createApp({
24 | template: `
25 | `,
34 | methods: {
35 | handler,
36 | handler2,
37 | },
38 | }).mount(container)
39 |
40 | expect(handler).toHaveBeenCalledTimes(3)
41 | expect(handler2).toHaveBeenCalledTimes(3)
42 | })
43 |
--------------------------------------------------------------------------------
/packages/vue/__tests__/e2e/hydration-strat-custom.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | click here to hydrate
4 | 0
5 |
6 |
45 |
--------------------------------------------------------------------------------
/packages/vue/__tests__/e2e/hydration-strat-idle.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | 0
4 |
5 |
45 |
--------------------------------------------------------------------------------
/packages/vue/__tests__/e2e/hydration-strat-interaction.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | click to hydrate
4 | 0
5 |
10 |
11 |
64 |
--------------------------------------------------------------------------------
/packages/vue/__tests__/e2e/hydration-strat-media.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | resize the window width to < 500px to hydrate
4 | 0
5 |
6 |
44 |
--------------------------------------------------------------------------------
/packages/vue/__tests__/e2e/hydration-strat-visible.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | scroll to the bottom to hydrate
4 | 0
5 |
10 |
11 |
65 |
--------------------------------------------------------------------------------
/packages/vue/__tests__/e2e/markdown.spec.ts:
--------------------------------------------------------------------------------
1 | import path from 'node:path'
2 | import { E2E_TIMEOUT, expectByPolling, setupPuppeteer } from './e2eUtils'
3 |
4 | describe('e2e: markdown', () => {
5 | const { page, isVisible, value, html } = setupPuppeteer()
6 |
7 | async function testMarkdown(apiType: 'classic' | 'composition') {
8 | const baseUrl = `file://${path.resolve(
9 | __dirname,
10 | `../../examples/${apiType}/markdown.html#test`,
11 | )}`
12 |
13 | await page().goto(baseUrl)
14 | expect(await isVisible('#editor')).toBe(true)
15 | expect(await value('textarea')).toBe('# hello')
16 | expect(await html('#editor div')).toBe('hello \n')
17 |
18 | await page().type('textarea', '\n## foo\n\n- bar\n- baz')
19 |
20 | // assert the output is not updated yet because of debounce
21 | // debounce has become unstable on CI so this assertion is disabled
22 | // expect(await html('#editor div')).toBe('hello \n')
23 |
24 | await expectByPolling(
25 | () => html('#editor div'),
26 | 'hello \n' +
27 | 'foo \n' +
28 | '\n',
29 | )
30 | }
31 |
32 | test(
33 | 'classic',
34 | async () => {
35 | await testMarkdown('classic')
36 | },
37 | E2E_TIMEOUT,
38 | )
39 |
40 | test(
41 | 'composition',
42 | async () => {
43 | await testMarkdown('composition')
44 | },
45 | E2E_TIMEOUT,
46 | )
47 | })
48 |
--------------------------------------------------------------------------------
/packages/vue/__tests__/e2e/ssr-custom-element.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1
6 | 1
11 |
12 |
45 |
--------------------------------------------------------------------------------
/packages/vue/__tests__/e2e/ssr-custom-element.spec.ts:
--------------------------------------------------------------------------------
1 | import path from 'node:path'
2 | import { setupPuppeteer } from './e2eUtils'
3 |
4 | const { page, click, text } = setupPuppeteer()
5 |
6 | // this must be tested in actual Chrome because jsdom does not support
7 | // declarative shadow DOM
8 | test('ssr custom element hydration', async () => {
9 | await page().goto(
10 | `file://${path.resolve(__dirname, './ssr-custom-element.html')}`,
11 | )
12 |
13 | function getColor() {
14 | return page().evaluate(() => {
15 | return [
16 | (document.querySelector('my-element') as any).style.border,
17 | (document.querySelector('my-element-async') as any).style.border,
18 | ]
19 | })
20 | }
21 |
22 | expect(await getColor()).toMatchObject(['1px solid red', ''])
23 | await page().evaluate(() => (window as any).resolve()) // exposed by test
24 | expect(await getColor()).toMatchObject(['1px solid red', '1px solid red'])
25 |
26 | async function assertInteraction(el: string) {
27 | const selector = `${el} >>> button`
28 | expect(await text(selector)).toBe('1')
29 | await click(selector)
30 | expect(await text(selector)).toBe('2')
31 | }
32 |
33 | await assertInteraction('my-element')
34 | await assertInteraction('my-element-async')
35 | })
36 |
--------------------------------------------------------------------------------
/packages/vue/__tests__/e2e/transition.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
73 |
--------------------------------------------------------------------------------
/packages/vue/__tests__/e2e/trusted-types.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
10 | Vue App
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/packages/vue/compiler-sfc/index.browser.js:
--------------------------------------------------------------------------------
1 | module.exports = require('@vue/compiler-sfc')
2 |
--------------------------------------------------------------------------------
/packages/vue/compiler-sfc/index.browser.mjs:
--------------------------------------------------------------------------------
1 | export * from '@vue/compiler-sfc'
2 |
--------------------------------------------------------------------------------
/packages/vue/compiler-sfc/index.d.mts:
--------------------------------------------------------------------------------
1 | export * from '@vue/compiler-sfc'
2 |
--------------------------------------------------------------------------------
/packages/vue/compiler-sfc/index.d.ts:
--------------------------------------------------------------------------------
1 | export * from '@vue/compiler-sfc'
2 |
--------------------------------------------------------------------------------
/packages/vue/compiler-sfc/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('@vue/compiler-sfc')
2 |
3 | require('./register-ts.js')
4 |
--------------------------------------------------------------------------------
/packages/vue/compiler-sfc/index.mjs:
--------------------------------------------------------------------------------
1 | export * from '@vue/compiler-sfc'
2 |
3 | import './register-ts.js'
4 |
--------------------------------------------------------------------------------
/packages/vue/compiler-sfc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "index.js",
3 | "module": "index.mjs"
4 | }
5 |
--------------------------------------------------------------------------------
/packages/vue/compiler-sfc/register-ts.js:
--------------------------------------------------------------------------------
1 | if (typeof require !== 'undefined') {
2 | require('@vue/compiler-sfc').registerTS(() => require('typescript'))
3 | }
4 |
--------------------------------------------------------------------------------
/packages/vue/examples/classic/markdown.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
27 |
28 |
66 |
--------------------------------------------------------------------------------
/packages/vue/examples/composition/markdown.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
31 |
32 |
70 |
--------------------------------------------------------------------------------
/packages/vue/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | if (process.env.NODE_ENV === 'production') {
4 | module.exports = require('./dist/vue.cjs.prod.js')
5 | } else {
6 | module.exports = require('./dist/vue.cjs.js')
7 | }
8 |
--------------------------------------------------------------------------------
/packages/vue/index.mjs:
--------------------------------------------------------------------------------
1 | export * from './index.js'
2 |
--------------------------------------------------------------------------------
/packages/vue/jsx-runtime/index.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/prefer-ts-expect-error */
2 | import type { NativeElements, ReservedProps, VNode } from '@vue/runtime-dom'
3 |
4 | /**
5 | * JSX namespace for usage with @jsxImportsSource directive
6 | * when ts compilerOptions.jsx is 'react-jsx' or 'react-jsxdev'
7 | * https://www.typescriptlang.org/tsconfig#jsxImportSource
8 | */
9 | export { h as jsx, h as jsxDEV, Fragment } from '@vue/runtime-dom'
10 |
11 | export namespace JSX {
12 | export interface Element extends VNode {}
13 | export interface ElementClass {
14 | $props: {}
15 | }
16 | export interface ElementAttributesProperty {
17 | $props: {}
18 | }
19 | export interface IntrinsicElements extends NativeElements {
20 | // allow arbitrary elements
21 | // @ts-ignore suppress ts:2374 = Duplicate string index signature.
22 | [name: string]: any
23 | }
24 | export interface IntrinsicAttributes extends ReservedProps {}
25 | }
26 |
--------------------------------------------------------------------------------
/packages/vue/jsx-runtime/index.js:
--------------------------------------------------------------------------------
1 | const { h, Fragment } = require('vue')
2 |
3 | function jsx(type, props, key) {
4 | const { children } = props
5 | delete props.children
6 | if (arguments.length > 2) {
7 | props.key = key
8 | }
9 | return h(type, props, children)
10 | }
11 |
12 | exports.jsx = jsx
13 | exports.jsxs = jsx
14 | exports.jsxDEV = jsx
15 | exports.Fragment = Fragment
16 |
--------------------------------------------------------------------------------
/packages/vue/jsx-runtime/index.mjs:
--------------------------------------------------------------------------------
1 | import { h, Fragment } from 'vue'
2 |
3 | function jsx(type, props, key) {
4 | const { children } = props
5 | delete props.children
6 | if (arguments.length > 2) {
7 | props.key = key
8 | }
9 | return h(type, props, children)
10 | }
11 |
12 | export { Fragment, jsx, jsx as jsxs, jsx as jsxDEV }
13 |
--------------------------------------------------------------------------------
/packages/vue/jsx-runtime/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "index.js",
3 | "module": "index.mjs",
4 | "types": "index.d.ts"
5 | }
6 |
--------------------------------------------------------------------------------
/packages/vue/jsx.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/prefer-ts-expect-error */
2 | // global JSX namespace registration
3 | // somehow we have to copy=pase the jsx-runtime types here to make TypeScript happy
4 | import type { NativeElements, ReservedProps, VNode } from '@vue/runtime-dom'
5 |
6 | declare global {
7 | namespace JSX {
8 | export interface Element extends VNode {}
9 | export interface ElementClass {
10 | $props: {}
11 | }
12 | export interface ElementAttributesProperty {
13 | $props: {}
14 | }
15 | export interface IntrinsicElements extends NativeElements {
16 | // allow arbitrary elements
17 | // @ts-ignore suppress ts:2374 = Duplicate string index signature.
18 | [name: string]: any
19 | }
20 | export interface IntrinsicAttributes extends ReservedProps {}
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packages/vue/server-renderer/index.d.mts:
--------------------------------------------------------------------------------
1 | export * from '@vue/server-renderer'
2 |
--------------------------------------------------------------------------------
/packages/vue/server-renderer/index.d.ts:
--------------------------------------------------------------------------------
1 | export * from '@vue/server-renderer'
2 |
--------------------------------------------------------------------------------
/packages/vue/server-renderer/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('@vue/server-renderer')
2 |
--------------------------------------------------------------------------------
/packages/vue/server-renderer/index.mjs:
--------------------------------------------------------------------------------
1 | export * from '@vue/server-renderer'
2 |
--------------------------------------------------------------------------------
/packages/vue/server-renderer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "main": "index.js",
3 | "module": "index.mjs"
4 | }
5 |
--------------------------------------------------------------------------------
/packages/vue/src/dev.ts:
--------------------------------------------------------------------------------
1 | import { initCustomFormatter } from '@vue/runtime-dom'
2 |
3 | export function initDev(): void {
4 | if (__BROWSER__) {
5 | /* istanbul ignore if */
6 | if (!__ESM_BUNDLER__) {
7 | console.info(
8 | `You are running a development build of Vue.\n` +
9 | `Make sure to use the production build (*.prod.js) when deploying for production.`,
10 | )
11 | }
12 |
13 | initCustomFormatter()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/packages/vue/src/runtime.ts:
--------------------------------------------------------------------------------
1 | // This entry exports the runtime only, and is built as
2 | // `dist/vue.esm-bundler.js` which is used by default for bundlers.
3 | import { initDev } from './dev'
4 | import { warn } from '@vue/runtime-dom'
5 |
6 | if (__DEV__) {
7 | initDev()
8 | }
9 |
10 | export * from '@vue/runtime-dom'
11 |
12 | export const compile = (): void => {
13 | if (__DEV__) {
14 | warn(
15 | `Runtime compilation is not supported in this build of Vue.` +
16 | (__ESM_BUNDLER__
17 | ? ` Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".`
18 | : __ESM_BROWSER__
19 | ? ` Use "vue.esm-browser.js" instead.`
20 | : __GLOBAL__
21 | ? ` Use "vue.global.js" instead.`
22 | : ``) /* should not happen */,
23 | )
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/pnpm-workspace.yaml:
--------------------------------------------------------------------------------
1 | packages:
2 | - 'packages/*'
3 | - 'packages-private/*'
4 |
5 | catalog:
6 | '@babel/parser': ^7.25.3
7 | '@babel/types': ^7.25.2
8 | 'estree-walker': ^2.0.2
9 | 'magic-string': ^0.30.11
10 | 'source-map-js': ^1.2.0
11 | 'vite': ^5.4.0
12 | '@vitejs/plugin-vue': ^5.1.2
13 |
--------------------------------------------------------------------------------
/scripts/aliases.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | // these aliases are shared between vitest and rollup
3 | import { readdirSync, statSync } from 'node:fs'
4 | import path from 'node:path'
5 | import { fileURLToPath } from 'node:url'
6 |
7 | const resolveEntryForPkg = (/** @type {string} */ p) =>
8 | path.resolve(
9 | fileURLToPath(import.meta.url),
10 | `../../packages/${p}/src/index.ts`,
11 | )
12 |
13 | const dirs = readdirSync(new URL('../packages', import.meta.url))
14 |
15 | /** @type {Record} */
16 | const entries = {
17 | vue: resolveEntryForPkg('vue'),
18 | 'vue/compiler-sfc': resolveEntryForPkg('compiler-sfc'),
19 | 'vue/server-renderer': resolveEntryForPkg('server-renderer'),
20 | '@vue/compat': resolveEntryForPkg('vue-compat'),
21 | }
22 |
23 | const nonSrcPackages = ['sfc-playground', 'template-explorer', 'dts-test']
24 |
25 | for (const dir of dirs) {
26 | const key = `@vue/${dir}`
27 | if (
28 | dir !== 'vue' &&
29 | !nonSrcPackages.includes(dir) &&
30 | !(key in entries) &&
31 | statSync(new URL(`../packages/${dir}`, import.meta.url)).isDirectory()
32 | ) {
33 | entries[key] = resolveEntryForPkg(dir)
34 | }
35 | }
36 |
37 | export { entries }
38 |
--------------------------------------------------------------------------------
/scripts/pre-dev-sfc.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | import fs from 'node:fs'
3 |
4 | const packagesToCheck = [
5 | 'compiler-sfc',
6 | 'compiler-core',
7 | 'compiler-dom',
8 | 'compiler-ssr',
9 | 'shared',
10 | ]
11 |
12 | let allFilesPresent = true
13 |
14 | for (const pkg of packagesToCheck) {
15 | if (
16 | !fs.existsSync(
17 | new URL(`../packages/${pkg}/dist/${pkg}.cjs.js`, import.meta.url),
18 | )
19 | ) {
20 | allFilesPresent = false
21 | break
22 | }
23 | }
24 |
25 | if (!allFilesPresent) {
26 | process.exit(1)
27 | }
28 |
--------------------------------------------------------------------------------
/scripts/verify-commit.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | import pico from 'picocolors'
3 | import { readFileSync } from 'node:fs'
4 | import path from 'node:path'
5 |
6 | const msgPath = path.resolve('.git/COMMIT_EDITMSG')
7 | const msg = readFileSync(msgPath, 'utf-8').trim()
8 |
9 | const commitRE =
10 | /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\(.+\))?: .{1,50}/
11 |
12 | if (!commitRE.test(msg)) {
13 | console.log()
14 | console.error(
15 | ` ${pico.white(pico.bgRed(' ERROR '))} ${pico.red(
16 | `invalid commit message format.`,
17 | )}\n\n` +
18 | pico.red(
19 | ` Proper commit message format is required for automated changelog generation. Examples:\n\n`,
20 | ) +
21 | ` ${pico.green(`feat(compiler): add 'comments' option`)}\n` +
22 | ` ${pico.green(
23 | `fix(v-model): handle events on blur (close #28)`,
24 | )}\n\n` +
25 | pico.red(` See .github/commit-convention.md for more details.\n`),
26 | )
27 | process.exit(1)
28 | }
29 |
--------------------------------------------------------------------------------
/scripts/verify-treeshaking.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | import fs from 'node:fs'
3 | import { exec } from './utils.js'
4 |
5 | exec('pnpm', ['build', 'vue', '-f', 'global-runtime']).then(() => {
6 | const errors = []
7 |
8 | const devBuild = fs.readFileSync(
9 | 'packages/vue/dist/vue.runtime.global.js',
10 | 'utf-8',
11 | )
12 |
13 | if (devBuild.includes('__spreadValues')) {
14 | errors.push(
15 | 'dev build contains unexpected esbuild object spread helper.\n' +
16 | 'This means { ...obj } syntax is used in runtime code. This should be ' +
17 | 'refactored to use the `extend` helper to avoid the extra code.',
18 | )
19 | }
20 |
21 | const prodBuild = fs.readFileSync(
22 | 'packages/vue/dist/vue.runtime.global.prod.js',
23 | 'utf-8',
24 | )
25 |
26 | if (prodBuild.includes('Vue warn')) {
27 | errors.push(
28 | 'prod build contains unexpected warning-related code.\n' +
29 | 'This means there are calls of warn() that are not guarded by the __DEV__ condition.',
30 | )
31 | }
32 |
33 | if (
34 | prodBuild.includes('html,body,base') ||
35 | prodBuild.includes('svg,animate,animateMotion') ||
36 | prodBuild.includes('annotation,annotation-xml,maction')
37 | ) {
38 | errors.push(
39 | 'prod build contains unexpected domTagConifg lists.\n' +
40 | 'This means helpers like isHTMLTag() is used in runtime code paths when it should be compiler-only.',
41 | )
42 | }
43 |
44 | if (errors.length) {
45 | throw new Error(
46 | `Found the following treeshaking errors:\n\n- ${errors.join('\n\n- ')}`,
47 | )
48 | }
49 | })
50 |
--------------------------------------------------------------------------------
/tsconfig.build-browser.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "types": [],
5 | "declaration": true,
6 | "emitDeclarationOnly": true,
7 | "stripInternal": true,
8 | "composite": false
9 | },
10 | "include": [
11 | "packages/global.d.ts",
12 | "packages/vue/src",
13 | "packages/vue-compat/src",
14 | "packages/compiler-core/src",
15 | "packages/compiler-dom/src",
16 | "packages/runtime-core/src",
17 | "packages/runtime-dom/src",
18 | "packages/reactivity/src",
19 | "packages/shared/src"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/tsconfig.build-node.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "types": ["node"],
5 | "declaration": true,
6 | "emitDeclarationOnly": true,
7 | "stripInternal": true,
8 | "composite": false
9 | },
10 | "include": [
11 | "packages/global.d.ts",
12 | "packages/compiler-sfc/src",
13 | "packages/compiler-ssr/src",
14 | "packages/server-renderer/src"
15 | ]
16 | }
17 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "outDir": "temp",
5 | "sourceMap": false,
6 | "target": "es2016",
7 | "newLine": "LF",
8 | "useDefineForClassFields": false,
9 | "module": "esnext",
10 | "moduleResolution": "bundler",
11 | "allowJs": false,
12 | "strict": true,
13 | "noUnusedLocals": true,
14 | "experimentalDecorators": true,
15 | "resolveJsonModule": true,
16 | "isolatedModules": true,
17 | "skipLibCheck": true,
18 | "esModuleInterop": true,
19 | "removeComments": false,
20 | "jsx": "preserve",
21 | "lib": ["es2016", "dom"],
22 | "types": ["vitest/globals", "puppeteer", "node"],
23 | "rootDir": ".",
24 | "paths": {
25 | "@vue/compat": ["packages/vue-compat/src"],
26 | "@vue/*": ["packages/*/src"],
27 | "vue": ["packages/vue/src"]
28 | },
29 | "isolatedDeclarations": true,
30 | "composite": true
31 | },
32 | "include": [
33 | "packages/global.d.ts",
34 | "packages/*/src",
35 | "packages-private/*/src",
36 | "packages/runtime-dom/types/jsx.d.ts",
37 | "packages/*/__tests__",
38 | "packages-private/dts-test",
39 | "packages/vue/jsx-runtime",
40 | "scripts/*",
41 | "rollup.*.js"
42 | ],
43 | "exclude": ["packages-private/sfc-playground/src/vue-dev-proxy*"]
44 | }
45 |
--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------
1 | import { configDefaults, defineConfig } from 'vitest/config'
2 | import { entries } from './scripts/aliases.js'
3 |
4 | export default defineConfig({
5 | define: {
6 | __DEV__: true,
7 | __TEST__: true,
8 | __VERSION__: '"test"',
9 | __BROWSER__: false,
10 | __GLOBAL__: false,
11 | __ESM_BUNDLER__: true,
12 | __ESM_BROWSER__: false,
13 | __CJS__: true,
14 | __SSR__: true,
15 | __FEATURE_OPTIONS_API__: true,
16 | __FEATURE_SUSPENSE__: true,
17 | __FEATURE_PROD_DEVTOOLS__: false,
18 | __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__: false,
19 | __COMPAT__: true,
20 | },
21 | resolve: {
22 | alias: entries,
23 | },
24 | test: {
25 | globals: true,
26 | pool: 'threads',
27 | setupFiles: 'scripts/setup-vitest.ts',
28 | environmentMatchGlobs: [
29 | ['packages/{vue,vue-compat,runtime-dom}/**', 'jsdom'],
30 | ],
31 | sequence: {
32 | hooks: 'list',
33 | },
34 | coverage: {
35 | provider: 'istanbul',
36 | reporter: ['text', 'html'],
37 | exclude: [
38 | ...configDefaults.coverage.exclude!,
39 | // DOM transitions are tested via e2e so no coverage is collected
40 | 'packages/runtime-dom/src/components/Transition*',
41 | // mostly entries
42 | 'packages/vue-compat/**',
43 | 'packages-private/**',
44 | 'scripts/**',
45 | ],
46 | },
47 | },
48 | })
49 |
--------------------------------------------------------------------------------
/vitest.e2e.config.ts:
--------------------------------------------------------------------------------
1 | import { mergeConfig } from 'vitest/config'
2 | import config from './vitest.config'
3 |
4 | export default mergeConfig(config, {
5 | test: {
6 | poolOptions: {
7 | threads: {
8 | singleThread: !!process.env.CI,
9 | },
10 | },
11 | include: ['packages/vue/__tests__/e2e/*.spec.ts'],
12 | },
13 | })
14 |
--------------------------------------------------------------------------------
/vitest.unit.config.ts:
--------------------------------------------------------------------------------
1 | import { configDefaults, mergeConfig } from 'vitest/config'
2 | import config from './vitest.config'
3 |
4 | export default mergeConfig(config, {
5 | test: {
6 | exclude: [...configDefaults.exclude, '**/e2e/**'],
7 | },
8 | })
9 |
--------------------------------------------------------------------------------
/vitest.workspace.ts:
--------------------------------------------------------------------------------
1 | import { defineWorkspace } from 'vitest/config'
2 |
3 | export default defineWorkspace([
4 | './vitest.unit.config.ts',
5 | './vitest.e2e.config.ts',
6 | ])
7 |
--------------------------------------------------------------------------------