diff --git a/.eslintrc.js b/.eslintrc.js index 4c667f90216..8485d76f53e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,7 +6,9 @@ module.exports = { parserOptions: { sourceType: 'module' }, + plugins: ["jest"], rules: { + 'no-debugger': 'error', 'no-unused-vars': [ 'error', // we are only using this rule to check for unused arguments since TS @@ -16,10 +18,11 @@ module.exports = { // most of the codebase are expected to be env agnostic 'no-restricted-globals': ['error', ...DOMGlobals, ...NodeGlobals], // since we target ES2015 for baseline support, we need to forbid object - // rest spread usage (both assign and destructure) + // rest spread usage in destructure as it compiles into a verbose helper. + // TS now compiles assignment spread into Object.assign() calls so that + // is allowed. 'no-restricted-syntax': [ 'error', - 'ObjectExpression > SpreadElement', 'ObjectPattern > RestElement', 'AwaitExpression' ] @@ -30,7 +33,9 @@ module.exports = { files: ['**/__tests__/**', 'test-dts/**'], rules: { 'no-restricted-globals': 'off', - 'no-restricted-syntax': 'off' + 'no-restricted-syntax': 'off', + 'jest/no-disabled-tests': 'error', + 'jest/no-focused-tests': 'error' } }, // shared, may be used in any env diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000000..fa5f6cc1039 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,68 @@ +name: "\U0001F41E Bug report" +description: Create a report to help us improve +body: + - type: markdown + attributes: + value: | + **Before You Start...** + + This form is only for submitting bug reports. If you have a usage question + or are unsure if this is really a bug, make sure to: + + - Read the [docs](https://vuejs.org/) + - Ask on [Discord Chat](https://chat.vuejs.org/) + - Ask on [GitHub Discussions](https://github.com/vuejs/core/discussions) + - Look for / ask questions on [Stack Overflow](https://stackoverflow.com/questions/ask?tags=vue.js) + + Also try to search for your issue - it may have already been answered or even fixed in the development branch. + However, if you find that an old, closed issue still persists in the latest version, + you should open a new issue using the form below instead of commenting on the old issue. + - type: input + id: reproduction-link + attributes: + label: Link to minimal reproduction + description: | + The easiest way to provide a reproduction is by showing the bug in [The SFC Playground](https://sfc.vuejs.org/). + If it cannot be reproduced in the playground and requires a proper build setup, try [StackBlitz](https://vite.new/vue). + If neither of these are suitable, you can always provide a GitHub reporistory. + + The reproduction should be **minimal** - i.e. it should contain only the bare minimum amount of code needed + to show the bug. See [Bug Reproduction Guidelines](https://github.com/vuejs/core/blob/main/.github/bug-repro-guidelines.md) for more details. + + Please do not just fill in a random link. The issue will be closed if no valid reproduction is provided. + placeholder: Reproduction Link + validations: + required: true + - type: textarea + id: steps-to-reproduce + attributes: + label: Steps to reproduce + description: | + What do we need to do after opening your repro in order to make the bug happen? Clear and concise reproduction instructions are important for us to be able to triage your issue in a timely manner. Note that you can use [Markdown](https://guides.github.com/features/mastering-markdown/) to format lists and code. + placeholder: Steps to reproduce + validations: + required: true + - type: textarea + id: expected + attributes: + label: What is expected? + validations: + required: true + - type: textarea + id: actually-happening + attributes: + label: What is actually happening? + validations: + required: true + - type: textarea + id: system-info + attributes: + label: System Info + description: Output of `npx envinfo --system --npmPackages vue --binaries --browsers` + render: shell + placeholder: System, Binaries, Browsers + - type: textarea + id: additional-comments + attributes: + label: Any additional comments? + description: e.g. some background/context of how you ran into this bug. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index d331b5312a9..af3782c8422 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,11 @@ blank_issues_enabled: false contact_links: - - name: Create new issue - url: https://new-issue.vuejs.org/?repo=vuejs/core - about: Please use the following link to create a new issue. + - name: Discord Chat + url: https://chat.vuejs.org + about: Ask questions and discuss with other Vue users in real time. + - name: Questions & Discussions + url: https://github.com/vuejs/core/discussions + about: Use GitHub discussions for message-board style questions and discussions. - name: Patreon url: https://www.patreon.com/evanyou about: Love Vue.js? Please consider supporting us via Patreon. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000000..9165eb4d291 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,39 @@ +name: "\U0001F680 New feature proposal" +description: Suggest an idea for this project +labels: [":sparkles: feature request"] +body: + - type: markdown + attributes: + value: | + **Before You Start...** + + This form is only for submitting feature requests. If you have a usage question + or are unsure if this is really a bug, make sure to: + + - Read the [docs](https://vuejs.org/) + - Ask on [Discord Chat](https://chat.vuejs.org/) + - Ask on [GitHub Discussions](https://github.com/vuejs/core/discussions) + - Look for / ask questions on [Stack Overflow](https://stackoverflow.com/questions/ask?tags=vue.js) + + Also try to search for your issue - another user may have already requested something similar! + + - type: textarea + id: problem-description + attributes: + label: What problem does this feature solve? + description: | + Explain your use case, context, and rationale behind this feature request. More importantly, what is the **end user experience** you are trying to build that led to the need for this feature? + + An important design goal of Vue is keeping the API surface small and straightforward. In general, we only consider adding new features that solve a problem that cannot be easily dealt with using existing APIs (i.e. not just an alternative way of doing things that can already be done). The problem should also be common enough to justify the addition. + placeholder: Problem description + validations: + required: true + - type: textarea + id: proposed-API + attributes: + label: What does the proposed API look like? + description: | + Describe how you propose to solve the problem and provide code samples of how the API would work once implemented. Note that you can use [Markdown](https://guides.github.com/features/mastering-markdown/) to format your code blocks. + placeholder: Steps to reproduce + validations: + required: true diff --git a/.github/bug-repro-guidelines.md b/.github/bug-repro-guidelines.md new file mode 100644 index 00000000000..19e9a7e2f26 --- /dev/null +++ b/.github/bug-repro-guidelines.md @@ -0,0 +1,29 @@ +## About Bug Reproductions + +A bug reproduction is a piece of code that can run and demonstrate how a bug can happen. + +### Text is not enough + +It's impossible to fix a bug from mere text descriptions. First, it's very difficult to precisely describe a technical problem while keeping it easy to follow; Second, the real cause may very well be something that you forgot to even mention. A reproduction is the only way that can reliably help us understand what is going on, so please provide one. + +### A repro must be runnable + +Screenshots or videos are NOT reproductions! They only show that the bug exists, but do not provide enough information on why it happens. Only runnable code provides the most complete context and allows us to properly debug the scenario. That said, in some cases videos/gifs can help explain interaction issues that are hard to describe in text. + +### A repro should be minimal + +Some users would give us a link to a real project and hope we can help them figure out what is wrong. We generally do not accept such requests because: + +You are already familiar with your codebase, but we are not. It is extremely time-consuming to hunt a bug in a big and unfamiliar codebase. + +The problematic behavior may very well be caused by your code rather than by a bug in Vue. + +A minimal reproduction means it demonstrates the bug, and the bug only. It should only contain the bare minimum amount of code that can reliably cause the bug. Try your best to get rid of anything that aren't directly related to the problem. + +### How to create a repro + +For Vue 3 core reproductions, try reproducing it in [The SFC Playground](https://sfc.vuejs.org/). + +If it cannot be reproduced in the playground and requires a proper build setup, try [StackBlitz](https://vite.new/vue). + +If neither of these are suitable, you can always provide a GitHub repository. diff --git a/.github/contributing.md b/.github/contributing.md index 33395947855..5f4e64b7e1e 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -17,7 +17,9 @@ Hi! I'm really excited that you are interested in contributing to Vue.js. Before ## Pull Request Guidelines -- Checkout a topic branch from a base branch, e.g. `master`, and merge back against that branch. +- Checkout a topic branch from a base branch, e.g. `main`, and merge back against that branch. + +- [Make sure to tick the "Allow edits from maintainers" box](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork). This allows us to directly make minor edits / refactors and saves a lot of time. - If adding a new feature: @@ -40,7 +42,7 @@ Hi! I'm really excited that you are interested in contributing to Vue.js. Before ## Development Setup -You will need [Node.js](https://nodejs.org) **version 16+**, and [PNPM](https://pnpm.io). +You will need [Node.js](https://nodejs.org) **version 16+**, and [PNPM](https://pnpm.io) **version 7+**. We also recommend installing [ni](https://github.com/antfu/ni) to help switching between repos using different package managers. `ni` also provides the handy `nr` command which running npm scripts easier. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index af713d27a13..206deefc560 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -62,3 +62,9 @@ updates: - dependency-name: node-notifier versions: - 8.0.1 +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: monthly + open-pull-requests-limit: 10 + versioning-strategy: lockfile-only diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e02bfc6627..eadcd94f6d8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,15 +7,13 @@ on: branches: - main jobs: - test: + unit-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install pnpm - uses: pnpm/action-setup@v2.0.1 - with: - version: 6.15.1 + uses: pnpm/action-setup@v2 - name: Set node version to 16 uses: actions/setup-node@v2 @@ -26,17 +24,34 @@ jobs: - run: pnpm install - name: Run unit tests - run: pnpm run test + run: pnpm run test-unit - test-dts: + e2e-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install pnpm - uses: pnpm/action-setup@v2.0.1 + uses: pnpm/action-setup@v2 + + - name: Set node version to 16 + uses: actions/setup-node@v2 with: - version: 6.15.1 + node-version: 16 + cache: 'pnpm' + + - run: pnpm install + + - name: Run e2e tests + run: pnpm run test-e2e + + lint-and-test-dts: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Install pnpm + uses: pnpm/action-setup@v2 - name: Set node version to 16 uses: actions/setup-node@v2 @@ -46,6 +61,9 @@ jobs: - run: pnpm install + - name: Run eslint + run: pnpm run lint + - name: Run type declaration tests run: pnpm run test-dts @@ -57,9 +75,7 @@ jobs: - uses: actions/checkout@v2 - name: Install pnpm - uses: pnpm/action-setup@v2.0.1 - with: - version: 6.15.1 + uses: pnpm/action-setup@v2 - name: Set node version to 16 uses: actions/setup-node@v2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ad5a8f24e4..87df134826b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,96 @@ +## [3.2.34](https://github.com/vuejs/core/compare/v3.2.34-beta.1...v3.2.34) (2022-05-19) + + +### Bug Fixes + +* **compiler-core:** should generate HYDRATE_EVENTS flag on dynamic component that resolves to element ([415091b](https://github.com/vuejs/core/commit/415091b0ee2de66e622145028f00523f2032ce77)), closes [#5870](https://github.com/vuejs/core/issues/5870) +* **compiler-sfc:** support `export { default } from '...'` ([#5937](https://github.com/vuejs/core/issues/5937)) ([73e6523](https://github.com/vuejs/core/commit/73e6523134a013f9e369f53f213a214497ac7c40)), closes [#5935](https://github.com/vuejs/core/issues/5935) +* **compiler-sfc:** type-only defineProps does not recognize Promise (fix [#5941](https://github.com/vuejs/core/issues/5941)) ([#5943](https://github.com/vuejs/core/issues/5943)) ([991d623](https://github.com/vuejs/core/commit/991d62322fa67d50b7ae8b0460f294d6b39f9711)) +* **compiler-ssr:** fix component event handlers inheritance in ssr ([f811dc2](https://github.com/vuejs/core/commit/f811dc2b60ba7efdbb9b1ab330dcbc18c1cc9a75)), closes [#5664](https://github.com/vuejs/core/issues/5664) +* **compiler-ssr:** fix wrong attrs fallthrough on non-single-root v-if branches ([516bc54](https://github.com/vuejs/core/commit/516bc548fce295f6d564c7fb371c8067ead7cd71)), closes [#5140](https://github.com/vuejs/core/issues/5140) +* **compiler-ssr:** only inject fallthrough attrs for root transition/keep-alive ([c65b805](https://github.com/vuejs/core/commit/c65b805ef1f9b164fb8aaa7bc679a91248b5891a)) +* **keep-alive:** fix keep-alive rendering when placed in vnode branch ([0841b9b](https://github.com/vuejs/core/commit/0841b9b5243acdaf191099b25e9a145b30189dea)), closes [#4817](https://github.com/vuejs/core/issues/4817) +* **runtime-core:** adjust force diff of dev root fragments ([cdda49b](https://github.com/vuejs/core/commit/cdda49bbfb1939c9cf812d624992ea7bdae74c78)), closes [#5946](https://github.com/vuejs/core/issues/5946) +* **ssr/teleport:** support nested teleports in ssr ([595263c](https://github.com/vuejs/core/commit/595263c0e9f5728c3650c6526dbed27cda9ba114)), closes [#5242](https://github.com/vuejs/core/issues/5242) +* **ssr:** fix hydration error on falsy v-if inside transition/keep-alive ([ee4186e](https://github.com/vuejs/core/commit/ee4186ef9ebbc45827b208f6f5b648dbf4337d1d)), closes [#5352](https://github.com/vuejs/core/issues/5352) +* **ssr:** fix hydration error when teleport is used as component root ([b60cff0](https://github.com/vuejs/core/commit/b60cff052c880b2965d06007f0ec4d0349ab47c0)), closes [#4293](https://github.com/vuejs/core/issues/4293) +* **ssr:** fix hydration error when transition contains comment children ([3705b3b](https://github.com/vuejs/core/commit/3705b3b46aa8f3e929014f564f8afa4a663e6375)), closes [#5351](https://github.com/vuejs/core/issues/5351) +* **ssr:** fix hydration for slot with empty text node ([939209c](https://github.com/vuejs/core/commit/939209c6b554aed6634d9cf2ca10a2aa46ba7673)), closes [#5728](https://github.com/vuejs/core/issues/5728) +* **ssr:** fix hydration mismatch caused by multi-line comments inside slot ([e1bc268](https://github.com/vuejs/core/commit/e1bc2681ef64aed7975ad38950a478ae53c1abad)), closes [#5355](https://github.com/vuejs/core/issues/5355) +* **ssr:** inherit scope id on functional component during ssr ([847d7f7](https://github.com/vuejs/core/commit/847d7f782bb6074c6b31378e07d94cb41ad30bd2)), closes [#5817](https://github.com/vuejs/core/issues/5817) +* **ssr:** render fallthrough attributes for transition-group with tag ([aed10c5](https://github.com/vuejs/core/commit/aed10c507279900f8afc4861dc01ca4f2b95acb8)), closes [#5141](https://github.com/vuejs/core/issues/5141) +* **ssr:** support client-compiled v-model with dynamic type during ssr ([#5787](https://github.com/vuejs/core/issues/5787)) ([c03459b](https://github.com/vuejs/core/commit/c03459b9b6d3c18450235bc4074a603677996320)), closes [#5786](https://github.com/vuejs/core/issues/5786) +* **types:** export ComponentProvideOptions ([#5947](https://github.com/vuejs/core/issues/5947)) ([3e2850f](https://github.com/vuejs/core/commit/3e2850fa6c628284b4a1ab5deba3b11f1d2f66b6)) +* **types:** fix `defineComponent` inference to `Component` ([#5949](https://github.com/vuejs/core/issues/5949)) ([7c8f457](https://github.com/vuejs/core/commit/7c8f4578e9e7178e326cf8e343f7a8b4143ba63b)) + + + +## [3.2.34-beta.1](https://github.com/vuejs/core/compare/v3.2.33...v3.2.34-beta.1) (2022-05-17) + + +### Bug Fixes + +* **compiler-core:** normalize v-bind:style with array literal value ([0f00cf4](https://github.com/vuejs/core/commit/0f00cf43cf5eaeeee7f12d523a5f4936f7dc0a84)), closes [#5106](https://github.com/vuejs/core/issues/5106) +* **compiler-core:** template v-if should never be treated as dev root fragment ([51f3d38](https://github.com/vuejs/core/commit/51f3d386de7f5fcec6eb4c1c223ba824be036648)), closes [#5189](https://github.com/vuejs/core/issues/5189) +* **compiler-dom:** properly stringify v-html/v-text with constant value ([6283b2e](https://github.com/vuejs/core/commit/6283b2ec413b78fe88775d249d3598cdce977b7a)), closes [#5439](https://github.com/vuejs/core/issues/5439) [#5445](https://github.com/vuejs/core/issues/5445) +* **compiler-sfc:** ` + + `) + assertCode(content) + }) + describe(' + + `) + expect(content).toMatch(`return { a, b, Baz }`) + assertCode(content) + }) }) describe('inlineTemplate mode', () => { @@ -502,6 +529,7 @@ defineExpose({ foo: 123 }) import { ref } from 'vue' import Foo, { bar } from './Foo.vue' import other from './util' + import * as tree from './tree' const count = ref(0) const constant = {} const maybe = foo() @@ -511,6 +539,7 @@ defineExpose({ foo: 123 }) `, { inlineTemplate: true } @@ -529,6 +558,8 @@ defineExpose({ foo: 123 }) expect(content).toMatch(`unref(maybe)`) // should unref() on let bindings expect(content).toMatch(`unref(lett)`) + // no need to unref namespace import (this also preserves tree-shaking) + expect(content).toMatch(`tree.foo()`) // no need to unref function declarations expect(content).toMatch(`{ onClick: fn }`) // no need to mark constant fns in patch flag @@ -695,6 +726,8 @@ defineExpose({ foo: 123 }) expect(content).toMatch(`\n __ssrInlineRender: true,\n`) expect(content).toMatch(`return (_ctx, _push`) expect(content).toMatch(`ssrInterpolate`) + expect(content).not.toMatch(`useCssVars`) + expect(content).toMatch(`"--${mockId}-count": (count.value)`) assertCode(content) }) }) @@ -1164,6 +1197,59 @@ const emit = defineEmits(['a', 'b']) assertAwaitDetection(`if (ok) { await foo } else { await bar }`) }) + test('multiple `if` nested statements', () => { + assertAwaitDetection(`if (ok) { + let a = 'foo' + await 0 + await 1 + await 2 + } else if (a) { + await 10 + if (b) { + await 0 + await 1 + } else { + let a = 'foo' + await 2 + } + if (b) { + await 3 + await 4 + } + } else { + await 5 + }`) + }) + + test('multiple `if while` nested statements', () => { + assertAwaitDetection(`if (ok) { + while (d) { + await 5 + } + while (d) { + await 5 + await 6 + if (c) { + let f = 10 + 10 + await 7 + } else { + await 8 + await 9 + } + } + }`) + }) + + test('multiple `if for` nested statements', () => { + assertAwaitDetection(`if (ok) { + for (let a of [1,2,3]) { + await a + } + for (let a of [1,2,3]) { + await a + await a + } + }`) + }) + test('should ignore await inside functions', () => { // function declaration assertAwaitDetection(`async function foo() { await bar }`, false) @@ -1550,4 +1636,59 @@ describe('SFC analyze + `, + undefined, + { + filename: 'FooBar.vue' + } + ) + expect(content).toMatch(`export default { + name: 'FooBar'`) + assertCode(content) + }) + + test('do not overwrite manual name (object)', () => { + const { content } = compile( + ` + + `, + undefined, + { + filename: 'FooBar.vue' + } + ) + expect(content).not.toMatch(`name: 'FooBar'`) + expect(content).toMatch(`name: 'Baz'`) + assertCode(content) + }) + + test('do not overwrite manual name (call)', () => { + const { content } = compile( + ` + + `, + undefined, + { + filename: 'FooBar.vue' + } + ) + expect(content).not.toMatch(`name: 'FooBar'`) + expect(content).toMatch(`name: 'Baz'`) + assertCode(content) + }) + }) }) diff --git a/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts b/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts index 140dbec2e6b..25fb4bed280 100644 --- a/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts @@ -59,7 +59,7 @@ describe('sfc props transform', () => { // function expect(content).toMatch(`props: _mergeDefaults(['foo', 'bar'], { foo: 1, - bar: () => {} + bar: () => ({}) })`) assertCode(content) }) @@ -74,7 +74,7 @@ describe('sfc props transform', () => { // function expect(content).toMatch(`props: { foo: { type: Number, required: false, default: 1 }, - bar: { type: Object, required: false, default: () => {} } + bar: { type: Object, required: false, default: () => ({}) } }`) assertCode(content) }) @@ -92,11 +92,11 @@ describe('sfc props transform', () => { // function expect(content).toMatch(`props: { foo: { default: 1 }, - bar: { default: () => {} }, + bar: { default: () => ({}) }, baz: null, boola: { type: Boolean }, boolb: { type: [Boolean, Number] }, - func: { type: Function, default: () => () => {} } + func: { type: Function, default: () => (() => {}) } }`) assertCode(content) }) @@ -127,6 +127,28 @@ describe('sfc props transform', () => { }) }) + // #5425 + test('non-identifier prop names', () => { + const { content, bindings } = compile(` + + + `) + expect(content).toMatch(`x = __props["foo.bar"]`) + expect(content).toMatch(`toDisplayString(__props["foo.bar"])`) + assertCode(content) + expect(bindings).toStrictEqual({ + x: BindingTypes.SETUP_LET, + 'foo.bar': BindingTypes.PROPS, + fooBar: BindingTypes.PROPS_ALIASED, + __propsAliases: { + fooBar: 'foo.bar' + } + }) + }) + test('rest spread', () => { const { content, bindings } = compile(` -

vuejs/vue@{{ currentBranch }}

+

vuejs/core@{{ currentBranch }}