├── .circleci └── config.yml ├── .eslintrc.js ├── .gitignore ├── .ls-lint.yml ├── .prettierrc ├── .vscode ├── launch.json └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── api-extractor.json ├── doc ├── assets │ ├── debugger.png │ ├── debugger2.png │ ├── proxy_limit.png │ └── proxy_set_handler.png ├── effect.md ├── prepare.md ├── reactive.md └── ref.md ├── jest.config.js ├── package.json ├── 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__ │ │ │ │ ├── hoistStatic.spec.ts.snap │ │ │ │ ├── transformText.spec.ts.snap │ │ │ │ ├── vFor.spec.ts.snap │ │ │ │ ├── vIf.spec.ts.snap │ │ │ │ ├── vModel.spec.ts.snap │ │ │ │ ├── vOnce.spec.ts.snap │ │ │ │ └── vSlot.spec.ts.snap │ │ │ ├── hoistStatic.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 │ │ │ ├── vModel.spec.ts │ │ │ ├── vOn.spec.ts │ │ │ ├── vOnce.spec.ts │ │ │ └── vSlot.spec.ts │ │ └── utils.spec.ts │ ├── api-extractor.json │ ├── index.js │ ├── package.json │ └── src │ │ ├── ast.ts │ │ ├── codegen.ts │ │ ├── compile.ts │ │ ├── errors.ts │ │ ├── index.ts │ │ ├── options.ts │ │ ├── parse.ts │ │ ├── runtimeHelpers.ts │ │ ├── transform.ts │ │ ├── transforms │ │ ├── hoistStatic.ts │ │ ├── noopDirectiveTransform.ts │ │ ├── transformElement.ts │ │ ├── transformExpression.ts │ │ ├── transformSlotOutlet.ts │ │ ├── transformText.ts │ │ ├── vBind.ts │ │ ├── vFor.ts │ │ ├── vIf.ts │ │ ├── vModel.ts │ │ ├── vOn.ts │ │ ├── vOnce.ts │ │ └── vSlot.ts │ │ ├── utils.ts │ │ └── validateExpression.ts ├── compiler-dom │ ├── LICENSE │ ├── README.md │ ├── __tests__ │ │ ├── __snapshots__ │ │ │ └── index.spec.ts.snap │ │ ├── index.spec.ts │ │ ├── parse.spec.ts │ │ └── transforms │ │ │ ├── __snapshots__ │ │ │ ├── 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 │ │ │ └── warnTransitionChildren.spec.ts │ ├── api-extractor.json │ ├── index.js │ ├── package.json │ └── src │ │ ├── decodeHtml.ts │ │ ├── decodeHtmlBrowser.ts │ │ ├── errors.ts │ │ ├── index.ts │ │ ├── namedChars.json │ │ ├── parserOptions.ts │ │ ├── runtimeHelpers.ts │ │ └── transforms │ │ ├── ignoreSideEffectTags.ts │ │ ├── stringifyStatic.ts │ │ ├── transformStyle.ts │ │ ├── vHtml.ts │ │ ├── vModel.ts │ │ ├── vOn.ts │ │ ├── vShow.ts │ │ ├── vText.ts │ │ └── warnTransitionChildren.ts ├── compiler-sfc │ ├── README.md │ ├── __tests__ │ │ ├── __snapshots__ │ │ │ ├── compileScript.spec.ts.snap │ │ │ ├── compileTemplate.spec.ts.snap │ │ │ ├── templateTransformAssetUrl.spec.ts.snap │ │ │ └── templateTransformSrcset.spec.ts.snap │ │ ├── compileScript.spec.ts │ │ ├── compileStyle.spec.ts │ │ ├── compileTemplate.spec.ts │ │ ├── fixture │ │ │ └── import.scss │ │ ├── parse.spec.ts │ │ ├── rewriteDefault.spec.ts │ │ ├── templateTransformAssetUrl.spec.ts │ │ ├── templateTransformSrcset.spec.ts │ │ └── templateUtils.spec.ts │ ├── api-extractor.json │ ├── package.json │ └── src │ │ ├── compileScript.ts │ │ ├── compileStyle.ts │ │ ├── compileTemplate.ts │ │ ├── genCssVars.ts │ │ ├── index.ts │ │ ├── parse.ts │ │ ├── rewriteDefault.ts │ │ ├── shims.d.ts │ │ ├── stylePluginScoped.ts │ │ ├── stylePluginScopedVars.ts │ │ ├── stylePluginTrim.ts │ │ ├── stylePreprocessors.ts │ │ ├── templateTransformAssetUrl.ts │ │ ├── templateTransformSrcset.ts │ │ └── templateUtils.ts ├── compiler-ssr │ ├── README.md │ ├── __tests__ │ │ ├── ssrComponent.spec.ts │ │ ├── ssrElement.spec.ts │ │ ├── ssrInjectCssVars.spec.ts │ │ ├── ssrPortal.spec.ts │ │ ├── ssrScopeId.spec.ts │ │ ├── ssrSlotOutlet.spec.ts │ │ ├── ssrSuspense.spec.ts │ │ ├── ssrText.spec.ts │ │ ├── ssrVFor.spec.ts │ │ ├── ssrVIf.spec.ts │ │ ├── ssrVModel.spec.ts │ │ ├── ssrVShow.spec.ts │ │ └── utils.ts │ ├── api-extractor.json │ ├── 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 │ │ ├── ssrVFor.ts │ │ ├── ssrVIf.ts │ │ ├── ssrVModel.ts │ │ └── ssrVShow.ts ├── global.d.ts ├── reactivity │ ├── LICENSE │ ├── README.md │ ├── __tests__ │ │ ├── collections │ │ │ ├── Map.spec.ts │ │ │ ├── Set.spec.ts │ │ │ ├── WeakMap.spec.ts │ │ │ └── WeakSet.spec.ts │ │ ├── computed.spec.ts │ │ ├── effect.spec.ts │ │ ├── reactive.spec.ts │ │ ├── reactiveArray.spec.ts │ │ ├── readonly.spec.ts │ │ ├── ref.spec.ts │ │ └── shallowReactive.spec.ts │ ├── api-extractor.json │ ├── index.js │ ├── package.json │ └── src │ │ ├── baseHandlers.ts │ │ ├── collectionHandlers.ts │ │ ├── computed.ts │ │ ├── effect.ts │ │ ├── index.ts │ │ ├── operations.ts │ │ ├── reactive.ts │ │ └── ref.ts ├── runtime-core │ ├── LICENSE │ ├── README.md │ ├── __tests__ │ │ ├── apiAsyncComponent.spec.ts │ │ ├── apiCreateApp.spec.ts │ │ ├── apiInject.spec.ts │ │ ├── apiLifecycle.spec.ts │ │ ├── apiOptions.spec.ts │ │ ├── apiSetupContext.spec.ts │ │ ├── apiTemplateRef.spec.ts │ │ ├── apiWatch.spec.ts │ │ ├── componentEmits.spec.ts │ │ ├── componentProps.spec.ts │ │ ├── componentProxy.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 │ │ │ ├── scopeId.spec.ts │ │ │ └── toHandlers.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 │ │ ├── scheduler.spec.ts │ │ ├── vnode.spec.ts │ │ └── vnodeHooks.spec.ts │ ├── api-extractor.json │ ├── index.js │ ├── package.json │ ├── src │ │ ├── apiAsyncComponent.ts │ │ ├── apiComputed.ts │ │ ├── apiCreateApp.ts │ │ ├── apiDefineComponent.ts │ │ ├── apiInject.ts │ │ ├── apiLifecycle.ts │ │ ├── apiWatch.ts │ │ ├── component.ts │ │ ├── componentEmits.ts │ │ ├── componentOptions.ts │ │ ├── componentProps.ts │ │ ├── componentPublicInstance.ts │ │ ├── componentRenderUtils.ts │ │ ├── componentSlots.ts │ │ ├── components │ │ │ ├── BaseTransition.ts │ │ │ ├── KeepAlive.ts │ │ │ ├── Suspense.ts │ │ │ └── Teleport.ts │ │ ├── customFormatter.ts │ │ ├── devtools.ts │ │ ├── directives.ts │ │ ├── errorHandling.ts │ │ ├── featureFlags.ts │ │ ├── h.ts │ │ ├── helpers │ │ │ ├── createSlots.ts │ │ │ ├── renderList.ts │ │ │ ├── renderSlot.ts │ │ │ ├── resolveAssets.ts │ │ │ ├── scopeId.ts │ │ │ ├── toHandlers.ts │ │ │ ├── typeUtils.ts │ │ │ ├── useSsrContext.ts │ │ │ └── withRenderContext.ts │ │ ├── hmr.ts │ │ ├── hydration.ts │ │ ├── index.ts │ │ ├── profiling.ts │ │ ├── renderer.ts │ │ ├── scheduler.ts │ │ ├── vnode.ts │ │ └── warning.ts │ └── types │ │ └── refBail.d.ts ├── runtime-dom │ ├── LICENSE │ ├── README.md │ ├── __tests__ │ │ ├── customizedBuiltIn.spec.ts │ │ ├── directives │ │ │ ├── vCloak.spec.ts │ │ │ ├── vModel.spec.ts │ │ │ ├── vOn.spec.ts │ │ │ └── vShow.spec.ts │ │ ├── helpers │ │ │ ├── useCssModule.spec.ts │ │ │ └── useCssVars.spec.ts │ │ ├── patchAttrs.spec.ts │ │ ├── patchClass.spec.ts │ │ ├── patchEvents.spec.ts │ │ ├── patchProps.spec.ts │ │ ├── patchStyle.spec.ts │ │ └── rendererStaticNode.spec.ts │ ├── api-extractor.json │ ├── index.js │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── Transition.ts │ │ │ └── TransitionGroup.ts │ │ ├── directives │ │ │ ├── vModel.ts │ │ │ ├── vOn.ts │ │ │ └── vShow.ts │ │ ├── helpers │ │ │ ├── useCssModule.ts │ │ │ └── useCssVars.ts │ │ ├── index.ts │ │ ├── modules │ │ │ ├── attrs.ts │ │ │ ├── class.ts │ │ │ ├── events.ts │ │ │ ├── props.ts │ │ │ └── style.ts │ │ ├── nodeOps.ts │ │ └── patchProp.ts │ └── types │ │ ├── jsx.d.ts │ │ └── refBail.d.ts ├── runtime-test │ ├── LICENSE │ ├── README.md │ ├── __tests__ │ │ └── testRuntime.spec.ts │ ├── api-extractor.json │ ├── index.js │ ├── package.json │ └── src │ │ ├── index.ts │ │ ├── nodeOps.ts │ │ ├── patchProp.ts │ │ ├── serialize.ts │ │ └── triggerEvent.ts ├── server-renderer │ ├── LICENSE │ ├── README.md │ ├── __tests__ │ │ ├── renderToStream.spec.ts │ │ ├── renderToString.spec.ts │ │ ├── ssrAttrFallthrough.spec.ts │ │ ├── ssrDirectives.spec.ts │ │ ├── ssrDynamicComponent.spec.ts │ │ ├── ssrInterpolate.spec.ts │ │ ├── ssrRenderAttrs.spec.ts │ │ ├── ssrRenderList.spec.ts │ │ ├── ssrResolveCssVars.spec.ts │ │ ├── ssrScopeId.spec.ts │ │ ├── ssrSuspense.spec.ts │ │ ├── ssrTeleport.spec.ts │ │ └── ssrVModelHelpers.spec.ts │ ├── api-extractor.json │ ├── index.js │ ├── package.json │ └── src │ │ ├── helpers │ │ ├── ssrCompile.ts │ │ ├── ssrInterpolate.ts │ │ ├── ssrRenderAttrs.ts │ │ ├── ssrRenderComponent.ts │ │ ├── ssrRenderList.ts │ │ ├── ssrRenderSlot.ts │ │ ├── ssrRenderSuspense.ts │ │ ├── ssrRenderTeleport.ts │ │ ├── ssrResolveCssVars.ts │ │ └── ssrVModelHelpers.ts │ │ ├── index.ts │ │ ├── render.ts │ │ ├── renderToStream.ts │ │ └── renderToString.ts ├── shared │ ├── README.md │ ├── __tests__ │ │ ├── __snapshots__ │ │ │ └── codeframe.spec.ts.snap │ │ ├── codeframe.spec.ts │ │ ├── escapeHtml.spec.ts │ │ ├── looseEqual.spec.ts │ │ └── toDisplayString.spec.ts │ ├── api-extractor.json │ ├── index.js │ ├── package.json │ └── src │ │ ├── codeframe.ts │ │ ├── domAttrConfig.ts │ │ ├── domTagConfig.ts │ │ ├── escapeHtml.ts │ │ ├── globalsWhitelist.ts │ │ ├── index.ts │ │ ├── looseEqual.ts │ │ ├── makeMap.ts │ │ ├── normalizeProp.ts │ │ ├── patchFlags.ts │ │ ├── shapeFlags.ts │ │ ├── slotFlags.ts │ │ └── toDisplayString.ts ├── size-check │ ├── README.md │ ├── package.json │ └── src │ │ └── index.ts ├── template-explorer │ ├── README.md │ ├── index.html │ ├── local.html │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── options.ts │ │ └── theme.ts │ └── style.css └── vue │ ├── README.md │ ├── __tests__ │ ├── Transition.spec.ts │ ├── TransitionGroup.spec.ts │ ├── e2eUtils.ts │ ├── index.spec.ts │ ├── svgNamespace.spec.ts │ └── transition.html │ ├── api-extractor.json │ ├── examples │ ├── __tests__ │ │ ├── commits.mock.ts │ │ ├── commits.spec.ts │ │ ├── grid.spec.ts │ │ ├── markdown.spec.ts │ │ ├── svg.spec.ts │ │ ├── todomvc.spec.ts │ │ └── tree.spec.ts │ ├── classic │ │ ├── commits.html │ │ ├── grid.html │ │ ├── markdown.html │ │ ├── svg.html │ │ ├── todomvc.html │ │ └── tree.html │ ├── composition │ │ ├── commits.html │ │ ├── grid.html │ │ ├── markdown.html │ │ ├── svg.html │ │ ├── test.html │ │ ├── todomvc.html │ │ └── tree.html │ └── transition │ │ ├── list.html │ │ └── modal.html │ ├── index.js │ ├── package.json │ └── src │ ├── dev.ts │ ├── index.ts │ └── runtime.ts ├── rollup.config.js ├── scripts ├── bootstrap.js ├── build.js ├── checkYarn.js ├── dev.js ├── release.js ├── setupJestEnv.ts ├── utils.js └── verifyCommit.js ├── test-dts ├── README.md ├── component.test-d.ts ├── componentTypeExtensions.test-d.tsx ├── defineComponent.test-d.tsx ├── functionalComponent.test-d.tsx ├── h.test-d.ts ├── index.d.ts ├── inject.test-d.ts ├── reactivity.test-d.ts ├── ref.test-d.ts ├── tsconfig.build.json ├── tsconfig.json ├── tsx.test-d.tsx └── watch.test-d.ts ├── tsconfig.json └── yarn.lock /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | defaults: &defaults 4 | docker: 5 | - image: vuejs/ci 6 | 7 | step_restore_cache: &restore_cache 8 | restore_cache: 9 | keys: 10 | - v1-dependencies-{{ checksum "yarn.lock" }}-1 11 | - v1-dependencies- 12 | 13 | step_install_deps: &install_deps 14 | run: 15 | name: Install Dependencies 16 | command: yarn --frozen-lockfile 17 | 18 | step_save_cache: &save_cache 19 | save_cache: 20 | paths: 21 | - node_modules 22 | - packages/compiler-core/node_modules 23 | - packages/compiler-sfc/node_modules 24 | - packages/vue/node_modules 25 | - ~/.cache/yarn 26 | key: v1-dependencies-{{ checksum "yarn.lock" }}-1 27 | 28 | jobs: 29 | test: 30 | <<: *defaults 31 | steps: 32 | - checkout 33 | - *restore_cache 34 | - *install_deps 35 | - *save_cache 36 | - run: yarn ls-lint 37 | - run: yarn test --ci 38 | 39 | test-dts: 40 | <<: *defaults 41 | steps: 42 | - checkout 43 | - *restore_cache 44 | - *install_deps 45 | - *save_cache 46 | - run: yarn test-dts 47 | 48 | workflows: 49 | version: 2 50 | ci: 51 | jobs: 52 | - test 53 | - test-dts 54 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const DOMGlobals = ['window', 'document'] 2 | const NodeGlobals = ['module', 'require'] 3 | 4 | module.exports = { 5 | parser: '@typescript-eslint/parser', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | rules: { 10 | 'no-unused-vars': [ 11 | 'error', 12 | // we are only using this rule to check for unused arguments since TS 13 | // catches unused variables but not args. 14 | { varsIgnorePattern: '.*', args: 'none' } 15 | ], 16 | // most of the codebase are expected to be env agnostic 17 | 'no-restricted-globals': ['error', ...DOMGlobals, ...NodeGlobals], 18 | // since we target ES2015 for baseline support, we need to forbid object 19 | // rest spread usage (both assign and destructure) 20 | 'no-restricted-syntax': [ 21 | 'error', 22 | 'ObjectExpression > SpreadElement', 23 | 'ObjectPattern > RestElement' 24 | ] 25 | }, 26 | overrides: [ 27 | // tests, no restrictions (runs in Node / jest with jsdom) 28 | { 29 | files: ['**/__tests__/**', 'test-dts/**'], 30 | rules: { 31 | 'no-restricted-globals': 'off', 32 | 'no-restricted-syntax': 'off' 33 | } 34 | }, 35 | // shared, may be used in any env 36 | { 37 | files: ['packages/shared/**'], 38 | rules: { 39 | 'no-restricted-globals': 'off' 40 | } 41 | }, 42 | // Packages targeting DOM 43 | { 44 | files: ['packages/{vue,runtime-dom}/**'], 45 | rules: { 46 | 'no-restricted-globals': ['error', ...NodeGlobals] 47 | } 48 | }, 49 | // Packages targeting Node 50 | { 51 | files: ['packages/{compiler-sfc,compiler-ssr,server-renderer}/**'], 52 | rules: { 53 | 'no-restricted-globals': ['error', ...DOMGlobals], 54 | 'no-restricted-syntax': 'off' 55 | } 56 | }, 57 | // Private package, browser only + no syntax restrictions 58 | { 59 | files: ['packages/template-explorer/**'], 60 | rules: { 61 | 'no-restricted-globals': ['error', ...NodeGlobals], 62 | 'no-restricted-syntax': 'off' 63 | } 64 | } 65 | ] 66 | } 67 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | .DS_Store 3 | node_modules 4 | coverage 5 | temp 6 | explorations 7 | TODOs.md 8 | *.log 9 | -------------------------------------------------------------------------------- /.ls-lint.yml: -------------------------------------------------------------------------------- 1 | ls: 2 | packages/*/{src,__tests__}: 3 | .js: kebab-case 4 | .ts: camelCase | PascalCase 5 | .d.ts: camelCase 6 | .spec.ts: camelCase | PascalCase 7 | .mock.ts: camelCase 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | semi: false 2 | singleQuote: true 3 | printWidth: 80 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 | "name": "Jest", 9 | "type": "node", 10 | "request": "launch", 11 | "program": "${workspaceFolder}/node_modules/.bin/jest", 12 | "stopOnEntry": false, 13 | "args": ["${fileBasename}", "--runInBand", "--detectOpenHandles"], 14 | "cwd": "${workspaceFolder}", 15 | "preLaunchTask": null, 16 | "runtimeExecutable": null, 17 | "runtimeArgs": ["--nolazy"], 18 | "env": { 19 | "NODE_ENV": "development" 20 | }, 21 | "console": "integratedTerminal", 22 | "sourceMaps": true, 23 | "windows": { 24 | "program": "${workspaceFolder}/node_modules/jest/bin/jest", 25 | } 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### vue-next 源码分析 2 | 3 | #### reactivity 模块 4 | * [prepare 准备工作](https://github.com/HUYIJUNCODING/vue-next-analysis/blob/master/doc/prepare.md) 5 | * [ref 源码分析](https://github.com/HUYIJUNCODING/vue-next-analysis/blob/master/doc/ref.md) 6 | * [reactive 源码分析](https://github.com/HUYIJUNCODING/vue-next-analysis/blob/master/doc/reactive.md) 7 | * [effect 源码分析](https://github.com/HUYIJUNCODING/vue-next-analysis/blob/master/doc/effect.md) 8 | 9 | -------------------------------------------------------------------------------- /api-extractor.json: -------------------------------------------------------------------------------- 1 | // this the shared base config for all packages. 2 | { 3 | "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", 4 | 5 | "apiReport": { 6 | "enabled": true, 7 | "reportFolder": "/temp/" 8 | }, 9 | 10 | "docModel": { 11 | "enabled": true 12 | }, 13 | 14 | "dtsRollup": { 15 | "enabled": true 16 | }, 17 | 18 | "tsdocMetadata": { 19 | "enabled": false 20 | }, 21 | 22 | "messages": { 23 | "compilerMessageReporting": { 24 | "default": { 25 | "logLevel": "warning" 26 | } 27 | }, 28 | 29 | "extractorMessageReporting": { 30 | "default": { 31 | "logLevel": "warning", 32 | "addToApiReportFile": true 33 | }, 34 | 35 | "ae-missing-release-tag": { 36 | "logLevel": "none" 37 | } 38 | }, 39 | 40 | "tsdocMessageReporting": { 41 | "default": { 42 | "logLevel": "warning" 43 | }, 44 | 45 | "tsdoc-undefined-tag": { 46 | "logLevel": "none" 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /doc/assets/debugger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HUYIJUNCODING/vue-next-analysis/a157d2395997972a529ed3e4c54c9dd52e90ba84/doc/assets/debugger.png -------------------------------------------------------------------------------- /doc/assets/debugger2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HUYIJUNCODING/vue-next-analysis/a157d2395997972a529ed3e4c54c9dd52e90ba84/doc/assets/debugger2.png -------------------------------------------------------------------------------- /doc/assets/proxy_limit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HUYIJUNCODING/vue-next-analysis/a157d2395997972a529ed3e4c54c9dd52e90ba84/doc/assets/proxy_limit.png -------------------------------------------------------------------------------- /doc/assets/proxy_set_handler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HUYIJUNCODING/vue-next-analysis/a157d2395997972a529ed3e4c54c9dd52e90ba84/doc/assets/proxy_set_handler.png -------------------------------------------------------------------------------- /doc/prepare.md: -------------------------------------------------------------------------------- 1 | # 源码调试前的准备工作 2 | ## 1. git clone git@github.com:vuejs/vue-next.git 将 vue-next 源代码克隆至本地 3 | 4 | ## 2. 项目根目录 yarn install 安装依赖包 5 | * 安装依赖要用 `yarn install` ,使用 `npm install /cnpm install `安装依赖包会报错 6 | * 这里需要注意的是安装依赖对 `node` 版本有要求,笔者开始使用 `v12.18.3` 版本会安装依赖报错,然后升级至 `12.19.0` 就安装成功了(推荐使用 `nvm` 进行 `node` 版本管理) 7 | 8 | ## 3. npm run dev 本地启动项目 9 | 10 | ## 4. 安装 Jest Runner 插件 + debugger 打断点调试 11 | 12 | * `vscode` (安装插件很方便,调试也很方便,`ts` 支持友好) 13 | * 可以采用调试单测实例的方式调试源码,每一个模块下都有一个`__tests__` 文件夹,存放的就是该模块所有的单测实例,安装了`Jest Runner` 插件后,在目标位置打上断点,点击 `Debug` 按钮,一路点点点即可 14 | 15 | ![单测实例调试](https://github.com/HUYIJUNCODING/vue-next-analysis/blob/master/doc/assets/debugger.png) 16 | 17 | * 新建 `html` 页面 + `vue.global.js` 自己写 `demo` 浏览器端断点调试(右键浏览器运行,然后打断点调试即可,`vue.global.js` 是执行 `npm run dev` 命令生成的编译后源码文件) 18 | 19 | ![浏览器端demo调试](https://github.com/HUYIJUNCODING/vue-next-analysis/blob/master/doc/assets/debugger2.png) 20 | 21 | 22 | 以上就是调试源码之前的一些准备工作,如果一切就绪,接下来就尽情享受阅读源码带来的快乐吧! 23 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | setupFilesAfterEnv: ['./scripts/setupJestEnv.ts'], 4 | globals: { 5 | __DEV__: true, 6 | __TEST__: true, 7 | __VERSION__: require('./package.json').version, 8 | __BROWSER__: false, 9 | __GLOBAL__: false, 10 | __ESM_BUNDLER__: true, 11 | __ESM_BROWSER__: false, 12 | __NODE_JS__: true, 13 | __FEATURE_OPTIONS_API__: true, 14 | __FEATURE_SUSPENSE__: true, 15 | __FEATURE_PROD_DEVTOOLS__: false 16 | }, 17 | coverageDirectory: 'coverage', 18 | coverageReporters: ['html', 'lcov', 'text'], 19 | collectCoverageFrom: [ 20 | 'packages/*/src/**/*.ts', 21 | '!packages/runtime-test/src/utils/**', 22 | '!packages/template-explorer/**', 23 | '!packages/size-check/**', 24 | '!packages/runtime-core/src/profiling.ts', 25 | '!packages/runtime-core/src/customFormatter.ts', 26 | // DOM transitions are tested via e2e so no coverage is collected 27 | '!packages/runtime-dom/src/components/Transition*', 28 | // only called in browsers 29 | '!packages/vue/src/devCheck.ts', 30 | // only used as a build entry 31 | '!packages/vue/src/runtime.ts' 32 | ], 33 | watchPathIgnorePatterns: ['/node_modules/', '/dist/', '/.git/'], 34 | moduleFileExtensions: ['ts', 'tsx', 'js', 'json'], 35 | moduleNameMapper: { 36 | '^@vue/(.*?)$': '/packages/$1/src', 37 | vue: '/packages/vue/src' 38 | }, 39 | rootDir: __dirname, 40 | testMatch: ['/packages/**/__tests__/**/*spec.[jt]s?(x)'], 41 | testPathIgnorePatterns: process.env.SKIP_E2E 42 | ? // ignore example tests on netlify builds since they don't contribute 43 | // to coverage and can cause netlify builds to fail 44 | ['/node_modules/', '/examples/__tests__'] 45 | : ['/node_modules/'] 46 | } 47 | -------------------------------------------------------------------------------- /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 | baseParse as parse, 3 | transform, 4 | ElementNode, 5 | noopDirectiveTransform, 6 | VNodeCall 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__/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { Position } from '../src/ast' 2 | import { getInnerRange, advancePositionWithClone } from '../src/utils' 3 | 4 | function p(line: number, column: number, offset: number): Position { 5 | return { column, line, offset } 6 | } 7 | 8 | describe('advancePositionWithClone', () => { 9 | test('same line', () => { 10 | const pos = p(1, 1, 0) 11 | const newPos = advancePositionWithClone(pos, 'foo\nbar', 2) 12 | 13 | expect(newPos.column).toBe(3) 14 | expect(newPos.line).toBe(1) 15 | expect(newPos.offset).toBe(2) 16 | }) 17 | 18 | test('same line', () => { 19 | const pos = p(1, 1, 0) 20 | const newPos = advancePositionWithClone(pos, 'foo\nbar', 4) 21 | 22 | expect(newPos.column).toBe(1) 23 | expect(newPos.line).toBe(2) 24 | expect(newPos.offset).toBe(4) 25 | }) 26 | 27 | test('multiple lines', () => { 28 | const pos = p(1, 1, 0) 29 | const newPos = advancePositionWithClone(pos, 'foo\nbar\nbaz', 10) 30 | 31 | expect(newPos.column).toBe(3) 32 | expect(newPos.line).toBe(3) 33 | expect(newPos.offset).toBe(10) 34 | }) 35 | }) 36 | 37 | describe('getInnerRange', () => { 38 | const loc1 = { 39 | source: 'foo\nbar\nbaz', 40 | start: p(1, 1, 0), 41 | end: p(3, 3, 11) 42 | } 43 | 44 | test('at start', () => { 45 | const loc2 = getInnerRange(loc1, 0, 4) 46 | expect(loc2.start).toEqual(loc1.start) 47 | expect(loc2.end.column).toBe(1) 48 | expect(loc2.end.line).toBe(2) 49 | expect(loc2.end.offset).toBe(4) 50 | }) 51 | 52 | test('at end', () => { 53 | const loc2 = getInnerRange(loc1, 4) 54 | expect(loc2.start.column).toBe(1) 55 | expect(loc2.start.line).toBe(2) 56 | expect(loc2.start.offset).toBe(4) 57 | expect(loc2.end).toEqual(loc1.end) 58 | }) 59 | 60 | test('in between', () => { 61 | const loc2 = getInnerRange(loc1, 4, 3) 62 | expect(loc2.start.column).toBe(1) 63 | expect(loc2.start.line).toBe(2) 64 | expect(loc2.start.offset).toBe(4) 65 | expect(loc2.end.column).toBe(4) 66 | expect(loc2.end.line).toBe(2) 67 | expect(loc2.end.offset).toBe(7) 68 | }) 69 | }) 70 | -------------------------------------------------------------------------------- /packages/compiler-core/api-extractor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../api-extractor.json", 3 | "mainEntryPointFilePath": "./dist/packages//src/index.d.ts", 4 | "dtsRollup": { 5 | "publicTrimmedFilePath": "./dist/.d.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /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.0.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 | "buildOptions": { 13 | "name": "VueCompilerCore", 14 | "formats": [ 15 | "esm-bundler", 16 | "cjs" 17 | ] 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/vuejs/vue-next.git", 22 | "directory": "packages/compiler-core" 23 | }, 24 | "keywords": [ 25 | "vue" 26 | ], 27 | "author": "Evan You", 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/vuejs/vue-next/issues" 31 | }, 32 | "homepage": "https://github.com/vuejs/vue-next/tree/master/packages/compiler-core#readme", 33 | "dependencies": { 34 | "@vue/shared": "3.0.2", 35 | "@babel/parser": "^7.12.0", 36 | "@babel/types": "^7.12.0", 37 | "estree-walker": "^2.0.1", 38 | "source-map": "^0.6.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/compiler-core/src/index.ts: -------------------------------------------------------------------------------- 1 | export { baseCompile } from './compile' 2 | 3 | // Also expose lower level APIs & types 4 | export { 5 | CompilerOptions, 6 | ParserOptions, 7 | TransformOptions, 8 | CodegenOptions, 9 | HoistTransform, 10 | BindingMetadata 11 | } from './options' 12 | export { baseParse, TextModes } from './parse' 13 | export { 14 | transform, 15 | TransformContext, 16 | createTransformContext, 17 | traverseNode, 18 | createStructuralDirectiveTransform, 19 | NodeTransform, 20 | StructuralDirectiveTransform, 21 | DirectiveTransform 22 | } from './transform' 23 | export { generate, CodegenContext, CodegenResult } from './codegen' 24 | export { 25 | ErrorCodes, 26 | CoreCompilerError, 27 | CompilerError, 28 | createCompilerError 29 | } from './errors' 30 | 31 | export * from './ast' 32 | export * from './utils' 33 | export * from './runtimeHelpers' 34 | 35 | export { getBaseTransformPreset, TransformPreset } from './compile' 36 | export { transformModel } from './transforms/vModel' 37 | export { transformOn } from './transforms/vOn' 38 | export { transformBind } from './transforms/vBind' 39 | export { noopDirectiveTransform } from './transforms/noopDirectiveTransform' 40 | export { processIf } from './transforms/vIf' 41 | export { processFor, createForLoopParams } from './transforms/vFor' 42 | export { 43 | transformExpression, 44 | processExpression 45 | } from './transforms/transformExpression' 46 | export { 47 | buildSlots, 48 | SlotFnBuilder, 49 | trackVForSlotScopes, 50 | trackSlotScopes 51 | } from './transforms/vSlot' 52 | export { 53 | transformElement, 54 | resolveComponentType, 55 | buildProps 56 | } from './transforms/transformElement' 57 | export { processSlotOutlet } from './transforms/transformSlotOutlet' 58 | export { generateCodeFrame } from '@vue/shared' 59 | -------------------------------------------------------------------------------- /packages/compiler-core/src/transforms/noopDirectiveTransform.ts: -------------------------------------------------------------------------------- 1 | import { DirectiveTransform } from '../transform' 2 | 3 | export const noopDirectiveTransform: DirectiveTransform = () => ({ props: [] }) 4 | -------------------------------------------------------------------------------- /packages/compiler-core/src/transforms/vBind.ts: -------------------------------------------------------------------------------- 1 | import { DirectiveTransform } from '../transform' 2 | import { createObjectProperty, createSimpleExpression, NodeTypes } from '../ast' 3 | import { createCompilerError, ErrorCodes } from '../errors' 4 | import { camelize } from '@vue/shared' 5 | import { CAMELIZE } from '../runtimeHelpers' 6 | 7 | // v-bind without arg is handled directly in ./transformElements.ts due to it affecting 8 | // codegen for the entire props object. This transform here is only for v-bind 9 | // *with* args. 10 | export const transformBind: DirectiveTransform = (dir, node, context) => { 11 | const { exp, modifiers, loc } = dir 12 | const arg = dir.arg! 13 | 14 | if (arg.type !== NodeTypes.SIMPLE_EXPRESSION) { 15 | arg.children.unshift(`(`) 16 | arg.children.push(`) || ""`) 17 | } else if (!arg.isStatic) { 18 | arg.content = `${arg.content} || ""` 19 | } 20 | 21 | // .prop is no longer necessary due to new patch behavior 22 | // .sync is replaced by v-model:arg 23 | if (modifiers.includes('camel')) { 24 | if (arg.type === NodeTypes.SIMPLE_EXPRESSION) { 25 | if (arg.isStatic) { 26 | arg.content = camelize(arg.content) 27 | } else { 28 | arg.content = `${context.helperString(CAMELIZE)}(${arg.content})` 29 | } 30 | } else { 31 | arg.children.unshift(`${context.helperString(CAMELIZE)}(`) 32 | arg.children.push(`)`) 33 | } 34 | } 35 | 36 | if ( 37 | !exp || 38 | (exp.type === NodeTypes.SIMPLE_EXPRESSION && !exp.content.trim()) 39 | ) { 40 | context.onError(createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc)) 41 | return { 42 | props: [createObjectProperty(arg!, createSimpleExpression('', true, loc))] 43 | } 44 | } 45 | 46 | return { 47 | props: [createObjectProperty(arg!, exp)] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/compiler-core/src/transforms/vOnce.ts: -------------------------------------------------------------------------------- 1 | import { NodeTransform } from '../transform' 2 | import { findDir } from '../utils' 3 | import { ElementNode, ForNode, 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)) { 11 | return 12 | } 13 | seen.add(node) 14 | context.helper(SET_BLOCK_TRACKING) 15 | return () => { 16 | const cur = context.currentNode as ElementNode | IfNode | ForNode 17 | if (cur.codegenNode) { 18 | cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */) 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/compiler-core/src/validateExpression.ts: -------------------------------------------------------------------------------- 1 | // these keywords should not appear inside expressions, but operators like 2 | 3 | import { SimpleExpressionNode } from './ast' 4 | import { TransformContext } from './transform' 5 | import { createCompilerError, ErrorCodes } from './errors' 6 | 7 | // typeof, instanceof and in are allowed 8 | const prohibitedKeywordRE = new RegExp( 9 | '\\b' + 10 | ( 11 | 'do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,' + 12 | 'super,throw,while,yield,delete,export,import,return,switch,default,' + 13 | 'extends,finally,continue,debugger,function,arguments,typeof,void' 14 | ) 15 | .split(',') 16 | .join('\\b|\\b') + 17 | '\\b' 18 | ) 19 | 20 | // strip strings in expressions 21 | const stripStringRE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`/g 22 | 23 | /** 24 | * Validate a non-prefixed expression. 25 | * This is only called when using the in-browser runtime compiler since it 26 | * doesn't prefix expressions. 27 | */ 28 | export function validateBrowserExpression( 29 | node: SimpleExpressionNode, 30 | context: TransformContext, 31 | asParams = false, 32 | asRawStatements = false 33 | ) { 34 | const exp = node.content 35 | 36 | // empty expressions are validated per-directive since some directives 37 | // do allow empty expressions. 38 | if (!exp.trim()) { 39 | return 40 | } 41 | 42 | try { 43 | new Function( 44 | asRawStatements 45 | ? ` ${exp} ` 46 | : `return ${asParams ? `(${exp}) => {}` : `(${exp})`}` 47 | ) 48 | } catch (e) { 49 | let message = e.message 50 | const keywordMatch = exp 51 | .replace(stripStringRE, '') 52 | .match(prohibitedKeywordRE) 53 | if (keywordMatch) { 54 | message = `avoid using JavaScript keyword as property name: "${ 55 | keywordMatch[0] 56 | }"` 57 | } 58 | context.onError( 59 | createCompilerError( 60 | ErrorCodes.X_INVALID_EXPRESSION, 61 | node.loc, 62 | undefined, 63 | message 64 | ) 65 | ) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /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 -------------------------------------------------------------------------------- /packages/compiler-dom/__tests__/__snapshots__/index.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 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, createVNode: _createVNode, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock } = _Vue 9 | 10 | return (_openBlock(), _createBlock(_Fragment, null, [ 11 | _createVNode(\\"div\\", { 12 | textContent: _toDisplayString(text) 13 | }, null, 8 /* PROPS */, [\\"textContent\\"]), 14 | _createVNode(\\"div\\", { innerHTML: html }, null, 8 /* PROPS */, [\\"innerHTML\\"]), 15 | _createVNode(\\"div\\", null, \\"test\\"), 16 | _createVNode(\\"div\\", { style: {\\"color\\":\\"red\\"} }, \\"red\\"), 17 | _createVNode(\\"div\\", { style: {color: 'green'} }, null, 4 /* STYLE */) 18 | ], 64 /* STABLE_FRAGMENT */)) 19 | } 20 | }" 21 | `; 22 | -------------------------------------------------------------------------------- /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 | // Jest Snapshot v1, https://goo.gl/fbAQLP 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, createVNode: _createVNode, withDirectives: _withDirectives, openBlock: _openBlock, createBlock: _createBlock } = _Vue 9 | 10 | return _withDirectives((_openBlock(), _createBlock(\\"div\\", null, null, 512 /* NEED_PATCH */)), [ 11 | [_vShow, a] 12 | ]) 13 | } 14 | }" 15 | `; 16 | -------------------------------------------------------------------------------- /packages/compiler-dom/__tests__/transforms/ignoreSideEffectTags.spec.ts: -------------------------------------------------------------------------------- 1 | import { compile, CompilerError } 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 | baseParse as parse, 3 | transform, 4 | generate, 5 | CompilerOptions 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 = jest.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/api-extractor.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../api-extractor.json", 3 | "mainEntryPointFilePath": "./dist/packages//src/index.d.ts", 4 | "dtsRollup": { 5 | "publicTrimmedFilePath": "./dist/.d.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /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.0.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 | "sideEffects": false, 15 | "buildOptions": { 16 | "name": "VueCompilerDOM", 17 | "formats": [ 18 | "esm-bundler", 19 | "esm-browser", 20 | "cjs", 21 | "global" 22 | ] 23 | }, 24 | "repository": { 25 | "type": "git", 26 | "url": "git+https://github.com/vuejs/vue-next.git", 27 | "directory": "packages/compiler-dom" 28 | }, 29 | "keywords": [ 30 | "vue" 31 | ], 32 | "author": "Evan You", 33 | "license": "MIT", 34 | "bugs": { 35 | "url": "https://github.com/vuejs/vue-next/issues" 36 | }, 37 | "homepage": "https://github.com/vuejs/vue-next/tree/master/packages/compiler-dom#readme", 38 | "dependencies": { 39 | "@vue/shared": "3.0.2", 40 | "@vue/compiler-core": "3.0.2" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/compiler-dom/src/decodeHtmlBrowser.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-restricted-globals */ 2 | 3 | let decoder: HTMLDivElement 4 | 5 | export function decodeHtmlBrowser(raw: string): string { 6 | ;(decoder || (decoder = document.createElement('div'))).innerHTML = raw 7 | return decoder.textContent as string 8 | } 9 | -------------------------------------------------------------------------------- /packages/compiler-dom/src/runtimeHelpers.ts: -------------------------------------------------------------------------------- 1 | import { registerRuntimeHelpers } from '@vue/compiler-core' 2 | 3 | export const V_MODEL_RADIO = Symbol(__DEV__ ? `vModelRadio` : ``) 4 | export const V_MODEL_CHECKBOX = Symbol(__DEV__ ? `vModelCheckbox` : ``) 5 | export const V_MODEL_TEXT = Symbol(__DEV__ ? `vModelText` : ``) 6 | export const V_MODEL_SELECT = Symbol(__DEV__ ? `vModelSelect` : ``) 7 | export const V_MODEL_DYNAMIC = Symbol(__DEV__ ? `vModelDynamic` : ``) 8 | 9 | export const V_ON_WITH_MODIFIERS = Symbol(__DEV__ ? `vOnModifiersGuard` : ``) 10 | export const V_ON_WITH_KEYS = Symbol(__DEV__ ? `vOnKeysGuard` : ``) 11 | 12 | export const V_SHOW = Symbol(__DEV__ ? `vShow` : ``) 13 | 14 | export const TRANSITION = Symbol(__DEV__ ? `Transition` : ``) 15 | export const TRANSITION_GROUP = Symbol(__DEV__ ? `TransitionGroup` : ``) 16 | 17 | registerRuntimeHelpers({ 18 | [V_MODEL_RADIO]: `vModelRadio`, 19 | [V_MODEL_CHECKBOX]: `vModelCheckbox`, 20 | [V_MODEL_TEXT]: `vModelText`, 21 | [V_MODEL_SELECT]: `vModelSelect`, 22 | [V_MODEL_DYNAMIC]: `vModelDynamic`, 23 | [V_ON_WITH_MODIFIERS]: `withModifiers`, 24 | [V_ON_WITH_KEYS]: `withKeys`, 25 | [V_SHOW]: `vShow`, 26 | [TRANSITION]: `Transition`, 27 | [TRANSITION_GROUP]: `TransitionGroup` 28 | }) 29 | -------------------------------------------------------------------------------- /packages/compiler-dom/src/transforms/ignoreSideEffectTags.ts: -------------------------------------------------------------------------------- 1 | import { NodeTransform, NodeTypes, ElementTypes } 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 | context.onError( 11 | createDOMCompilerError(DOMErrorCodes.X_IGNORED_SIDE_EFFECT_TAG, node.loc) 12 | ) 13 | context.removeNode() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/compiler-dom/src/transforms/transformStyle.ts: -------------------------------------------------------------------------------- 1 | import { 2 | NodeTransform, 3 | NodeTypes, 4 | createSimpleExpression, 5 | SimpleExpressionNode, 6 | SourceLocation 7 | } from '@vue/compiler-core' 8 | import { parseStringStyle } from '@vue/shared' 9 | 10 | // Parse inline CSS strings for static style attributes into an object. 11 | // This is a NodeTransform since it works on the static `style` attribute and 12 | // converts it into a dynamic equivalent: 13 | // style="color: red" -> :style='{ "color": "red" }' 14 | // It is then processed by `transformElement` and included in the generated 15 | // props. 16 | export const transformStyle: NodeTransform = node => { 17 | if (node.type === NodeTypes.ELEMENT) { 18 | node.props.forEach((p, i) => { 19 | if (p.type === NodeTypes.ATTRIBUTE && p.name === 'style' && p.value) { 20 | // replace p with an expression node 21 | node.props[i] = { 22 | type: NodeTypes.DIRECTIVE, 23 | name: `bind`, 24 | arg: createSimpleExpression(`style`, true, p.loc), 25 | exp: parseInlineCSS(p.value.content, p.loc), 26 | modifiers: [], 27 | loc: p.loc 28 | } 29 | } 30 | }) 31 | } 32 | } 33 | 34 | const parseInlineCSS = ( 35 | cssText: string, 36 | loc: SourceLocation 37 | ): SimpleExpressionNode => { 38 | const normalized = parseStringStyle(cssText) 39 | return createSimpleExpression(JSON.stringify(normalized), false, loc, true) 40 | } 41 | -------------------------------------------------------------------------------- /packages/compiler-dom/src/transforms/vHtml.ts: -------------------------------------------------------------------------------- 1 | import { 2 | DirectiveTransform, 3 | createObjectProperty, 4 | createSimpleExpression 5 | } from '@vue/compiler-core' 6 | import { createDOMCompilerError, DOMErrorCodes } 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 { DirectiveTransform } from '@vue/compiler-core' 2 | import { createDOMCompilerError, DOMErrorCodes } 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 | DirectiveTransform, 3 | createObjectProperty, 4 | createSimpleExpression, 5 | TO_DISPLAY_STRING, 6 | createCallExpression 7 | } from '@vue/compiler-core' 8 | import { createDOMCompilerError, DOMErrorCodes } from '../errors' 9 | 10 | export const transformVText: DirectiveTransform = (dir, node, context) => { 11 | const { exp, loc } = dir 12 | if (!exp) { 13 | context.onError( 14 | createDOMCompilerError(DOMErrorCodes.X_V_TEXT_NO_EXPRESSION, loc) 15 | ) 16 | } 17 | if (node.children.length) { 18 | context.onError( 19 | createDOMCompilerError(DOMErrorCodes.X_V_TEXT_WITH_CHILDREN, loc) 20 | ) 21 | node.children.length = 0 22 | } 23 | return { 24 | props: [ 25 | createObjectProperty( 26 | createSimpleExpression(`textContent`, true), 27 | exp 28 | ? createCallExpression( 29 | context.helperString(TO_DISPLAY_STRING), 30 | [exp], 31 | loc 32 | ) 33 | : createSimpleExpression('', true) 34 | ) 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/compiler-dom/src/transforms/warnTransitionChildren.ts: -------------------------------------------------------------------------------- 1 | import { 2 | NodeTransform, 3 | NodeTypes, 4 | ElementTypes, 5 | ComponentNode, 6 | IfBranchNode 7 | } from '@vue/compiler-core' 8 | import { TRANSITION } from '../runtimeHelpers' 9 | import { createDOMCompilerError, DOMErrorCodes } from '../errors' 10 | 11 | export const warnTransitionChildren: NodeTransform = (node, context) => { 12 | if ( 13 | node.type === NodeTypes.ELEMENT && 14 | node.tagType === ElementTypes.COMPONENT 15 | ) { 16 | const component = context.isBuiltInComponent(node.tag) 17 | if (component === TRANSITION) { 18 | return () => { 19 | if (node.children.length && hasMultipleChildren(node)) { 20 | context.onError( 21 | createDOMCompilerError( 22 | DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN, 23 | { 24 | start: node.children[0].loc.start, 25 | end: node.children[node.children.length - 1].loc.end, 26 | source: '' 27 | } 28 | ) 29 | ) 30 | } 31 | } 32 | } 33 | } 34 | } 35 | 36 | function hasMultipleChildren(node: ComponentNode | IfBranchNode): boolean { 37 | // #1352 filter out potential comment nodes. 38 | const children = (node.children = node.children.filter( 39 | c => c.type !== NodeTypes.COMMENT 40 | )) 41 | const child = children[0] 42 | return ( 43 | children.length !== 1 || 44 | child.type === NodeTypes.FOR || 45 | (child.type === NodeTypes.IF && child.branches.some(hasMultipleChildren)) 46 | ) 47 | } 48 | -------------------------------------------------------------------------------- /packages/compiler-sfc/README.md: -------------------------------------------------------------------------------- 1 | # @vue/compiler-sfc 2 | 3 | > Lower level utilities for compiling Vue single file components 4 | 5 | This package contains lower level utilities that you can use if you are writing a plugin / transform for a bundler or module system that compiles Vue single file components into JavaScript. It is used in [vue-loader](https://github.com/vuejs/vue-loader). 6 | 7 | The API surface is intentionally minimal - the goal is to reuse as much as possible while being as flexible as possible. 8 | 9 | ## Browser Build Usage 10 | 11 | This package relies on `postcss`, `postcss-selector-parser` and `postcss-modules` 12 | 13 | ## API 14 | 15 | TODO 16 | -------------------------------------------------------------------------------- /packages/compiler-sfc/__tests__/__snapshots__/compileTemplate.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`source map 1`] = ` 4 | Object { 5 | "mappings": ";;;wBACE,aAA8B;IAAzB,aAAmB,4BAAbA,WAAM", 6 | "names": Array [ 7 | "render", 8 | ], 9 | "sources": Array [ 10 | "example.vue", 11 | ], 12 | "sourcesContent": Array [ 13 | " 14 |

{{ render }}

15 | ", 16 | ], 17 | "version": 3, 18 | } 19 | `; 20 | 21 | exports[`template errors 1`] = ` 22 | Array [ 23 | [SyntaxError: Error parsing JavaScript expression: Unexpected token (1:3)], 24 | [SyntaxError: v-bind is missing expression.], 25 | [SyntaxError: v-model can only be used on , 7 |
8 |
9 | 10 | 29 | 30 | 65 | -------------------------------------------------------------------------------- /packages/vue/examples/composition/commits.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |

Latest Vue.js Commits

5 | 13 |

vuejs/vue@{{ currentBranch }}

14 | 22 |
23 | 24 | 59 | 60 | 76 | -------------------------------------------------------------------------------- /packages/vue/examples/composition/markdown.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 |
8 |
9 | 10 | 28 | 29 | 64 | -------------------------------------------------------------------------------- /packages/vue/examples/composition/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 |
5 |
6 | 7 | 40 | -------------------------------------------------------------------------------- /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/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue", 3 | "version": "3.0.2", 4 | "description": "vue", 5 | "main": "index.js", 6 | "module": "dist/vue.runtime.esm-bundler.js", 7 | "types": "dist/vue.d.ts", 8 | "unpkg": "dist/vue.global.js", 9 | "jsdelivr": "dist/vue.global.js", 10 | "files": [ 11 | "index.js", 12 | "dist" 13 | ], 14 | "buildOptions": { 15 | "name": "Vue", 16 | "formats": [ 17 | "esm-bundler", 18 | "esm-bundler-runtime", 19 | "cjs", 20 | "global", 21 | "global-runtime", 22 | "esm-browser", 23 | "esm-browser-runtime" 24 | ] 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "git+https://github.com/vuejs/vue-next.git" 29 | }, 30 | "keywords": [ 31 | "vue" 32 | ], 33 | "author": "Evan You", 34 | "license": "MIT", 35 | "bugs": { 36 | "url": "https://github.com/vuejs/vue-next/issues" 37 | }, 38 | "homepage": "https://github.com/vuejs/vue-next/tree/master/packages/vue#readme", 39 | "dependencies": { 40 | "@vue/shared": "3.0.2", 41 | "@vue/compiler-dom": "3.0.2", 42 | "@vue/runtime-dom": "3.0.2" 43 | }, 44 | "devDependencies": { 45 | "lodash": "^4.17.15", 46 | "marked": "^0.7.0", 47 | "todomvc-app-css": "^2.3.0" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/vue/src/dev.ts: -------------------------------------------------------------------------------- 1 | import { setDevtoolsHook, initCustomFormatter } from '@vue/runtime-dom' 2 | import { getGlobalThis } from '@vue/shared' 3 | 4 | export function initDev() { 5 | const target = getGlobalThis() 6 | 7 | target.__VUE__ = true 8 | setDevtoolsHook(target.__VUE_DEVTOOLS_GLOBAL_HOOK__) 9 | 10 | if (__BROWSER__) { 11 | console.info( 12 | `You are running a development build of Vue.\n` + 13 | `Make sure to use the production build (*.prod.js) when deploying for production.` 14 | ) 15 | 16 | initCustomFormatter() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /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 | __DEV__ && initDev() 7 | 8 | export * from '@vue/runtime-dom' 9 | 10 | export const compile = () => { 11 | if (__DEV__) { 12 | warn( 13 | `Runtime compilation is not supported in this build of Vue.` + 14 | (__ESM_BUNDLER__ 15 | ? ` Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".` 16 | : __ESM_BROWSER__ 17 | ? ` Use "vue.esm-browser.js" instead.` 18 | : __GLOBAL__ 19 | ? ` Use "vue.global.js" instead.` 20 | : ``) /* should not happen */ 21 | ) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /scripts/checkYarn.js: -------------------------------------------------------------------------------- 1 | if (!/yarn\.js$/.test(process.env.npm_execpath || '')) { 2 | console.warn( 3 | '\u001b[33mThis repository requires Yarn 1.x for scripts to work properly.\u001b[39m\n' 4 | ) 5 | process.exit(1) 6 | } 7 | -------------------------------------------------------------------------------- /scripts/dev.js: -------------------------------------------------------------------------------- 1 | /* 2 | Run Rollup in watch mode for development. 3 | 4 | To specific the package to watch, simply pass its name and the desired build 5 | formats to watch (defaults to "global"): 6 | 7 | ``` 8 | # name supports fuzzy match. will watch all packages with name containing "dom" 9 | yarn dev dom 10 | 11 | # specify the format to output 12 | yarn dev core --formats cjs 13 | 14 | # Can also drop all __DEV__ blocks with: 15 | __DEV__=false yarn dev 16 | ``` 17 | */ 18 | 19 | const execa = require('execa') 20 | const { fuzzyMatchTarget } = require('./utils') 21 | const args = require('minimist')(process.argv.slice(2)) 22 | const target = args._.length ? fuzzyMatchTarget(args._)[0] : 'vue' 23 | const formats = args.formats || args.f 24 | const sourceMap = args.sourcemap || args.s 25 | const commit = execa.sync('git', ['rev-parse', 'HEAD']).stdout.slice(0, 7) 26 | 27 | execa( 28 | 'rollup', 29 | [ 30 | '-wc', 31 | '--environment', 32 | [ 33 | `COMMIT:${commit}`, 34 | `TARGET:${target}`, 35 | `FORMATS:${formats || 'global'}`, 36 | sourceMap ? `SOURCE_MAP:true` : `` 37 | ] 38 | .filter(Boolean) 39 | .join(',') 40 | ], 41 | { 42 | stdio: 'inherit' 43 | } 44 | ) 45 | -------------------------------------------------------------------------------- /scripts/utils.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const chalk = require('chalk') 3 | 4 | const targets = (exports.targets = fs.readdirSync('packages').filter(f => { 5 | if (!fs.statSync(`packages/${f}`).isDirectory()) { 6 | return false 7 | } 8 | const pkg = require(`../packages/${f}/package.json`) 9 | if (pkg.private && !pkg.buildOptions) { 10 | return false 11 | } 12 | return true 13 | })) 14 | 15 | exports.fuzzyMatchTarget = (partialTargets, includeAllMatching) => { 16 | const matched = [] 17 | partialTargets.forEach(partialTarget => { 18 | for (const target of targets) { 19 | if (target.match(partialTarget)) { 20 | matched.push(target) 21 | if (!includeAllMatching) { 22 | break 23 | } 24 | } 25 | } 26 | }) 27 | if (matched.length) { 28 | return matched 29 | } else { 30 | console.log() 31 | console.error( 32 | ` ${chalk.bgRed.white(' ERROR ')} ${chalk.red( 33 | `Target ${chalk.underline(partialTargets)} not found!` 34 | )}` 35 | ) 36 | console.log() 37 | 38 | process.exit(1) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /scripts/verifyCommit.js: -------------------------------------------------------------------------------- 1 | // Invoked on the commit-msg git hook by yorkie. 2 | 3 | const chalk = require('chalk') 4 | const msgPath = process.env.GIT_PARAMS 5 | const msg = require('fs') 6 | .readFileSync(msgPath, 'utf-8') 7 | .trim() 8 | 9 | const commitRE = /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\(.+\))?: .{1,50}/ 10 | 11 | if (!commitRE.test(msg)) { 12 | console.log() 13 | console.error( 14 | ` ${chalk.bgRed.white(' ERROR ')} ${chalk.red( 15 | `invalid commit message format.` 16 | )}\n\n` + 17 | chalk.red( 18 | ` Proper commit message format is required for automated changelog generation. Examples:\n\n` 19 | ) + 20 | ` ${chalk.green(`feat(compiler): add 'comments' option`)}\n` + 21 | ` ${chalk.green( 22 | `fix(v-model): handle events on blur (close #28)` 23 | )}\n\n` + 24 | chalk.red(` See .github/commit-convention.md for more details.\n`) 25 | ) 26 | process.exit(1) 27 | } 28 | -------------------------------------------------------------------------------- /test-dts/README.md: -------------------------------------------------------------------------------- 1 | # Test-ts 2 | 3 | Tests Typescript types to ensure the types remain as expected. 4 | 5 | ## Configuration 6 | 7 | ### tsconfig.json 8 | 9 | Config used to test against the package source 10 | 11 | ### tsconfig.build.json 12 | 13 | Replaces the `vue` and `@vue/*` dependencies with the built Typescript to ensure the published types are correct. 14 | -------------------------------------------------------------------------------- /test-dts/componentTypeExtensions.test-d.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent, expectError, expectType } from './index' 2 | 3 | declare module '@vue/runtime-core' { 4 | interface ComponentCustomOptions { 5 | test?(n: number): void 6 | } 7 | 8 | interface ComponentCustomProperties { 9 | state: 'stopped' | 'running' 10 | } 11 | 12 | interface ComponentCustomProps { 13 | custom?: number 14 | } 15 | } 16 | 17 | export const Custom = defineComponent({ 18 | props: { 19 | bar: String, 20 | baz: { 21 | type: Number, 22 | required: true 23 | } 24 | }, 25 | 26 | data: () => ({ counter: 0 }), 27 | 28 | test(n) { 29 | expectType(n) 30 | }, 31 | 32 | methods: { 33 | aMethod() { 34 | // @ts-expect-error 35 | expectError(this.notExisting) 36 | this.counter++ 37 | this.state = 'running' 38 | // @ts-expect-error 39 | expectError((this.state = 'not valid')) 40 | } 41 | } 42 | }) 43 | 44 | expectType() 45 | expectType() 46 | expectType() 47 | 48 | // @ts-expect-error 49 | expectType() 50 | // @ts-expect-error 51 | expectError() 52 | // @ts-expect-error 53 | expectError() 54 | // @ts-expect-error 55 | expectError() 56 | // @ts-expect-error 57 | expectError() 58 | -------------------------------------------------------------------------------- /test-dts/functionalComponent.test-d.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | FunctionalComponent, 3 | expectError, 4 | expectType, 5 | Component 6 | } from './index' 7 | 8 | // simple function signature 9 | const Foo = (props: { foo: number }) => props.foo 10 | 11 | // TSX 12 | expectType() 13 | expectType() 14 | expectType() 15 | // @ts-expect-error 16 | expectError() 17 | // @ts-expect-error 18 | expectError() 19 | // @ts-expect-error 20 | expectError() 21 | 22 | // Explicit signature with props + emits 23 | const Bar: FunctionalComponent< 24 | { foo: number }, 25 | { update: (value: number) => void } 26 | > = (props, { emit }) => { 27 | expectType(props.foo) 28 | 29 | emit('update', 123) 30 | // @ts-expect-error 31 | expectError(emit('nope')) 32 | // @ts-expect-error 33 | expectError(emit('update')) 34 | // @ts-expect-error 35 | expectError(emit('update', 'nope')) 36 | } 37 | 38 | // assigning runtime options 39 | Bar.props = { 40 | foo: Number 41 | } 42 | // @ts-expect-error 43 | expectError((Bar.props = { foo: String })) 44 | 45 | Bar.emits = { 46 | update: value => value > 1 47 | } 48 | // @ts-expect-error 49 | expectError((Bar.emits = { baz: () => void 0 })) 50 | 51 | // TSX 52 | expectType() 53 | // @ts-expect-error 54 | expectError() 55 | // @ts-expect-error 56 | expectError() 57 | // @ts-expect-error 58 | expectError() 59 | 60 | const Baz: FunctionalComponent<{}, string[]> = (props, { emit }) => { 61 | expectType<{}>(props) 62 | expectType<(event: string) => void>(emit) 63 | } 64 | 65 | expectType(Baz) 66 | 67 | const Qux: FunctionalComponent<{}, ['foo', 'bar']> = (props, { emit }) => { 68 | emit('foo') 69 | emit('foo', 1, 2) 70 | emit('bar') 71 | emit('bar', 1, 2) 72 | } 73 | 74 | expectType(Qux) 75 | -------------------------------------------------------------------------------- /test-dts/index.d.ts: -------------------------------------------------------------------------------- 1 | // This directory contains a number of d.ts assertions using tsd: 2 | // https://github.com/SamVerschueren/tsd 3 | // The tests checks type errors and will probably show up red in VSCode, and 4 | // it's intended. We cannot use directives like @ts-ignore or @ts-nocheck since 5 | // that would suppress the errors that should be caught. 6 | 7 | export * from '@vue/runtime-dom' 8 | 9 | export function describe(_name: string, _fn: () => void): void 10 | 11 | export function expectType(value: T): void 12 | export function expectError(value: T): void 13 | export function expectAssignable(value: T2): void 14 | -------------------------------------------------------------------------------- /test-dts/inject.test-d.ts: -------------------------------------------------------------------------------- 1 | import { provide, inject, InjectionKey, expectType } from './index' 2 | 3 | const key: InjectionKey = Symbol() 4 | 5 | provide(key, 1) 6 | // @ts-expect-error 7 | provide(key, 'foo') 8 | 9 | expectType(inject(key)) 10 | expectType(inject(key, 1)) 11 | expectType(inject(key, () => 1, true /* treatDefaultAsFactory */)) 12 | 13 | expectType<() => number>(inject('foo', () => 1)) 14 | expectType<() => number>(inject('foo', () => 1, false)) 15 | expectType(inject('foo', () => 1, true)) 16 | -------------------------------------------------------------------------------- /test-dts/reactivity.test-d.ts: -------------------------------------------------------------------------------- 1 | import { readonly, describe, expectError } from './index' 2 | 3 | describe('should support DeepReadonly', () => { 4 | const r = readonly({ obj: { k: 'v' } }) 5 | // @ts-expect-error 6 | expectError((r.obj = {})) 7 | // @ts-expect-error 8 | expectError((r.obj.k = 'x')) 9 | }) 10 | -------------------------------------------------------------------------------- /test-dts/tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": false, 5 | "paths": { 6 | "@vue/*": ["../packages/*/dist"], 7 | "vue": ["../packages/vue/dist"] 8 | } 9 | }, 10 | "exclude": ["../packages/*/__tests__", "../packages/*/src"], 11 | "include": [ 12 | "../packages/global.d.ts", 13 | "../packages/*/dist", 14 | "../packages/runtime-dom/types/jsx.d.ts", 15 | "../packages/*/__tests__", 16 | "../test-dts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /test-dts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true, 5 | "declaration": true 6 | }, 7 | "exclude": ["../packages/*/__tests__"] 8 | } 9 | -------------------------------------------------------------------------------- /test-dts/tsx.test-d.tsx: -------------------------------------------------------------------------------- 1 | // TSX w/ defineComponent is tested in defineComponent.test-d.tsx 2 | import { 3 | KeepAlive, 4 | Suspense, 5 | Fragment, 6 | Teleport, 7 | expectError, 8 | expectType 9 | } from './index' 10 | 11 | expectType(
) 12 | expectType(
) 13 | expectType() 14 | 15 | // @ts-expect-error unknown prop 16 | expectError(
) 17 | 18 | // allow key/ref on arbitrary element 19 | expectType(
) 20 | expectType(
) 21 | 22 | expectType( 23 | { 25 | // infer correct event type 26 | expectType(e.target) 27 | }} 28 | /> 29 | ) 30 | 31 | // built-in types 32 | expectType() 33 | expectType() 34 | 35 | expectType() 36 | expectType() 37 | 38 | // @ts-expect-error 39 | expectError() 40 | // @ts-expect-error 41 | expectError() 42 | 43 | // KeepAlive 44 | expectType() 45 | expectType() 46 | // @ts-expect-error 47 | expectError() 48 | 49 | // Suspense 50 | expectType() 51 | expectType() 52 | expectType( 53 | {}} onFallback={() => {}} onPending={() => {}} /> 54 | ) 55 | // @ts-expect-error 56 | expectError() 57 | -------------------------------------------------------------------------------- /test-dts/watch.test-d.ts: -------------------------------------------------------------------------------- 1 | import { ref, computed, watch, expectType } from './index' 2 | 3 | const source = ref('foo') 4 | const source2 = computed(() => source.value) 5 | const source3 = () => 1 6 | 7 | // lazy watcher will have consistent types for oldValue. 8 | watch(source, (value, oldValue) => { 9 | expectType(value) 10 | expectType(oldValue) 11 | }) 12 | 13 | watch([source, source2, source3], (values, oldValues) => { 14 | expectType<(string | number)[]>(values) 15 | expectType<(string | number)[]>(oldValues) 16 | }) 17 | 18 | // const array 19 | watch([source, source2, source3] as const, (values, oldValues) => { 20 | expectType>(values) 21 | expectType>(oldValues) 22 | }) 23 | 24 | // immediate watcher's oldValue will be undefined on first run. 25 | watch( 26 | source, 27 | (value, oldValue) => { 28 | expectType(value) 29 | expectType(oldValue) 30 | }, 31 | { immediate: true } 32 | ) 33 | 34 | watch( 35 | [source, source2, source3], 36 | (values, oldValues) => { 37 | expectType<(string | number)[]>(values) 38 | expectType<(string | number | undefined)[]>(oldValues) 39 | }, 40 | { immediate: true } 41 | ) 42 | 43 | // const array 44 | watch( 45 | [source, source2, source3] as const, 46 | (values, oldValues) => { 47 | expectType>(values) 48 | expectType< 49 | Readonly<[string | undefined, string | undefined, number | undefined]> 50 | >(oldValues) 51 | }, 52 | { immediate: true } 53 | ) 54 | 55 | // should provide correct ref.value inner type to callbacks 56 | const nestedRefSource = ref({ 57 | foo: ref(1) 58 | }) 59 | 60 | watch(nestedRefSource, (v, ov) => { 61 | expectType<{ foo: number }>(v) 62 | expectType<{ foo: number }>(ov) 63 | }) 64 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "outDir": "dist", 5 | "sourceMap": false, 6 | "target": "esnext", 7 | "module": "esnext", 8 | "moduleResolution": "node", 9 | "allowJs": false, 10 | "strict": true, 11 | "noUnusedLocals": true, 12 | "experimentalDecorators": true, 13 | "resolveJsonModule": true, 14 | "esModuleInterop": true, 15 | "removeComments": false, 16 | "jsx": "preserve", 17 | "lib": ["esnext", "dom"], 18 | "types": ["jest", "puppeteer", "node"], 19 | "rootDir": ".", 20 | "paths": { 21 | "@vue/*": ["packages/*/src"], 22 | "vue": ["packages/vue/src"] 23 | } 24 | }, 25 | "include": [ 26 | "packages/global.d.ts", 27 | "packages/*/src", 28 | "packages/runtime-dom/types/jsx.d.ts", 29 | "packages/*/__tests__", 30 | "test-dts" 31 | ] 32 | } 33 | --------------------------------------------------------------------------------