diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index ea44a0001..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,69 +0,0 @@ -const DOMGlobals = ['window', 'document'] -const NodeGlobals = ['module', 'require'] - -module.exports = { - parser: '@typescript-eslint/parser', - parserOptions: { - sourceType: 'module' - }, - rules: { - 'no-unused-vars': [ - 'error', - // we are only using this rule to check for unused arguments since TS - // catches unused variables but not args. - { varsIgnorePattern: '.*', args: 'none' } - ], - // 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) - 'no-restricted-syntax': [ - 'error', - 'ObjectExpression > SpreadElement', - 'ObjectPattern > RestElement', - 'AwaitExpression' - ] - }, - overrides: [ - // tests, no restrictions (runs in Node / jest with jsdom) - { - files: ['**/__tests__/**', 'test-dts/**'], - rules: { - 'no-restricted-globals': 'off', - 'no-restricted-syntax': 'off' - } - }, - // shared, may be used in any env - { - files: ['packages/shared/**'], - rules: { - 'no-restricted-globals': 'off' - } - }, - // Packages targeting DOM - { - files: ['packages/{vue,vue-compat,runtime-dom}/**'], - rules: { - 'no-restricted-globals': ['error', ...NodeGlobals] - } - }, - // Packages targeting Node - { - files: [ - 'packages/{compiler-sfc,compiler-ssr,server-renderer,ref-transform}/**' - ], - rules: { - 'no-restricted-globals': ['error', ...DOMGlobals], - 'no-restricted-syntax': 'off' - } - }, - // Private package, browser only + no syntax restrictions - { - files: ['packages/template-explorer/**', 'packages/sfc-playground/**'], - rules: { - 'no-restricted-globals': ['error', ...NodeGlobals], - 'no-restricted-syntax': 'off' - } - } - ] -} diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000..d06b03a3f --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# update prettier & eslint config (#9162) +bfe6b459d3a0ce6168611ee1ac7e6e789709df9d diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 4a8f6fd42..9288efdb9 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,3 +1,2 @@ -open_collective: vuejs -patreon: evanyou github: yyx990803 +open_collective: vuejs diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000..95e0ca79c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,74 @@ +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: version + attributes: + label: Vue version + validations: + required: true + - 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://play.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. + + 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 ac8a00ef1..02f99c6bf 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,14 @@ blank_issues_enabled: false contact_links: - - name: Create new issue - url: https://new-issue.vuejs.org/?repo=vuejs/vue-next - about: Please use the following link to create a new issue. + - name: Feature Request + url: https://github.com/vuejs/rfcs/discussions + about: Suggest new features for consideration + - 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/bug-repro-guidelines.md b/.github/bug-repro-guidelines.md new file mode 100644 index 000000000..90458b307 --- /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://play.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/commit-convention.md b/.github/commit-convention.md index a8522fa21..11a64576a 100644 --- a/.github/commit-convention.md +++ b/.github/commit-convention.md @@ -6,7 +6,7 @@ Messages must be matched by the following regex: -``` js +```regexp /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip)(\(.+\))?: .{1,50}/ ``` @@ -44,7 +44,7 @@ This reverts commit 667ecc1654a317a13331b17617d973392f415f02. ### Full Message Format -A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**: +A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**: ``` (): @@ -74,9 +74,9 @@ The scope could be anything specifying the place of the commit change. For examp The subject contains a succinct description of the change: -* use the imperative, present tense: "change" not "changed" nor "changes" -* don't capitalize the first letter -* no dot (.) at the end +- use the imperative, present tense: "change" not "changed" nor "changes" +- don't capitalize the first letter +- no dot (.) at the end ### Body diff --git a/.github/contributing.md b/.github/contributing.md index 5c50f8a96..2554582b8 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -2,7 +2,7 @@ Hi! I'm really excited that you are interested in contributing to Vue.js. Before submitting your contribution, please make sure to take a moment and read through the following guidelines: -- [Code of Conduct](https://github.com/vuejs/vue/blob/dev/.github/CODE_OF_CONDUCT.md) +- [Code of Conduct](https://vuejs.org/about/coc.html) - [Issue Reporting Guidelines](#issue-reporting-guidelines) - [Pull Request Guidelines](#pull-request-guidelines) - [Development Setup](#development-setup) @@ -17,7 +17,33 @@ 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. +### What kinds of Pull Requests are accepted? + +- Bug fix that addresses a clearly identified bug. **"Clearly identified bug"** means the bug has a proper reproduction either from a related open issue, or is included in the PR itself. Avoid submitting PRs that claim to fix something but do not sufficiently explain what is being fixed. + +- New feature that addresses a clearly explained and widely applicable use case. **"Widely applicable"** means the new feature should provide non-trivial improvements to the majority of the user base. Vue already has a large API surface so we are quite cautious about adding new features - if the use case is niche and can be addressed via userland implementations, it likely isn't suitable to go into core. + + The feature implementation should also consider the trade-off between the added complexity vs. the benefits gained. For example, if a small feature requires significant changes that spreads across the codebase, it is likely not worth it, or the approach should be reconsidered. + + If the feature has a non-trivial API surface addition, or significantly affects the way a common use case is approached by the users, it should go through a discussion first in the [RFC repo](https://github.com/vuejs/rfcs/discussions). PRs of such features without prior discussion make it really difficult to steer / adjust the API design due to coupling with concrete implementations, and can lead to wasted work. + +- Chore: typos, comment improvements, build config, CI config, etc. For typos and comment changes, try to combine multiple of them into a single PR. + +- **It should be noted that we discourage contributors from submitting code refactors that are largely stylistic.** Code refactors are only accepted if it improves performance, or comes with sufficient explanations on why it objectively improves the code quality (e.g. makes a related feature implementation easier). + + The reason is that code readability is subjective. The maintainers of this project have chosen to write the code in its current style based on our preferences, and we do not want to spend time explaining our stylistic preferences. Contributors should just respect the established conventions when contributing code. + + Another aspect of it is that large scale stylistic changes result in massive diffs that touch multiple files, adding noise to the git history and makes tracing behavior changes across commits more cumbersome. + +### Pull Request Checklist + +- Vue core has two primary work branches: `main` and `minor`. + + - If your pull request is a feature that adds new API surface, it should be submitted against the `minor` branch. + + - Otherwise, it should be submitted against the `main` 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: @@ -28,21 +54,36 @@ Hi! I'm really excited that you are interested in contributing to Vue.js. Before - If you are resolving a special issue, add `(fix #xxxx[,#xxxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `update entities encoding/decoding (fix #3899)`. - Provide a detailed description of the bug in the PR. Live demo preferred. - - Add appropriate test coverage if applicable. You can check the coverage of your code addition by running `npm test -- --coverage`. + - Add appropriate test coverage if applicable. You can check the coverage of your code addition by running `nr test-coverage`. - It's OK to have multiple small commits as you work on the PR - GitHub can automatically squash them before merging. - Make sure tests pass! -- Commit messages must follow the [commit message convention](./commit-convention.md) so that changelogs can be automatically generated. Commit messages are automatically validated before commit (by invoking [Git Hooks](https://git-scm.com/docs/githooks) via [yorkie](https://github.com/yyx990803/yorkie)). +- Commit messages must follow the [commit message convention](./commit-convention.md) so that changelogs can be automatically generated. Commit messages are automatically validated before commit (by invoking [Git Hooks](https://git-scm.com/docs/githooks) via [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks)). -- No need to worry about code style as long as you have installed the dev dependencies - modified files are automatically formatted with Prettier on commit (by invoking [Git Hooks](https://git-scm.com/docs/githooks) via [yorkie](https://github.com/yyx990803/yorkie)). +- No need to worry about code style as long as you have installed the dev dependencies - modified files are automatically formatted with Prettier on commit (by invoking [Git Hooks](https://git-scm.com/docs/githooks) via [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks)). + +### Advanced Pull Request Tips + +- The PR should fix the intended bug **only** and not introduce unrelated changes. This includes unnecessary refactors - a PR should focus on the fix and not code style, this makes it easier to trace changes in the future. + +- Consider the performance / size impact of the changes, and whether the bug being fixes justifies the cost. If the bug being fixed is a very niche edge case, we should try to minimize the size / perf cost to make it worthwhile. + + - Is the code perf-sensitive (e.g. in "hot paths" like component updates or the vdom patch function?) + + - If the branch is dev-only, performance is less of a concern. + + - Check how much extra bundle size the change introduces. + - Make sure to put dev-only code in `__DEV__` branches so they are tree-shakable. + - Runtime code is more sensitive to size increase than compiler code. + - Make sure it doesn't accidentally cause dev-only or compiler-only code branches to be included in the runtime build. Notable case is that some functions in `@vue/shared` are compiler-only and should not be used in runtime code, e.g. `isHTMLTag` and `isSVGTag`. ## Development Setup -You will need [Node.js](https://nodejs.org) **version 10+**, and [PNPM](https://pnpm.io). +You will need [Node.js](https://nodejs.org) with minimum version as specified in the [`.node-version`](https://github.com/vuejs/core/blob/main/.node-version) file, and [PNPM](https://pnpm.io) with minimum version as specified in the [`"packageManager"` field in `package.json`](https://github.com/vuejs/core/blob/main/package.json#L4). -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. +We also recommend installing [@antfu/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. After cloning the repo, run: @@ -53,13 +94,35 @@ $ pnpm i # install the dependencies of the project A high level overview of tools used: - [TypeScript](https://www.typescriptlang.org/) as the development language -- [Rollup](https://rollupjs.org) for bundling -- [Jest](https://jestjs.io/) for unit testing +- [Vite](https://vitejs.dev/) and [ESBuild](https://esbuild.github.io/) for development bundling +- [Rollup](https://rollupjs.org) for production bundling +- [Vitest](https://vitest.dev/) for unit testing - [Prettier](https://prettier.io/) for code formatting +- [ESLint](https://eslint.org/) for static error prevention (outside of types) + +## Git Hooks + +The project uses [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks) to enforce the following on each commit: + +- Type check the entire project +- Automatically format changed files using Prettier +- Verify commit message format (logic in `scripts/verify-commit.js`) ## Scripts -**The examples below will be using the `nr` command from the [ni](https://github.com/antfu/ni) package.** You can also use plain `npm run`, but you will need to pass all additional arguments after the command after an extra `--`. For example, `nr build runtime --all` is equivalent to `npm run build -- runtime --all`. +**The examples below will be using the `nr` command from the [@antfu/ni](https://github.com/antfu/ni) package.** You can also use plain `npm run`, but you will need to pass all additional arguments after the command after an extra `--`. For example, `nr build runtime --all` is equivalent to `npm run build -- runtime --all`. + +The `run-s` and `run-p` commands found in some scripts are from [npm-run-all](https://github.com/mysticatea/npm-run-all) for orchestrating multiple scripts. `run-s` means "run in sequence" while `run-p` means "run in parallel". + +- [`nr build`](#nr-build) +- [`nr build-dts`](#nr-build-dts) +- [`nr check`](#nr-check) +- [`nr dev`](#nr-dev) +- [`nr dev-sfc`](#nr-dev-sfc) +- [`nr dev-esm`](#nr-dev-esm) +- [`nr dev-compiler`](#nr-dev-compiler) +- [`nr test`](#nr-test) +- [`nr test-dts`](#nr-test-dts) ### `nr build` @@ -75,6 +138,8 @@ nr build runtime-core nr build runtime --all ``` +Note that `nr build` uses `rollup-plugin-esbuild` for transpiling typescript and **does not perform type checking**. To run type check on the entire codebase, run `nr check`. Type checks are also automatically run on each commit. + #### Build Formats By default, each package will be built in multiple distribution formats as specified in the `buildOptions.formats` field in its `package.json`. These can be overwritten via the `-f` flag. The following formats are supported: @@ -90,7 +155,7 @@ Additional formats that only apply to the main `vue` package: - **`esm-bundler-runtime`** - **`esm-browser-runtime`** -More details about each of these formats can be found in the [`vue` package README](https://github.com/vuejs/vue-next/blob/master/packages/vue/README.md#which-dist-file-to-use) and the [Rollup config file](https://github.com/vuejs/vue-next/blob/master/rollup.config.js). +More details about each of these formats can be found in the [`vue` package README](https://github.com/vuejs/core/blob/main/packages/vue/README.md#which-dist-file-to-use) and the [Rollup config file](https://github.com/vuejs/core/blob/main/rollup.config.js). For example, to build `runtime-core` with the global build only: @@ -108,13 +173,11 @@ nr build runtime-core -f esm-browser,cjs Use the `--sourcemap` or `-s` flag to build with source maps. Note this will make the build much slower. -#### Build with Type Declarations +### `nr build-dts` -The `--types` or `-t` flag will generate type declarations during the build and in addition: +This command builds the type declarations for all packages. It first generates the raw `.d.ts` files in the `temp` directory, then uses [rollup-plugin-dts](https://github.com/Swatinem/rollup-plugin-dts) to roll the types into a single `.d.ts` file for each package. -- Roll the declarations into a single `.d.ts` file for each package; -- Generate an API report in `/temp/.api.md`. This report contains potential warnings emitted by [api-extractor](https://api-extractor.com/). -- Generate an API model json in `/temp/.api.json`. This file can be used to generate a Markdown version of the exported APIs. +### `nr check` ### `nr dev` @@ -123,39 +186,57 @@ The `dev` script bundles a target package (default: `vue`) in a specified format ```bash $ nr dev -> rollup v1.19.4 -> bundles packages/vue/src/index.ts → packages/vue/dist/vue.global.js... +> built: packages/vue/dist/vue.global.js ``` -- The `dev` script also supports fuzzy match for the target package, but will only match the first package matched. +- **Important:** output of the `dev` script is for development and debugging only. While it has the same runtime behavior, the generated code should never be published to npm. + +- The `dev` script does not support fuzzy match - you must specify the full package name, e.g. `nr dev runtime-core`. - The `dev` script supports specifying build format via the `-f` flag just like the `build` script. - The `dev` script also supports the `-s` flag for generating source maps, but it will make rebuilds slower. +- The `dev` script supports the `-i` flag for inlining all deps. This is useful when debugging `esm-bundler` builds which externalizes deps by default. + +### `nr dev-sfc` + +Shortcut for starting the SFC Playground in local dev mode. This provides the fastest feedback loop when debugging issues that can be reproduced in the SFC Playground. + +### `nr dev-esm` + +Builds and watches `vue/dist/vue-runtime.esm-bundler.js` with all deps inlined using esbuild. This is useful when debugging the ESM build in a reproduction that requires real build setups: link `packages/vue` globally, then link it into the project being debugged. + ### `nr dev-compiler` -The `dev-compiler` script builds, watches and serves the [Template Explorer](https://github.com/vuejs/vue-next/tree/master/packages/template-explorer) at `http://localhost:5000`. This is extremely useful when working on the compiler. +The `dev-compiler` script builds, watches and serves the [Template Explorer](https://github.com/vuejs/core/tree/main/packages/template-explorer) at `http://localhost:3000`. This is useful when working on pure compiler issues. ### `nr test` -The `test` script simply calls the `jest` binary, so all [Jest CLI Options](https://jestjs.io/docs/en/cli) can be used. Some examples: +The `test` script simply calls the `vitest` binary, so all [Vitest CLI Options](https://vitest.dev/guide/cli.html#options) can be used. Some examples: ```bash -# run all tests +# run all tests in watch mode $ nr test +# run once and exit (equivalent to `vitest run`) +$ nr test run + # run all tests under the runtime-core package $ nr test runtime-core -# run tests in a specific file -$ nr test fileName +# run tests in files matching the pattern +$ nr test -# run a specific test in a specific file -$ nr test fileName -t 'test name' +# run a specific test in specific files +$ nr test -t 'test name' ``` -The default `test` script includes the `--runInBand` jest flag to improve test stability, especially for the CSS transition related tests. When you are testing specific test specs, you can also run `npx jest` with flags directly to speed up tests (jest runs them in parallel by default). +Tests that test against source code are grouped under `nr test-unit`, while tests that test against built files that run in real browsers are grouped under `nr test-e2e`. + +### `nr test-dts` + +Runs `nr build-dts` first, then verify the type tests in `packages-private/dts-test` are working correctly against the actual built type declarations. ## Project Structure @@ -175,16 +256,22 @@ This repository employs a [monorepo](https://en.wikipedia.org/wiki/Monorepo) set - `compiler-dom`: Compiler with additional plugins specifically targeting the browser. +- `compiler-sfc`: Lower level utilities for compiling Vue Single File Components. + - `compiler-ssr`: Compiler that produces render functions optimized for server-side rendering. -- `template-explorer`: A development tool for debugging compiler output. You can run `nr dev template-explorer` and open its `index.html` to get a repl of template compilation based on current source code. - - A [live version](https://vue-next-template-explorer.netlify.com) of the template explorer is also available, which can be used for providing reproductions for compiler bugs. You can also pick the deployment for a specific commit from the [deploy logs](https://app.netlify.com/sites/vue-next-template-explorer/deploys). - - `shared`: Internal utilities shared across multiple packages (especially environment-agnostic utils used by both runtime and compiler packages). - `vue`: The public facing "full build" which includes both the runtime AND the compiler. +- Private utility packages: + + - `dts-test`: Contains type-only tests against generated dts files. + + - `sfc-playground`: The playground continuously deployed at https://play.vuejs.org. To run the playground locally, use [`nr dev-sfc`](#nr-dev-sfc). + + - `template-explorer`: A development tool for debugging compiler output, continuously deployed at https://template-explorer.vuejs.org/. To run it locally, run [`nr dev-compiler`](#nr-dev-compiler). + ### Importing Packages The packages can import each other directly using their package names. Note that when importing a package, the name listed in its `package.json` should be used. Most of the time the `@vue/` prefix is needed: @@ -196,32 +283,34 @@ import { h } from '@vue/runtime-core' This is made possible via several configurations: - For TypeScript, `compilerOptions.paths` in `tsconfig.json` -- For Jest, `moduleNameMapper` in `jest.config.js` +- Vitest and Rollup share the same set of aliases from `scripts/aliases.js` - For plain Node.js, they are linked using [PNPM Workspaces](https://pnpm.io/workspaces). ### Package Dependencies -``` - +---------------------+ - | | - | @vue/compiler-sfc | - | | - +-----+--------+------+ - | | - v v - +---------------------+ +----------------------+ - | | | | - +------------>| @vue/compiler-dom +--->| @vue/compiler-core | - | | | | | - +----+----+ +---------------------+ +----------------------+ - | | - | vue | - | | - +----+----+ +---------------------+ +----------------------+ +-------------------+ - | | | | | | | - +------------>| @vue/runtime-dom +--->| @vue/runtime-core +--->| @vue/reactivity | - | | | | | | - +---------------------+ +----------------------+ +-------------------+ +```mermaid + flowchart LR + compiler-sfc["@vue/compiler-sfc"] + compiler-dom["@vue/compiler-dom"] + compiler-core["@vue/compiler-core"] + vue["vue"] + runtime-dom["@vue/runtime-dom"] + runtime-core["@vue/runtime-core"] + reactivity["@vue/reactivity"] + + subgraph "Runtime Packages" + runtime-dom --> runtime-core + runtime-core --> reactivity + end + + subgraph "Compiler Packages" + compiler-sfc --> compiler-core + compiler-sfc --> compiler-dom + compiler-dom --> compiler-core + end + + vue ---> compiler-dom + vue --> runtime-dom ``` There are some rules to follow when importing across package boundaries: @@ -234,7 +323,7 @@ There are some rules to follow when importing across package boundaries: ## Contributing Tests -Unit tests are collocated with the code being tested in each package, inside directories named `__tests__`. Consult the [Jest docs](https://jestjs.io/docs/en/using-matchers) and existing test cases for how to write new test specs. Here are some additional guidelines: +Unit tests are collocated with the code being tested in each package, inside directories named `__tests__`. Consult the [Vitest docs](https://vitest.dev/api/) and existing test cases for how to write new test specs. Here are some additional guidelines: - Use the minimal API needed for a test case. For example, if a test can be written without involving the reactivity system or a component, it should be written so. This limits the test's exposure to changes in unrelated parts and makes it more stable. @@ -242,13 +331,11 @@ Unit tests are collocated with the code being tested in each package, inside dir - Only use platform-specific runtimes if the test is asserting platform-specific behavior. -Test coverage is continuously deployed at https://vue-next-coverage.netlify.app/. PRs that improve test coverage are welcome, but in general the test coverage should be used as a guidance for finding API use cases that are not covered by tests. We don't recommend adding tests that only improve coverage but not actually test a meaning use case. +Test coverage is continuously deployed at https://coverage.vuejs.org. PRs that improve test coverage are welcome, but in general the test coverage should be used as a guidance for finding API use cases that are not covered by tests. We don't recommend adding tests that only improve coverage but not actually test a meaning use case. ### Testing Type Definition Correctness -This project uses [tsd](https://github.com/SamVerschueren/tsd) to test the built definition files (`*.d.ts`). - -Type tests are located in the `test-dts` directory. To run the dts tests, run `nr test-dts`. Note that the type test requires all relevant `*.d.ts` files to be built first (and the script does it for you). Once the `d.ts` files are built and up-to-date, the tests can be re-run by simply running `nr test-dts`. +Type tests are located in the `packages-private/dts-test` directory. To run the dts tests, run `nr test-dts`. Note that the type test requires all relevant `*.d.ts` files to be built first (and the script does it for you). Once the `d.ts` files are built and up-to-date, the tests can be re-run by running `nr test-dts-only`. ## Financial Contribution @@ -265,4 +352,4 @@ Funds donated via Patreon go directly to support Evan You's full-time work on Vu Thank you to all the people who have already contributed to Vue.js! - + diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index af713d27a..000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,64 +0,0 @@ -version: 2 -updates: -- package-ecosystem: npm - directory: "/" - schedule: - interval: monthly - open-pull-requests-limit: 10 - versioning-strategy: lockfile-only - ignore: - - dependency-name: "@types/node" - versions: - - 14.14.24 - - 14.14.37 - - dependency-name: "@babel/parser" - versions: - - 7.12.11 - - 7.12.13 - - 7.12.14 - - 7.12.15 - - 7.12.16 - - 7.12.17 - - 7.13.0 - - 7.13.10 - - 7.13.11 - - 7.13.13 - - 7.13.4 - - 7.13.9 - - dependency-name: eslint - versions: - - 7.23.0 - - dependency-name: postcss - versions: - - 8.2.4 - - 8.2.5 - - 8.2.7 - - 8.2.8 - - dependency-name: typescript - versions: - - 4.2.2 - - dependency-name: "@babel/types" - versions: - - 7.12.12 - - 7.12.13 - - 7.12.17 - - 7.13.0 - - dependency-name: pug-code-gen - versions: - - 2.0.3 - - dependency-name: estree-walker - versions: - - 2.0.2 - - dependency-name: "@typescript-eslint/parser" - versions: - - 4.14.2 - - 4.15.0 - - dependency-name: "@microsoft/api-extractor" - versions: - - 7.13.1 - - dependency-name: rollup - versions: - - 2.38.5 - - dependency-name: node-notifier - versions: - - 8.0.1 diff --git a/.github/git-branch-workflow.excalidraw b/.github/git-branch-workflow.excalidraw new file mode 100644 index 000000000..dd9127938 --- /dev/null +++ b/.github/git-branch-workflow.excalidraw @@ -0,0 +1,1746 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "type": "arrow", + "version": 799, + "versionNonce": 529220601, + "isDeleted": false, + "id": "Gao2krnDddLMCj468JSWD", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 860.0129225738813, + "y": 663.9911710635109, + "strokeColor": "#f08c00", + "backgroundColor": "#ffc9c9", + "width": 133.75296854079784, + "height": 149.58016791936518, + "seed": 1415631543, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "hDC6an14QljktaZCUhcPF", + "focus": 0.09950793234484598, + "gap": 1.2432497743127229 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 25.209039386719837, + 85.96948921803892 + ], + [ + 133.75296854079784, + 149.58016791936518 + ] + ] + }, + { + "type": "arrow", + "version": 563, + "versionNonce": 290881303, + "isDeleted": false, + "id": "N3wyyEU7TQ8BsOQgxCmlR", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 292.88008929085873, + "y": 660.7027503334302, + "strokeColor": "#2f9e44", + "backgroundColor": "#b2f2bb", + "width": 936.9972134376155, + "height": 1.3184243543457796, + "seed": 534235417, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 936.9972134376155, + -1.3184243543457796 + ] + ] + }, + { + "type": "arrow", + "version": 302, + "versionNonce": 883286489, + "isDeleted": false, + "id": "nRDWQs5nQa37yzCWTBiXC", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 293.1231624544633, + "y": 820.6017661012943, + "strokeColor": "#f08c00", + "backgroundColor": "#b2f2bb", + "width": 790.7091601354882, + "height": 0.35284814071621895, + "seed": 515907671, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "ggogfJT7E_bbfEog7Hjnp", + "focus": -0.14000162237652433, + "gap": 1 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 790.7091601354882, + -0.35284814071621895 + ] + ] + }, + { + "type": "text", + "version": 36, + "versionNonce": 981763127, + "isDeleted": false, + "id": "ZPdMAnEUq5Jgj1W07Zqiw", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 292.0450153578305, + "y": 619.3959946602608, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "width": 46.875, + "height": 24, + "seed": 1311694519, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 3, + "text": "main", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "main", + "lineHeight": 1.2, + "baseline": 20 + }, + { + "type": "text", + "version": 94, + "versionNonce": 18759353, + "isDeleted": false, + "id": "g9IkEIfu4vA8Qkwtw01Hi", + "fillStyle": "hachure", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 290.88990199912035, + "y": 779.1760596323645, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "width": 58.59375, + "height": 24, + "seed": 329886135, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false, + "fontSize": 20, + "fontFamily": 3, + "text": "minor", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "minor", + "lineHeight": 1.2, + "baseline": 20 + }, + { + "type": "ellipse", + "version": 50, + "versionNonce": 1442112855, + "isDeleted": false, + "id": "RrdEQ7hwgGGDPhzDnuZj1", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 361.55609907891005, + "y": 649.8742329483416, + "strokeColor": "#2f9e44", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 2077639991, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 79, + "versionNonce": 1547173785, + "isDeleted": false, + "id": "Zmp49FKWxGSzKnVKomjQc", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 427.3015090315691, + "y": 650.256485100784, + "strokeColor": "#2f9e44", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 372652121, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 76, + "versionNonce": 586949239, + "isDeleted": false, + "id": "UOl9nLBksM7RPdH9mzjJa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 490.9435520120701, + "y": 651.2601420343765, + "strokeColor": "#2f9e44", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 508667545, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 120, + "versionNonce": 874947705, + "isDeleted": false, + "id": "oMC55V0VO_hOXoZ1se8Kl", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 555.4481126698772, + "y": 650.7975189165487, + "strokeColor": "#2f9e44", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 1914963513, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 66, + "versionNonce": 39762839, + "isDeleted": false, + "id": "DZY5DC5uVP7-U5c3ngIZ4", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 622.5167031502219, + "y": 649.3743647489936, + "strokeColor": "#2f9e44", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 165914713, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 107, + "versionNonce": 1689103705, + "isDeleted": false, + "id": "Vsw6oIiTM3fQypkiCic3f", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 690.330195260967, + "y": 650.6681412649529, + "strokeColor": "#2f9e44", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 280044345, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "lwYvAs-7FTjcwxKjcx0KV", + "type": "arrow" + } + ], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 148, + "versionNonce": 1986194201, + "isDeleted": false, + "id": "D14w9erv_2l53mINe2nSt", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 361.004283792179, + "y": 810.2809579853473, + "strokeColor": "#f08c00", + "backgroundColor": "#ffc9c9", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 1203257975, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 179, + "versionNonce": 1172811511, + "isDeleted": false, + "id": "6WO8xOpG0rf673b_bT0m7", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 426.74969374483805, + "y": 810.6632101377896, + "strokeColor": "#f08c00", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 2056706967, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "mE8Mu0qKfFaWPCC5vmF_f", + "type": "arrow" + } + ], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 173, + "versionNonce": 820518905, + "isDeleted": false, + "id": "VB9U8oH-78hf530hIb_mG", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 490.391736725339, + "y": 811.6668670713822, + "strokeColor": "#f08c00", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 1149587639, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 218, + "versionNonce": 1227143191, + "isDeleted": false, + "id": "Bxv1hcS0VmxUwI0JLFH97", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 554.8962973831461, + "y": 811.2042439535543, + "strokeColor": "#f08c00", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 1864901079, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "M14Q0Uo1DBy2Ss2SOFSgW", + "type": "arrow" + } + ], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 167, + "versionNonce": 1387509977, + "isDeleted": false, + "id": "4v23gkfhy-hzk18YdkfLz", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 621.9648878634908, + "y": 809.7810897859994, + "strokeColor": "#f08c00", + "backgroundColor": "#ffc9c9", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 462671607, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "vEF1cIIYYWKm84KLKqEz3", + "type": "arrow" + } + ], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 200, + "versionNonce": 774085943, + "isDeleted": false, + "id": "AtEf7o4WZQn4Zxq8EN5fH", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 689.7783799742359, + "y": 811.0748663019584, + "strokeColor": "#f08c00", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 1414322199, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "3heKY3vfe3-6ni4dX7Uqo", + "type": "arrow" + } + ], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 199, + "versionNonce": 1834563001, + "isDeleted": false, + "id": "ugDby5sBv4NKdNt8eC1sg", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 762.6179978227377, + "y": 810.2986003923828, + "strokeColor": "#f08c00", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 1598537015, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 211, + "versionNonce": 407428695, + "isDeleted": false, + "id": "Fwe4F2sB_0jptOZGYsusj", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 837.1081608628116, + "y": 810.859236882632, + "strokeColor": "#f08c00", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 1340669527, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "M14Q0Uo1DBy2Ss2SOFSgW", + "type": "arrow" + } + ], + "updated": 1698927613071, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 57, + "versionNonce": 335287961, + "isDeleted": false, + "id": "mE8Mu0qKfFaWPCC5vmF_f", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 437.60867586595543, + "y": 830.4227236701945, + "strokeColor": "#f08c00", + "backgroundColor": "#ffc9c9", + "width": 0.5232394659406623, + "height": 33.25787987764363, + "seed": 482155929, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false, + "startBinding": { + "elementId": "6WO8xOpG0rf673b_bT0m7", + "focus": -0.1727591064041787, + "gap": 1.046152088903881 + }, + "endBinding": { + "elementId": "JALHBtowuh3_a86loej2x", + "focus": 0.015156451076917701, + "gap": 15.586906139714472 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -0.5232394659406623, + 33.25787987764363 + ] + ] + }, + { + "type": "arrow", + "version": 59, + "versionNonce": 1248394103, + "isDeleted": false, + "id": "AI-_jSAuzesxTqwRvpk0s", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 501.2878833373983, + "y": 652.3088851192829, + "strokeColor": "#2f9e44", + "backgroundColor": "#ffc9c9", + "width": 0, + "height": 40.40111211199792, + "seed": 1052632343, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 0, + -40.40111211199792 + ] + ] + }, + { + "type": "arrow", + "version": 261, + "versionNonce": 693099385, + "isDeleted": false, + "id": "lwYvAs-7FTjcwxKjcx0KV", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 786.7392304423553, + "y": 649.6016935672433, + "strokeColor": "#2f9e44", + "backgroundColor": "#ffc9c9", + "width": 0, + "height": 40.40111211199792, + "seed": 1233043511, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false, + "startBinding": { + "elementId": "s0PKxsWTJSDbQeEl_WI-C", + "focus": 0.016372633695398757, + "gap": 1 + }, + "endBinding": { + "elementId": "9ia1Uwc5X0fRw5iaahmcT", + "focus": 0.025318405829282714, + "gap": 14.862364635333904 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 0, + -40.40111211199792 + ] + ] + }, + { + "type": "text", + "version": 121, + "versionNonce": 952661143, + "isDeleted": false, + "id": "qWW8uxDIcV3Bkj28uvRLr", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 454.32425448306674, + "y": 537.8854189061962, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "width": 93.75, + "height": 57.599999999999994, + "seed": 809847769, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "patch\nrelease\ne.g. 3.3.8", + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "patch\nrelease\ne.g. 3.3.8", + "lineHeight": 1.2, + "baseline": 53 + }, + { + "type": "text", + "version": 257, + "versionNonce": 1838679129, + "isDeleted": false, + "id": "9ia1Uwc5X0fRw5iaahmcT", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 741.0510307156029, + "y": 536.7382168199114, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "width": 93.75, + "height": 57.599999999999994, + "seed": 213765431, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [ + { + "id": "lwYvAs-7FTjcwxKjcx0KV", + "type": "arrow" + } + ], + "updated": 1698927613071, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "patch\nrelease\ne.g. 3.3.9", + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "patch\nrelease\ne.g. 3.3.9", + "lineHeight": 1.2, + "baseline": 53 + }, + { + "type": "text", + "version": 222, + "versionNonce": 1528547767, + "isDeleted": false, + "id": "JALHBtowuh3_a86loej2x", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 350.7264132088442, + "y": 879.2675096875524, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "width": 168.75, + "height": 57.599999999999994, + "seed": 41180921, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [ + { + "id": "mE8Mu0qKfFaWPCC5vmF_f", + "type": "arrow" + } + ], + "updated": 1698927613071, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "pre minor\nrelease\ne.g. 3.4.0-alpha.1", + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "pre minor\nrelease\ne.g. 3.4.0-alpha.1", + "lineHeight": 1.2, + "baseline": 53 + }, + { + "type": "arrow", + "version": 345, + "versionNonce": 1286082873, + "isDeleted": false, + "id": "3heKY3vfe3-6ni4dX7Uqo", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 699.5281288163526, + "y": 831.0290882554708, + "strokeColor": "#f08c00", + "backgroundColor": "#ffc9c9", + "width": 0.5502191262773977, + "height": 33.25154356841597, + "seed": 627698359, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613071, + "link": null, + "locked": false, + "startBinding": { + "elementId": "AtEf7o4WZQn4Zxq8EN5fH", + "focus": -0.05612657009295625, + "gap": 1.1451322685712295 + }, + "endBinding": { + "elementId": "9t6qH-tAxVUexkHHi2pd2", + "focus": 0.015156451076917755, + "gap": 15.586906139714358 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -0.5502191262773977, + 33.25154356841597 + ] + ] + }, + { + "type": "text", + "version": 365, + "versionNonce": 1049066199, + "isDeleted": false, + "id": "9t6qH-tAxVUexkHHi2pd2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 617.3409291322284, + "y": 879.8675379636011, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "width": 159.375, + "height": 57.599999999999994, + "seed": 1013545943, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [ + { + "id": "3heKY3vfe3-6ni4dX7Uqo", + "type": "arrow" + } + ], + "updated": 1698927613071, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "pre minor\nrelease\ne.g. 3.4.0-beta.1", + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "pre minor\nrelease\ne.g. 3.4.0-beta.1", + "lineHeight": 1.2, + "baseline": 53 + }, + { + "type": "arrow", + "version": 788, + "versionNonce": 1810072089, + "isDeleted": false, + "id": "vEF1cIIYYWKm84KLKqEz3", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 630.3597332113623, + "y": 667.2735668205443, + "strokeColor": "#f08c00", + "backgroundColor": "#ffc9c9", + "width": 2.258228100583324, + "height": 140.75112333166828, + "seed": 2091697367, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "4v23gkfhy-hzk18YdkfLz", + "focus": 0.13930391883256707, + "gap": 1.8256906627890626 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 1.8426514015177418, + 69.09942755691065 + ], + [ + 2.258228100583324, + 140.75112333166828 + ] + ] + }, + { + "type": "arrow", + "version": 687, + "versionNonce": 2017318649, + "isDeleted": false, + "id": "M14Q0Uo1DBy2Ss2SOFSgW", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 370.5976915356099, + "y": 667.5155013947814, + "strokeColor": "#f08c00", + "backgroundColor": "#ffc9c9", + "width": 1.5329291446666957, + "height": 145.39303664953377, + "seed": 361678233, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": null, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -0.34892760581925586, + 83.56228079137543 + ], + [ + 1.1840015388474399, + 145.39303664953377 + ] + ] + }, + { + "type": "text", + "version": 537, + "versionNonce": 342487319, + "isDeleted": false, + "id": "CHAOOJMz7tNaG1VsG_uzT", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 384.81046417498214, + "y": 725.4677076298137, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "width": 131.25, + "height": 57.599999999999994, + "seed": 1656007289, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "merge main\ninto minor\nbefore release", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "merge main\ninto minor\nbefore release", + "lineHeight": 1.2, + "baseline": 53 + }, + { + "type": "ellipse", + "version": 202, + "versionNonce": 876253145, + "isDeleted": false, + "id": "hDC6an14QljktaZCUhcPF", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 993.0386151813434, + "y": 810.335845473903, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 1433430105, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "Gao2krnDddLMCj468JSWD", + "type": "arrow" + } + ], + "updated": 1698927613072, + "link": null, + "locked": false + }, + { + "type": "arrow", + "version": 1525, + "versionNonce": 777631287, + "isDeleted": false, + "id": "ces8IwHCpQlTnELpjFDIn", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1092.5386800881793, + "y": 827.5114796878765, + "strokeColor": "#f08c00", + "backgroundColor": "#ffc9c9", + "width": 0.3315362017829102, + "height": 49.45191086419197, + "seed": 225867737, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "8rWUxp-jRNGrGRmhHHfm4", + "focus": -0.2047594653982401, + "gap": 10.392197401393389 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + -0.3315362017829102, + 49.45191086419197 + ] + ] + }, + { + "type": "text", + "version": 894, + "versionNonce": 1173171385, + "isDeleted": false, + "id": "8rWUxp-jRNGrGRmhHHfm4", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1047.251646167428, + "y": 887.3555879534618, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "width": 112.5, + "height": 57.599999999999994, + "seed": 1600918713, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [ + { + "id": "ces8IwHCpQlTnELpjFDIn", + "type": "arrow" + } + ], + "updated": 1698927613072, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "stable minor\nrelease\ne.g. 3.4.0", + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "stable minor\nrelease\ne.g. 3.4.0", + "lineHeight": 1.2, + "baseline": 53 + }, + { + "type": "ellipse", + "version": 201, + "versionNonce": 78435447, + "isDeleted": false, + "id": "3RHuRn_evSK0YUe02B4MY", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 909.9742423218671, + "y": 810.4142561718397, + "strokeColor": "#2f9e44", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 1199705047, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 371, + "versionNonce": 2093872087, + "isDeleted": false, + "id": "9h2Cu__8owLUgUGjGcWDe", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 848.4414471158692, + "y": 650.826922928275, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 603147257, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 361, + "versionNonce": 1981618457, + "isDeleted": false, + "id": "s0PKxsWTJSDbQeEl_WI-C", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 777.1778842958995, + "y": 650.2466837635417, + "strokeColor": "#2f9e44", + "backgroundColor": "#b2f2bb", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 326722777, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "lwYvAs-7FTjcwxKjcx0KV", + "type": "arrow" + } + ], + "updated": 1698927613072, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 871, + "versionNonce": 1528156247, + "isDeleted": false, + "id": "3JAdSa7kqqSDSom5ZFDoE", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 904.3603861670398, + "y": 707.2413714353705, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "width": 140.625, + "height": 57.599999999999994, + "seed": 1011049431, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "final merge\nmain into minor\nbefore release", + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "final merge\nmain into minor\nbefore release", + "lineHeight": 1.2, + "baseline": 53 + }, + { + "type": "arrow", + "version": 591, + "versionNonce": 1714373785, + "isDeleted": false, + "id": "7kFBLq2Iczmj0lVnVk8Ad", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 1100.7141458557703, + "y": 814.2034531496416, + "strokeColor": "#2f9e44", + "backgroundColor": "#ffffff", + "width": 127.38209933342364, + "height": 144.5383600420214, + "seed": 25829591, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false, + "startBinding": null, + "endBinding": { + "elementId": "Y7VXnuc9QEz2N2l9i0xrc", + "focus": 0.3932764551319699, + "gap": 5.928572790502042 + }, + "lastCommittedPoint": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "points": [ + [ + 0, + 0 + ], + [ + 88.94909573964219, + -43.721805169626464 + ], + [ + 127.38209933342364, + -144.5383600420214 + ] + ] + }, + { + "type": "text", + "version": 1208, + "versionNonce": 1254600055, + "isDeleted": false, + "id": "gwFWlPLabuYhxCOweJjWz", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1223.0464288187204, + "y": 725.1565933898091, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "width": 150, + "height": 38.4, + "seed": 51102743, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "main merge minor\n(fast forward)", + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "main merge minor\n(fast forward)", + "lineHeight": 1.2, + "baseline": 34 + }, + { + "type": "ellipse", + "version": 597, + "versionNonce": 1760381305, + "isDeleted": false, + "id": "Y7VXnuc9QEz2N2l9i0xrc", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1227.4473966637659, + "y": 647.6689320688656, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 412038615, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "7kFBLq2Iczmj0lVnVk8Ad", + "type": "arrow" + } + ], + "updated": 1698927613072, + "link": null, + "locked": false + }, + { + "type": "ellipse", + "version": 547, + "versionNonce": 1585505943, + "isDeleted": false, + "id": "ggogfJT7E_bbfEog7Hjnp", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 1083.7911569735343, + "y": 809.5203742153592, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 18.814646969963974, + "height": 18.814646969963974, + "seed": 741463161, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "boundElements": [ + { + "id": "nRDWQs5nQa37yzCWTBiXC", + "type": "arrow" + } + ], + "updated": 1698927613072, + "link": null, + "locked": false + }, + { + "type": "text", + "version": 229, + "versionNonce": 1935127129, + "isDeleted": false, + "id": "eU-EgpwDD42CLYUEIDLaD", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 305.8405004265049, + "y": 389.31989430571576, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 581.25, + "height": 19.2, + "seed": 1086231577, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "- merge feature PRs into, and release minors from minor branch", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "- merge feature PRs into, and release minors from minor branch", + "lineHeight": 1.2, + "baseline": 15 + }, + { + "type": "text", + "version": 397, + "versionNonce": 116088535, + "isDeleted": false, + "id": "Kt6VBAVD4sLM4IexsRGoX", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 305.4136207977353, + "y": 358.61173442109686, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 618.75, + "height": 19.2, + "seed": 273353945, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698927617946, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "- merge fix / chore PRs into, and release patches from main branch", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "- merge fix / chore PRs into, and release patches from main branch", + "lineHeight": 1.2, + "baseline": 15 + }, + { + "type": "text", + "version": 459, + "versionNonce": 440532793, + "isDeleted": false, + "id": "JwKEdnU6H_Nu74WbEAX5M", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 305.6723761009271, + "y": 418.3724478537203, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 459.375, + "height": 19.2, + "seed": 1001222329, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "- merge main into minor before each minor release", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "- merge main into minor before each minor release", + "lineHeight": 1.2, + "baseline": 15 + }, + { + "type": "text", + "version": 602, + "versionNonce": 1108720119, + "isDeleted": false, + "id": "mb9ZoP803MiH7MTO8wH-2", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "angle": 0, + "x": 305.0895924262568, + "y": 447.44321411383333, + "strokeColor": "#1e1e1e", + "backgroundColor": "#a5d8ff", + "width": 534.375, + "height": 19.2, + "seed": 264651479, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "- fast forward main to minor after a stable minor release", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "- fast forward main to minor after a stable minor release", + "lineHeight": 1.2, + "baseline": 15 + }, + { + "type": "text", + "version": 612, + "versionNonce": 1588872441, + "isDeleted": false, + "id": "IfJPOFiwrCibpaBQqc5g-", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 2, + "opacity": 100, + "angle": 0, + "x": 646.7131179044119, + "y": 724.4984335940012, + "strokeColor": "#1e1e1e", + "backgroundColor": "#ffc9c9", + "width": 131.25, + "height": 57.599999999999994, + "seed": 1301100087, + "groupIds": [], + "frameId": null, + "roundness": null, + "boundElements": [], + "updated": 1698927613072, + "link": null, + "locked": false, + "fontSize": 16, + "fontFamily": 3, + "text": "merge main\ninto minor\nbefore release", + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "merge main\ninto minor\nbefore release", + "lineHeight": 1.2, + "baseline": 53 + } + ], + "appState": { + "gridSize": null, + "viewBackgroundColor": "#ffffff" + }, + "files": {} +} \ No newline at end of file diff --git a/.github/git-branch-workflow.png b/.github/git-branch-workflow.png new file mode 100644 index 000000000..6c8ee07d4 Binary files /dev/null and b/.github/git-branch-workflow.png differ diff --git a/.github/issue-workflow.png b/.github/issue-workflow.png new file mode 100644 index 000000000..92b1de063 Binary files /dev/null and b/.github/issue-workflow.png differ diff --git a/.github/maintenance.md b/.github/maintenance.md new file mode 100644 index 000000000..b1fb550dd --- /dev/null +++ b/.github/maintenance.md @@ -0,0 +1,123 @@ +# Vue Core Maintenance Handbook + +Unlike [contributing.md](./contributing.md), which targets external contributors, this document is mainly intended for team members responsible for maintaining the project. It provides guidelines on how to triage issues, review & merge PRs, and publish releases. However, it should also be valuable to external contributors even if you are not a maintainer, as it gives you a better idea of how the maintainers operate, and how you can better collaborate with them. And who knows - maybe one day you will join as a maintainer as well! + +- [Issue Triage Workflow](#issue-triage-workflow) +- [Pull Request Review Guidelines](#pull-request-review-guidelines) + - [Reviewing a Fix](#reviewing-a-fix) + - [Reviewing a Refactor](#reviewing-a-refactor) + - [Reviewing a Feature](#reviewing-a-feature) + - [Common Considerations for All PRs](#common-considerations-for-all-prs) +- [PR Merge Rules for Team Members](#pr-merge-rules-for-team-members) +- [Git Branch and Release Workflow](#git-branch-and-release-workflow) + +## Issue Triage Workflow + +![Workflow](./issue-workflow.png) + +## Pull Request Review Guidelines + +The first step of reviewing a PR is to identify its purpose. We can usually put a PR in one of these categories: + +- **Fix**: fixes some wrong behavior. Usually associated with an issue that has a reproduction of the behavior being fixed. +- **Refactor**: improves performance or code quality, but does not affect behavior. +- **Feature**: implements something that increases the public API surface. + +Depending on the type of the PR, different considerations need to be taken into account. + +### Reviewing a Fix + +- Is the PR fixing a well defined issue / bug report? + - If not, ask to clarify context / provide reproduction or failing test case +- In most cases, a fix PR should include a test case that fails without the fix. +- Is it the right fix? + - If not, guide user to rework the PR. + - If the needed change is small and obvious, can directly push to the PR or add inline suggestions to reduce the back-and-forth. +- Is the cost justified? + - Sometimes the fix for a rare edge case might be introducing disproportionately large overhead (perf or code size). We should try our best to reduce the overhead to make the fix a reasonable tradeoff. +- If the reviewer is not sure about a fix, try to leave a comment explaining the concerns / reservations so the contributor at least gets some feedback. + +#### Verifying a Fix + +- **Always locally verify that the fix indeed fixes the original behavior, either through a reproduction or a failing test case.** +- We will run [ecosystem-ci](https://github.com/vuejs/ecosystem-ci) before every release, but if you are concerned about the potential impact of a change, it never hurts to manually run ecosystem-ci by leaving a `/ecosystem-ci run` comment (only works for team members). +- Take extra caution with snapshot tests! The CI can be "passing" even if the code generated in the snapshot contains bugs. It's best to always accompany a snapshot test with extra `expect(code).toMatch(...)` assertions. + +### Reviewing a Refactor + +- Performance: if a refactor PR claims to improve performance, there should be benchmarks showcasing said performance unless the improvement is self-explanatory. + +- Code quality / stylistic PRs: we should be conservative on merging this type PRs because (1) they can be subjective in many cases, and (2) they often come with large git diffs, causing merge conflicts with other pending PRs, and leading to unwanted noise when tracing changes through git history. Use your best judgement on this type of PRs on whether they are worth it. + + - For PRs in this category that are approved, do not merge immediately. Group them before releasing a new minor, after all feature-oriented PRs are merged. + +### Reviewing a Feature + +- Feature PRs should always have clear context and explanation on why the feature should be added, ideally in the form of an RFC. If the PR doesn't explain what real-world problem it is solving, ask the contributor to clarify. + +- Decide if the feature should require an RFC process. The line isn't always clear, but a rough criteria is whether it is augmenting an existing API vs. adding a new API. Some examples: + + - Adding a new built-in component or directive is "significant" and definitely requires an RFC. + - Template syntax additions like adding a new `v-on` modifier or a new `v-bind` syntax sugar are "substantial". It would be nice to have an RFC for it, but a detailed explanation on the use case and reasoning behind the design directly in the PR itself can be acceptable. + - Small, low-impact additions like exposing a new utility type or adding a new app config option can be self-explanatory, but should still provide enough context in the PR. + +- Always ask if the use case can be solved with existing APIs. Vue already has a pretty large API surface, so we want to make sure every new addition either solves something that wasn't possible before, or significantly improves the DX of a common task. + +### Common Considerations for All PRs + +- Scope: a PR should only contain changes directly related to the problem being addressed. It should not contain unnecessary code style changes. + +- Implementation: code style should be consistent with the rest of the codebase, follow common best practices. Prefer code that is boring but easy to understand over "clever" code. + +- Size: bundle size matters. We have a GitHub action that compares the size change for every PR. We should always aim to realize the desired changes with the smallest amount of code size increase. + + - Sometimes we need to compare the size increase vs. perceived benefits to decide whether a change is justifiable. Also take extra care to make sure added code can be tree-shaken if not needed. + + - Make sure to put dev-only code in `__DEV__` branches so they are tree-shakable. + + - Runtime code is more sensitive to size increase than compiler code. + + - Make sure it doesn't accidentally cause dev-only or compiler-only code branches to be included in the runtime build. Notable case is that some functions in @vue/shared are compiler-only and should not be used in runtime code, e.g. `isHTMLTag` and `isSVGTag`. + +- Performance + + - Be careful about code changes in "hot paths", in particular the Virtual DOM renderer (`runtime-core/src/renderer.ts`) and component instantiation code. + +- Potential Breakage + - avoiding runtime behavior breakage is the highest priority + - if not sure, use `ecosystem-ci` to verify! + - some fix inevitably cause behavior change, these must be discussed case-by-case + - type level breakage (e.g upgrading TS) is possible between minors + +## PR Merge Rules for Team Members + +Given that the PR meets the review requirements: + +- Chore / dependencies bumps: can merge directly. +- Fixes / refactors: can merge with two or more approvals from team members. + - If you believe a PR looks good but you are not 100% confident to merge, label with "ready for merge" and Evan will provide a final review before merging. +- Features: if approved by two or more team members, label with "ready to merge". Evan will review periodically, or they can be raised and discussed at team meetings. + +## Git Branch and Release Workflow + +We use two primary work branches: `main` and `minor`. + +- The `main` branch is for stable releases. Changes that are bug fixes or refactors that do not affect the public API surface should land in this branch. We periodically release patch releases from the `main` branch. + +- The `minor` branch is the WIP branch for the next minor release. Changes that are new features or those that affect public API behavior should land in this branch. We will periodically release pre-releases (alpha / beta) for the next minor from this branch. + +Before each release, we merge latest `main` into `minor` so it would include the latest bug fixes. + +When the minor is ready, we do a final merge of `main` into `minor`, and then release a stable minor from this branch (e.g. `3.4.0`). After that, the `main` branch is fast-forwarded to the release commit, so the two branches are synced at each stable minor release. + +![Workflow](./git-branch-workflow.png) + +### Reasoning Behind the Workflow + +The reason behind this workflow is to allow merging and releasing of fixes and features in parallel. In the past, we used a linear trunk-based development model. While the linear model results in a clean git history, the downside is that we need to be careful about when to merge patches vs. features. + +Vue typically groups a number of features with the same scope in a minor release. We don't want to release a minor just because we happened to merge a feature PR along with a bunch of small bug fixes. So we usually "wait" until we feel we are ready to start working on a minor release before merging feature PRs. + +But in reality, there are always bugs to fix and patch release to work on - this caused the intervals between minors to drag on longer than we had hoped, and many feature PRs were left waiting for a long period of time. + +This is why we decided to separate bug fixes and feature PRs into separate branches. With this two-branch model, we are able to merge and release both types of changes in parallel. diff --git a/.github/renovate.json5 b/.github/renovate.json5 new file mode 100644 index 000000000..8808b599e --- /dev/null +++ b/.github/renovate.json5 @@ -0,0 +1,66 @@ +{ + $schema: 'https://docs.renovatebot.com/renovate-schema.json', + extends: ['config:base', 'schedule:weekly', 'group:allNonMajor'], + labels: ['dependencies'], + ignorePaths: ['**/__tests__/**'], + rangeStrategy: 'bump', + packageRules: [ + { + depTypeList: ['peerDependencies'], + enabled: false, + }, + { + groupName: 'test', + matchPackageNames: ['vitest', 'jsdom', 'puppeteer'], + matchPackagePrefixes: ['@vitest'], + }, + { + groupName: 'playground', + matchFileNames: [ + 'packages-private/sfc-playground/package.json', + 'packages-private/template-explorer/package.json', + ], + }, + { + groupName: 'compiler', + matchPackageNames: ['magic-string'], + matchPackagePrefixes: ['@babel', 'postcss'], + }, + { + groupName: 'build', + matchPackageNames: ['vite', '@swc/core'], + matchPackagePrefixes: ['rollup', 'esbuild', '@rollup', '@vitejs'], + }, + { + groupName: 'lint', + matchPackageNames: ['simple-git-hooks', 'lint-staged'], + matchPackagePrefixes: ['typescript-eslint', 'eslint', 'prettier'], + }, + ], + ignoreDeps: [ + 'vue', + + // manually bumping + 'node', + 'typescript', + + // ESM only + 'estree-walker', + + // pinned + // https://github.com/vuejs/core/issues/10300#issuecomment-1940855364 + 'lru-cache', + + // pinned + // https://github.com/vuejs/core/commit/a012e39b373f1b6918e5c89856e8f902e1bfa14d + '@rollup/plugin-replace', + + // pinned + // only used in example for e2e tests + 'marked', + + // pinned, 5.0+ has exports issues + // https://github.com/vuejs/core/issues/11603 + 'entities', + ], +} diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml new file mode 100644 index 000000000..d5c31beff --- /dev/null +++ b/.github/workflows/autofix.yml @@ -0,0 +1,34 @@ +name: autofix.ci + +on: + pull_request: +permissions: + contents: read + +jobs: + autofix: + runs-on: ubuntu-latest + env: + PUPPETEER_SKIP_DOWNLOAD: 'true' + steps: + - uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4.0.0 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.node-version' + registry-url: 'https://registry.npmjs.org' + cache: 'pnpm' + + - run: pnpm install + + - name: Run eslint + run: pnpm run lint --fix + + - name: Run prettier + run: pnpm run format + + - uses: autofix-ci/action@ff86a557419858bb967097bfc916833f5647fa8c diff --git a/.github/workflows/canary-minor.yml b/.github/workflows/canary-minor.yml new file mode 100644 index 000000000..b5d75b9ce --- /dev/null +++ b/.github/workflows/canary-minor.yml @@ -0,0 +1,33 @@ +name: canary minor release +on: + # Runs every Monday at 1 AM UTC (9:00 AM in Singapore) + schedule: + - cron: 0 1 * * MON + workflow_dispatch: + +jobs: + canary: + # prevents this action from running on forks + if: github.repository == 'vuejs/core' + runs-on: ubuntu-latest + environment: Release + steps: + - uses: actions/checkout@v4 + with: + ref: minor + + - name: Install pnpm + uses: pnpm/action-setup@v4.0.0 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.node-version' + registry-url: 'https://registry.npmjs.org' + cache: 'pnpm' + + - run: pnpm install + + - run: pnpm release --canary --publish --tag minor + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml new file mode 100644 index 000000000..bb622725a --- /dev/null +++ b/.github/workflows/canary.yml @@ -0,0 +1,31 @@ +name: canary release +on: + # Runs every Monday at 1 AM UTC (9:00 AM in Singapore) + schedule: + - cron: 0 1 * * MON + workflow_dispatch: + +jobs: + canary: + # prevents this action from running on forks + if: github.repository == 'vuejs/core' + runs-on: ubuntu-latest + environment: Release + steps: + - uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4.0.0 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.node-version' + registry-url: 'https://registry.npmjs.org' + cache: 'pnpm' + + - run: pnpm install + + - run: pnpm release --canary --publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 085c8dbbd..c8c217f62 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,76 +3,40 @@ on: push: branches: - '**' + tags: + - '!**' pull_request: branches: - - master + - main + - minor + jobs: test: + if: ${{ ! startsWith(github.event.head_commit.message, 'release:') && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository) }} + uses: ./.github/workflows/test.yml + + continuous-release: + if: github.repository == 'vuejs/core' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - name: Checkout + uses: actions/checkout@v4 - name: Install pnpm - uses: pnpm/action-setup@v2.0.1 - with: - version: 6.15.1 + uses: pnpm/action-setup@v4 - - name: Set node version to 16 - uses: actions/setup-node@v2 + - name: Install Node.js + uses: actions/setup-node@v4 with: - node-version: 16 + node-version-file: '.node-version' + registry-url: 'https://registry.npmjs.org' cache: 'pnpm' - - run: pnpm install + - name: Install deps + run: pnpm install - - name: Run unit tests - run: pnpm run test + - name: Build + run: pnpm build --withTypes - test-dts: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - - name: Install pnpm - uses: pnpm/action-setup@v2.0.1 - with: - version: 6.15.1 - - - name: Set node version to 16 - uses: actions/setup-node@v2 - with: - node-version: 16 - cache: 'pnpm' - - - run: pnpm install - - - name: Run type declaration tests - run: pnpm run test-dts - - size: - runs-on: ubuntu-latest - env: - CI_JOB_NUMBER: 1 - steps: - - uses: actions/checkout@v2 - - - name: Install pnpm - uses: pnpm/action-setup@v2.0.1 - with: - version: 6.15.1 - - - name: Set node version to 16 - uses: actions/setup-node@v2 - with: - node-version: 16 - cache: 'pnpm' - - - run: pnpm install - - run: pnpm run size - - # - name: Check build size - # uses: posva/size-check-action@v1.1.2 - # with: - # github_token: ${{ secrets.GITHUB_TOKEN }} - # build_script: size - # files: packages/vue/dist/vue.global.prod.js packages/runtime-dom/dist/runtime-dom.global.prod.js packages/size-check/dist/index.js + - name: Release + run: pnpx pkg-pr-new publish --compact --pnpm './packages/*' diff --git a/.github/workflows/close-cant-reproduce-issues.yml b/.github/workflows/close-cant-reproduce-issues.yml new file mode 100644 index 000000000..8fb48f842 --- /dev/null +++ b/.github/workflows/close-cant-reproduce-issues.yml @@ -0,0 +1,21 @@ +name: Auto close issues with "can't reproduce" label + +on: + schedule: + - cron: '0 0 * * *' + +permissions: + issues: write + +jobs: + close-issues: + if: github.repository == 'vuejs/core' + runs-on: ubuntu-latest + steps: + - name: can't reproduce + uses: actions-cool/issues-helper@v3 + with: + actions: 'close-issues' + token: ${{ secrets.GITHUB_TOKEN }} + labels: "can't reproduce" + inactive-day: 3 diff --git a/.github/workflows/ecosystem-ci-trigger.yml b/.github/workflows/ecosystem-ci-trigger.yml new file mode 100644 index 000000000..b3e963ece --- /dev/null +++ b/.github/workflows/ecosystem-ci-trigger.yml @@ -0,0 +1,90 @@ +name: ecosystem-ci trigger + +on: + issue_comment: + types: [created] + +jobs: + trigger: + runs-on: ubuntu-latest + if: github.repository == 'vuejs/core' && github.event.issue.pull_request && startsWith(github.event.comment.body, '/ecosystem-ci run') + steps: + - name: Check user permission + uses: actions/github-script@v7 + with: + script: | + const user = context.payload.sender.login + console.log(`Validate user: ${user}`) + + let isVuejsMember = false + try { + const { status } = await github.rest.orgs.checkMembershipForUser({ + org: 'vuejs', + username: user + }); + + isVuejsMember = (status === 204) + } catch (e) {} + + if (isVuejsMember) { + console.log('Allowed') + await github.rest.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: '+1', + }) + } else { + console.log('Not allowed') + await github.rest.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: '-1', + }) + throw new Error('not allowed') + } + - name: Get PR info + uses: actions/github-script@v7 + id: get-pr-data + with: + script: | + console.log(`Get PR info: ${context.repo.owner}/${context.repo.repo}#${context.issue.number}`) + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number + }) + return { + num: context.issue.number, + branchName: pr.head.ref, + repo: pr.head.repo.full_name, + commit: pr.head.sha + } + - name: Trigger run + uses: actions/github-script@v7 + id: trigger + env: + COMMENT: ${{ github.event.comment.body }} + with: + github-token: ${{ secrets.ECOSYSTEM_CI_ACCESS_TOKEN }} + result-encoding: string + script: | + const comment = process.env.COMMENT.trim() + const prData = ${{ steps.get-pr-data.outputs.result }} + + const suite = comment.replace(/^\/ecosystem-ci run/, '').trim() + + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: 'ecosystem-ci', + workflow_id: 'ecosystem-ci-from-pr.yml', + ref: 'main', + inputs: { + prNumber: '' + prData.num, + branchName: prData.branchName, + repo: prData.repo, + suite: suite === '' ? '-' : suite, + commit: prData.commit + } + }) diff --git a/.github/workflows/lock-closed-issues.yml b/.github/workflows/lock-closed-issues.yml new file mode 100644 index 000000000..68a7d6c7a --- /dev/null +++ b/.github/workflows/lock-closed-issues.yml @@ -0,0 +1,20 @@ +name: Lock Closed Issues + +on: + schedule: + - cron: '0 0 * * *' + +permissions: + issues: write + +jobs: + action: + if: github.repository == 'vuejs/core' + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v5 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + issue-inactive-days: '14' + issue-lock-reason: '' + process-only: 'issues' diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml deleted file mode 100644 index 8781b44c8..000000000 --- a/.github/workflows/release-tag.yml +++ /dev/null @@ -1,23 +0,0 @@ -on: - push: - tags: - - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 - -name: Create Release - -jobs: - build: - name: Create Release - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@master - - name: Create Release for Tag - id: release_tag - uses: yyx990803/release-tag@master - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - body: | - Please refer to [CHANGELOG.md](https://github.com/vuejs/vue-next/blob/master/CHANGELOG.md) for details. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..c260a728e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,55 @@ +name: Release + +on: + push: + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + +jobs: + test: + uses: ./.github/workflows/test.yml + + release: + # prevents this action from running on forks + if: github.repository == 'vuejs/core' + needs: [test] + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write + # Use Release environment for deployment protection + environment: Release + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.node-version' + registry-url: 'https://registry.npmjs.org' + cache: 'pnpm' + + - name: Install deps + run: pnpm install + + - name: Build and publish + id: publish + run: | + pnpm release --publishOnly + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Create GitHub release + id: release_tag + uses: yyx990803/release-tag@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + body: | + For stable releases, please refer to [CHANGELOG.md](https://github.com/vuejs/core/blob/main/CHANGELOG.md) for details. + For pre-releases, please refer to [CHANGELOG.md](https://github.com/vuejs/core/blob/minor/CHANGELOG.md) of the `minor` branch. diff --git a/.github/workflows/size-data.yml b/.github/workflows/size-data.yml new file mode 100644 index 000000000..7f8bf7b08 --- /dev/null +++ b/.github/workflows/size-data.yml @@ -0,0 +1,51 @@ +name: size data + +on: + push: + branches: + - main + - minor + pull_request: + branches: + - main + - minor + +permissions: + contents: read + +env: + PUPPETEER_SKIP_DOWNLOAD: 'true' + +jobs: + upload: + if: github.repository == 'vuejs/core' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4.0.0 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.node-version' + cache: pnpm + + - name: Install dependencies + run: pnpm install + + - run: pnpm run size + + - name: Save PR number & base branch + if: ${{github.event_name == 'pull_request'}} + run: | + echo ${{ github.event.number }} > ./temp/size/number.txt + echo ${{ github.base_ref }} > ./temp/size/base.txt + + - name: Upload Size Data + uses: actions/upload-artifact@v4 + with: + name: size-data + path: temp/size diff --git a/.github/workflows/size-report.yml b/.github/workflows/size-report.yml new file mode 100644 index 000000000..f9d2052b6 --- /dev/null +++ b/.github/workflows/size-report.yml @@ -0,0 +1,85 @@ +name: size report + +on: + workflow_run: + workflows: ['size data'] + types: + - completed + +permissions: + contents: read + pull-requests: write + issues: write + +env: + PUPPETEER_SKIP_DOWNLOAD: 'true' + +jobs: + size-report: + runs-on: ubuntu-latest + if: > + github.repository == 'vuejs/core' && + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' + steps: + - uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4.0.0 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.node-version' + cache: pnpm + + - name: Install dependencies + run: pnpm install + + - name: Download Size Data + uses: dawidd6/action-download-artifact@v6 + with: + name: size-data + run_id: ${{ github.event.workflow_run.id }} + path: temp/size + + - name: Read PR Number + id: pr-number + uses: juliangruber/read-file-action@v1 + with: + path: temp/size/number.txt + + - name: Read base branch + id: pr-base + uses: juliangruber/read-file-action@v1 + with: + path: temp/size/base.txt + + - name: Download Previous Size Data + uses: dawidd6/action-download-artifact@v6 + with: + branch: ${{ steps.pr-base.outputs.content }} + workflow: size-data.yml + event: push + name: size-data + path: temp/size-prev + if_no_artifact_found: warn + + - name: Prepare report + run: node scripts/size-report.js > size-report.md + + - name: Read Size Report + id: size-report + uses: juliangruber/read-file-action@v1 + with: + path: ./size-report.md + + - name: Create Comment + uses: actions-cool/maintain-one-comment@v3 + with: + token: ${{ secrets.GITHUB_TOKEN }} + number: ${{ steps.pr-number.outputs.content }} + body: | + ${{ steps.size-report.outputs.content }} + + body-include: '' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..70dc82248 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,108 @@ +name: 'test' + +on: workflow_call + +permissions: + contents: read # to fetch code (actions/checkout) + +jobs: + unit-test: + runs-on: ubuntu-latest + env: + PUPPETEER_SKIP_DOWNLOAD: 'true' + steps: + - uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4.0.0 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.node-version' + cache: 'pnpm' + + - run: pnpm install + + - name: Run unit tests + run: pnpm run test-unit + + unit-test-windows: + runs-on: windows-latest + env: + PUPPETEER_SKIP_DOWNLOAD: 'true' + steps: + - uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4.0.0 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.node-version' + cache: 'pnpm' + + - run: pnpm install + + - name: Run compiler unit tests + run: pnpm run test-unit compiler + + - name: Run ssr unit tests + run: pnpm run test-unit server-renderer + + e2e-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Setup cache for Chromium binary + uses: actions/cache@v4 + with: + path: ~/.cache/puppeteer + key: chromium-${{ hashFiles('pnpm-lock.yaml') }} + + - name: Install pnpm + uses: pnpm/action-setup@v4.0.0 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.node-version' + cache: 'pnpm' + + - run: pnpm install + - run: node node_modules/puppeteer/install.mjs + + - name: Run e2e tests + run: pnpm run test-e2e + + - name: verify treeshaking + run: node scripts/verify-treeshaking.js + + lint-and-test-dts: + runs-on: ubuntu-latest + env: + PUPPETEER_SKIP_DOWNLOAD: 'true' + steps: + - uses: actions/checkout@v4 + + - name: Install pnpm + uses: pnpm/action-setup@v4.0.0 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version-file: '.node-version' + cache: 'pnpm' + + - run: pnpm install + + - name: Run eslint + run: pnpm run lint + + - name: Run prettier + run: pnpm run format-check + + - name: Run type declaration tests + run: pnpm run test-dts diff --git a/.gitignore b/.gitignore index 1487e3b7c..9dd21f59b 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ explorations TODOs.md *.log .idea +.eslintcache +dts-build/packages +*.tsbuildinfo +*.tgz diff --git a/.node-version b/.node-version new file mode 100644 index 000000000..209e3ef4b --- /dev/null +++ b/.node-version @@ -0,0 +1 @@ +20 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..ca3c40849 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +dist +pnpm-lock.yaml +CHANGELOG*.md diff --git a/.prettierrc b/.prettierrc index ef93d9482..759232e7c 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,5 +1,5 @@ -semi: false -singleQuote: true -printWidth: 80 -trailingComma: 'none' -arrowParens: 'avoid' +{ + "semi": false, + "singleQuote": true, + "arrowParens": "avoid" +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000..91ebd5692 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["vitest.explorer"] +} diff --git a/.vscode/launch.json b/.vscode/launch.json index b63ffc79b..9fc03aa9b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,24 +5,15 @@ "version": "0.2.0", "configurations": [ { - "name": "Jest", "type": "node", "request": "launch", - "program": "${workspaceFolder}/node_modules/.bin/jest", - "stopOnEntry": false, - "args": ["${fileBasename}", "--runInBand", "--detectOpenHandles"], - "cwd": "${workspaceFolder}", - "preLaunchTask": null, - "runtimeExecutable": null, - "runtimeArgs": ["--nolazy"], - "env": { - "NODE_ENV": "development" - }, - "console": "integratedTerminal", - "sourceMaps": true, - "windows": { - "program": "${workspaceFolder}/node_modules/jest/bin/jest", - } + "name": "Vitest - Debug Current Test File", + "autoAttachChildProcesses": true, + "skipFiles": ["/**", "**/node_modules/**"], + "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs", + "args": ["run", "${relativeFile}"], + "smartStep": true, + "console": "integratedTerminal" } ] } diff --git a/BACKERS.md b/BACKERS.md new file mode 100644 index 000000000..d8eb697f9 --- /dev/null +++ b/BACKERS.md @@ -0,0 +1,9 @@ +

Sponsors & Backers

+ +Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of the awesome sponsors and backers listed in this file. If you'd like to join them, please consider [ sponsoring Vue's development](https://vuejs.org/sponsor/). + +

+ + sponsors + +

diff --git a/CHANGELOG.md b/CHANGELOG.md index 777c77960..930c8b590 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,2477 +1,486 @@ -## [3.2.23](https://github.com/vuejs/vue-next/compare/v3.2.22...v3.2.23) (2021-11-26) +## [3.5.12](https://github.com/vuejs/core/compare/v3.5.11...v3.5.12) (2024-10-11) ### Bug Fixes -* **reactivity:** retain readonly proxies when setting as reactive property ([d145128](https://github.com/vuejs/vue-next/commit/d145128ab400f4563eb3727626d0942ea5f4980a)), closes [#4986](https://github.com/vuejs/vue-next/issues/4986) -* **runtime-core:** fix component public instance has check for accessed non-existent properties ([aac0466](https://github.com/vuejs/vue-next/commit/aac0466cb8819fd132fbcc9c4d3e1014c14e2ad8)), closes [#4962](https://github.com/vuejs/vue-next/issues/4962) -* **runtime-core:** handle error in async KeepAlive hooks ([#4978](https://github.com/vuejs/vue-next/issues/4978)) ([820a143](https://github.com/vuejs/vue-next/commit/820a14345798edc0ab673bae8ce3181e479d9cca)) -* **runtime-dom:** fix option element value patching edge case ([#4959](https://github.com/vuejs/vue-next/issues/4959)) ([89b2f92](https://github.com/vuejs/vue-next/commit/89b2f924fc82d7f71dcb8ffbacb386fd5cf9ade2)), closes [#4956](https://github.com/vuejs/vue-next/issues/4956) -* **runtime-dom:** patchDOMProps should not set _value if element is custom element ([#4839](https://github.com/vuejs/vue-next/issues/4839)) ([1701bf3](https://github.com/vuejs/vue-next/commit/1701bf3968f001dd3a2bc9f41e3e7e0f1b13e922)) -* **types:** export ref-macros.d.ts ([1245709](https://github.com/vuejs/vue-next/commit/124570973df4ddfdd38e43bf1e92b9710321e5d9)) -* **types:** fix propType type inference ([#4985](https://github.com/vuejs/vue-next/issues/4985)) ([3c449cd](https://github.com/vuejs/vue-next/commit/3c449cd408840d35987fb32b39737fbf093809d6)), closes [#4983](https://github.com/vuejs/vue-next/issues/4983) -* **types:** scrip-setup+ts: ensure proper handling of `null` as default prop value. ([#4979](https://github.com/vuejs/vue-next/issues/4979)) ([f2d2d7b](https://github.com/vuejs/vue-next/commit/f2d2d7b2d236f256531ae9ad2048bd939c92d834)), closes [#4868](https://github.com/vuejs/vue-next/issues/4868) +* **compiler-dom:** avoid stringify option with null value ([#12096](https://github.com/vuejs/core/issues/12096)) ([f6d9926](https://github.com/vuejs/core/commit/f6d99262364b7444ebab8742158599e8cdd79eaa)), closes [#12093](https://github.com/vuejs/core/issues/12093) +* **compiler-sfc:** do not skip TSInstantiationExpression when transforming props destructure ([#12064](https://github.com/vuejs/core/issues/12064)) ([d3ecde8](https://github.com/vuejs/core/commit/d3ecde8a696ff62c8d0ab067fd1d7ee0565b63c5)) +* **compiler-sfc:** use sass modern api if available and avoid deprecation warning ([#11992](https://github.com/vuejs/core/issues/11992)) ([4474c11](https://github.com/vuejs/core/commit/4474c113d1fb1c26298dd6794275d5b5c7cc4d93)) +* **compiler:** clone loc to `ifNode` ([#12131](https://github.com/vuejs/core/issues/12131)) ([cde2c06](https://github.com/vuejs/core/commit/cde2c0671b00d4f6111fcbd7aa76e45872f20b0c)), closes [vuejs/language-tools#4911](https://github.com/vuejs/language-tools/issues/4911) +* **custom-element:** properly remove hyphenated attribute ([#12143](https://github.com/vuejs/core/issues/12143)) ([e16e9a7](https://github.com/vuejs/core/commit/e16e9a7341e7cfb3c443da4e5e5b06e8158712c3)), closes [#12139](https://github.com/vuejs/core/issues/12139) +* **defineModel:** handle kebab-case model correctly ([#12063](https://github.com/vuejs/core/issues/12063)) ([c0418a3](https://github.com/vuejs/core/commit/c0418a3b8fa96a0b108ab71b7aab5d3388f90557)), closes [#12060](https://github.com/vuejs/core/issues/12060) +* **deps:** update dependency monaco-editor to ^0.52.0 ([#12119](https://github.com/vuejs/core/issues/12119)) ([f7cbea2](https://github.com/vuejs/core/commit/f7cbea2111c7770a180b640f36f6a5d4d6abc698)) +* **hydration:** provide compat fallback for idle callback hydration strategy ([#11935](https://github.com/vuejs/core/issues/11935)) ([1ae545a](https://github.com/vuejs/core/commit/1ae545a3786abef983be1c969726489685569c92)) +* **reactivity:** trigger reactivity for Map key `undefined` ([#12055](https://github.com/vuejs/core/issues/12055)) ([7ad289e](https://github.com/vuejs/core/commit/7ad289e1e7fea654524008ff91e43a8b8a55ef22)), closes [#12054](https://github.com/vuejs/core/issues/12054) +* **runtime-core:** allow symbol values for slot prop key ([#12069](https://github.com/vuejs/core/issues/12069)) ([d9d4d4e](https://github.com/vuejs/core/commit/d9d4d4e158cd51a9ddda249f29de8467f60b2792)), closes [#12068](https://github.com/vuejs/core/issues/12068) +* **runtime-core:** fix required prop check false positive for kebab-case edge cases ([#12034](https://github.com/vuejs/core/issues/12034)) ([9da1ac1](https://github.com/vuejs/core/commit/9da1ac156552ac449754e1373aac7e349841becb)), closes [#12011](https://github.com/vuejs/core/issues/12011) +* **runtime-dom:** prevent unnecessary updates in v-model checkbox when value is unchanged ([#12146](https://github.com/vuejs/core/issues/12146)) ([ea943af](https://github.com/vuejs/core/commit/ea943afe404c4ca4b729906c5e8daf7aa2ccde9b)), closes [#12144](https://github.com/vuejs/core/issues/12144) +* **teleport:** handle disabled teleport with updateCssVars ([#12113](https://github.com/vuejs/core/issues/12113)) ([76a8223](https://github.com/vuejs/core/commit/76a8223199c148b79a5c0ea19e235164809760cd)), closes [#12112](https://github.com/vuejs/core/issues/12112) +* **transition/ssr:** make transition appear work with Suspense in SSR ([#12047](https://github.com/vuejs/core/issues/12047)) ([f1a4f67](https://github.com/vuejs/core/commit/f1a4f67aedfe83e440c54222213f070774faa421)), closes [#12046](https://github.com/vuejs/core/issues/12046) +* **types:** ensure `this.$props` type does not include `string` ([#12123](https://github.com/vuejs/core/issues/12123)) ([704173e](https://github.com/vuejs/core/commit/704173e24276706de672cca6c9507e4dd9651197)), closes [#12122](https://github.com/vuejs/core/issues/12122) +* **types:** retain union type narrowing with defaults applied ([#12108](https://github.com/vuejs/core/issues/12108)) ([05685a9](https://github.com/vuejs/core/commit/05685a9d7c42d4cd37169b867833776b91154fed)), closes [#12106](https://github.com/vuejs/core/issues/12106) +* **useId:** ensure useId consistency when using serverPrefetch ([#12128](https://github.com/vuejs/core/issues/12128)) ([b4d3534](https://github.com/vuejs/core/commit/b4d35349d8bc39aa15bd3f1094d230e5928b177c)), closes [#12102](https://github.com/vuejs/core/issues/12102) +* **watch:** watchEffect clean-up with SSR ([#12097](https://github.com/vuejs/core/issues/12097)) ([b094c72](https://github.com/vuejs/core/commit/b094c72b3d40c52c7124f145a9db028509a11202)), closes [#11956](https://github.com/vuejs/core/issues/11956) -### Features - -* **compiler-sfc:** export resolveTemplateUsageCheckString for HMR plugin use ([#4908](https://github.com/vuejs/vue-next/issues/4908)) ([c61baac](https://github.com/vuejs/vue-next/commit/c61baac75a03b938bc728a8de961ba93736a0ff6)) -* **compiler-sfc:** expose properties for more accurate HMR ([68c45e7](https://github.com/vuejs/vue-next/commit/68c45e73da902e715df9614800a7ab43d6579198)), closes [#4358](https://github.com/vuejs/vue-next/issues/4358) [#4908](https://github.com/vuejs/vue-next/issues/4908) - - - -## [3.2.22](https://github.com/vuejs/vue-next/compare/v3.2.21...v3.2.22) (2021-11-15) - - -### Bug Fixes - -* **compiler-sfc:** add type for props include Function in prod mode ([#4938](https://github.com/vuejs/vue-next/issues/4938)) ([9c42a1e](https://github.com/vuejs/vue-next/commit/9c42a1e2a3385f3b33faed5cdcc430bf8c1fc4b2)) -* **compiler-sfc:** add type for props's properties in prod mode ([#4790](https://github.com/vuejs/vue-next/issues/4790)) ([090df08](https://github.com/vuejs/vue-next/commit/090df0837eb0aedd8a02fd0107b7668ca5c136a1)), closes [#4783](https://github.com/vuejs/vue-next/issues/4783) -* **compiler-sfc:** externalRE support automatic http/https prefix url pattern ([#4922](https://github.com/vuejs/vue-next/issues/4922)) ([574070f](https://github.com/vuejs/vue-next/commit/574070f43f804fd855f4ee319936ec770a56cef0)), closes [#4920](https://github.com/vuejs/vue-next/issues/4920) -* **compiler-sfc:** fix expose codegen edge case ([#4919](https://github.com/vuejs/vue-next/issues/4919)) ([31fd590](https://github.com/vuejs/vue-next/commit/31fd590fd47e2dc89b84687ffe26a5c6f05fea34)), closes [#4917](https://github.com/vuejs/vue-next/issues/4917) -* **devtool:** improve devtools late injection browser env detection ([#4890](https://github.com/vuejs/vue-next/issues/4890)) ([fa2237f](https://github.com/vuejs/vue-next/commit/fa2237f1d824eac511c4246135318594c48dc121)) -* **runtime-core:** improve dedupe listeners when attr fallthrough ([#4912](https://github.com/vuejs/vue-next/issues/4912)) ([b4eb7e3](https://github.com/vuejs/vue-next/commit/b4eb7e3866d7dc722d93a48f4faae1696d4e7023)), closes [#4859](https://github.com/vuejs/vue-next/issues/4859) -* **types/sfc:** fix withDefaults type inference when using union types ([#4925](https://github.com/vuejs/vue-next/issues/4925)) ([04e5835](https://github.com/vuejs/vue-next/commit/04e58351965caf489ac68e4961ef70448d954912)) - - - -## [3.2.21](https://github.com/vuejs/vue-next/compare/v3.2.20...v3.2.21) (2021-11-02) - - -### Bug Fixes - -* **custom-element:** fix custom element props access on initial render ([4b7f76e](https://github.com/vuejs/vue-next/commit/4b7f76e36a7fc650986a20eca258f7a5d912424f)), closes [#4792](https://github.com/vuejs/vue-next/issues/4792) -* **custom-element:** fix initial attr type casting for programmtically created elements ([3ca8317](https://github.com/vuejs/vue-next/commit/3ca83179d1a798f65e4e70215c511e2f1b64adb6)), closes [#4772](https://github.com/vuejs/vue-next/issues/4772) -* **devtools:** avoid open handle in non-browser env ([6916d72](https://github.com/vuejs/vue-next/commit/6916d725a06a57e92ff9d046ccf132c305cd0a51)), closes [#4815](https://github.com/vuejs/vue-next/issues/4815) -* **devtools:** fix memory leak when devtools is not installed ([#4833](https://github.com/vuejs/vue-next/issues/4833)) ([6b32f0d](https://github.com/vuejs/vue-next/commit/6b32f0d976c0aac8bb2c1b78fedd03e76fb391eb)), closes [#4829](https://github.com/vuejs/vue-next/issues/4829) -* **runtime-core:** add `v-memo` to built-in directives check ([#4787](https://github.com/vuejs/vue-next/issues/4787)) ([5eb7263](https://github.com/vuejs/vue-next/commit/5eb72630a53a8dd82c2b8a9705c21a8075161a3d)) -* **runtime-dom:** fix behavior regression for v-show + style display binding ([3f38d59](https://github.com/vuejs/vue-next/commit/3f38d599f5aacdd3eeaa9475251a24f74e7ae3b4)), closes [#4768](https://github.com/vuejs/vue-next/issues/4768) -* **types:** fix ref unwrapping type inference for nested shallowReactive & shallowRef ([20a3615](https://github.com/vuejs/vue-next/commit/20a361541cc5faffa82cbf3f2d49639a97b3b678)), closes [#4771](https://github.com/vuejs/vue-next/issues/4771) - - - -## [3.2.20](https://github.com/vuejs/vue-next/compare/v3.2.19...v3.2.20) (2021-10-08) - - -### Bug Fixes - -* **compiler-sfc:** fix props codegen w/ leading import ([d4c04e9](https://github.com/vuejs/vue-next/commit/d4c04e979934b81a30467aa4b1e717175b9b2d80)), closes [#4764](https://github.com/vuejs/vue-next/issues/4764) -* **compiler-sfc:** support runtime Enum in normal script ([#4698](https://github.com/vuejs/vue-next/issues/4698)) ([f66d456](https://github.com/vuejs/vue-next/commit/f66d456b7a39db9dae7e70c28bb431ff293d8fef)) -* **devtools:** clear devtools buffer after timeout ([f4639e0](https://github.com/vuejs/vue-next/commit/f4639e0a36abe16828b202d7297e1486653b1217)), closes [#4738](https://github.com/vuejs/vue-next/issues/4738) -* **hmr:** fix hmr for components with no active instance yet ([9e3d773](https://github.com/vuejs/vue-next/commit/9e3d7731c7839638f49157123c6b372fec9e4d46)), closes [#4757](https://github.com/vuejs/vue-next/issues/4757) -* **types:** ensure that DeepReadonly handles Ref type properly ([#4714](https://github.com/vuejs/vue-next/issues/4714)) ([ed0071a](https://github.com/vuejs/vue-next/commit/ed0071ac1a6d18439f3212711c6901fbb7193288)) -* **types:** make `toRef` return correct type(fix [#4732](https://github.com/vuejs/vue-next/issues/4732)) ([#4734](https://github.com/vuejs/vue-next/issues/4734)) ([925bc34](https://github.com/vuejs/vue-next/commit/925bc346fe85091467fcd2e40d6c1ff07f3b51c4)) - - -### Features - -* **compiler-sfc:** `` -- In-browser playground on [Codepen](https://codepen.io/yyx990803/pen/OJNoaZL) -- Scaffold via [Vite](https://github.com/vitejs/vite): +## Sponsors - ```bash - # npm 6.x - npm init vite@latest my-vue-app --template vue - # npm 7+, extra double-dash is needed: - npm init vite@latest my-vue-app -- --template vue - # yarn - yarn create vite my-vue-app --template vue - ``` +Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome [backers](https://github.com/vuejs/core/blob/main/BACKERS.md). If you'd like to join them, please consider [ sponsoring Vue's development](https://vuejs.org/sponsor/). -- Scaffold via [vue-cli](https://cli.vuejs.org/): +

+

Special Sponsor

+

- ```bash - npm install -g @vue/cli # OR yarn global add @vue/cli - vue create hello-vue3 - # select vue 3 preset - ``` +

+ + special sponsor appwrite + +

-## Changes from Vue 2 +

+ + sponsors + +

-Please consult the [Migration Guide](https://v3.vuejs.org/guide/migration/introduction.html). +## Questions -Also note: Vue 3 does not support IE11 ([RFC](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0038-vue3-ie11-support.md) | [Discussion](https://github.com/vuejs/rfcs/discussions/296)). +For questions and support please use [the official forum](https://forum.vuejs.org) or [community chat](https://chat.vuejs.org/). The issue list of this repo is **exclusively** for bug reports and feature requests. -## Supporting Libraries +## Issues -All of our official libraries and tools now support Vue 3, but most of them are still in beta status and distributed under the `next` dist tag on NPM. **We are planning to stabilize and switch all projects to use the `latest` dist tag in early 2021.** +Please make sure to respect issue requirements and use [the new issue helper](https://new-issue.vuejs.org/) when opening an issue. Issues not conforming to the guidelines may be closed immediately. -### Vue CLI +## Stay In Touch -As of v4.5.0, `vue-cli` now provides built-in option to choose Vue 3 preset when creating a new project. You can upgrade `vue-cli` and run `vue create` to create a Vue 3 project today. +- [Twitter](https://twitter.com/vuejs) +- [Blog](https://blog.vuejs.org/) +- [Job Board](https://vuejobs.com/?ref=vuejs) -### Vue Router +## Contribution -Vue Router 4.0 provides Vue 3 support and has a number of breaking changes of its own. Check out its [Migration Guide](https://next.router.vuejs.org/guide/migration/) for full details. +Please make sure to read the [Contributing Guide](https://github.com/vuejs/core/blob/main/.github/contributing.md) before making a pull request. If you have a Vue-related project/component/tool, add it with a pull request to [this curated list](https://github.com/vuejs/awesome-vue)! -- [![beta](https://img.shields.io/npm/v/vue-router/next.svg)](https://www.npmjs.com/package/vue-router/v/next) -- [GitHub](https://github.com/vuejs/vue-router-next) -- [RFCs](https://github.com/vuejs/rfcs/pulls?q=is%3Apr+is%3Amerged+label%3Arouter) +Thank you to all the people who already contributed to Vue! -### Vuex + -Vuex 4.0 provides Vue 3 support with largely the same API as 3.x. The only breaking change is [how the plugin is installed](https://github.com/vuejs/vuex/tree/4.0#breaking-changes). +## License -- [![beta](https://img.shields.io/npm/v/vuex/next.svg)](https://www.npmjs.com/package/vuex/v/next) -- [GitHub](https://github.com/vuejs/vuex/tree/4.0) +[MIT](https://opensource.org/licenses/MIT) -### Devtools Extension - -We are working on a new version of the Devtools with a new UI and refactored internals to support multiple Vue versions. The new version is currently in beta and only supports Vue 3 (for now). Vuex and Router integration is also work in progress. - -- For Chrome: [Install from Chrome web store](https://chrome.google.com/webstore/detail/vuejs-devtools/ljjemllljcmogpfapbkkighbhhppjdbg?hl=en) - - - Note: the beta channel may conflict with the stable version of devtools so you may need to temporarily disable the stable version for the beta channel to work properly. - -- For Firefox: [Download the signed extension](https://github.com/vuejs/vue-devtools/releases/tag/v6.0.0-beta.2) (`.xpi` file under Assets) - -### IDE Support - -It is recommended to use [VSCode](https://code.visualstudio.com/). There are currently two viable extensions for Single-File Components (SFCs) support: - -- [Vetur](https://marketplace.visualstudio.com/items?itemName=octref.vetur) (recommended if you are used to Vetur features) -- [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) (recommended if using TypeScript with SFCs, or ` + + + + diff --git a/packages-private/sfc-playground/src/Header.vue b/packages-private/sfc-playground/src/Header.vue new file mode 100644 index 000000000..aea6c022a --- /dev/null +++ b/packages-private/sfc-playground/src/Header.vue @@ -0,0 +1,317 @@ + + + + + diff --git a/packages-private/sfc-playground/src/VersionSelect.vue b/packages-private/sfc-playground/src/VersionSelect.vue new file mode 100644 index 000000000..3a30e497f --- /dev/null +++ b/packages-private/sfc-playground/src/VersionSelect.vue @@ -0,0 +1,151 @@ + + + + + diff --git a/packages/sfc-playground/src/download/download.ts b/packages-private/sfc-playground/src/download/download.ts similarity index 75% rename from packages/sfc-playground/src/download/download.ts rename to packages-private/sfc-playground/src/download/download.ts index dd7e3761d..28d836edb 100644 --- a/packages/sfc-playground/src/download/download.ts +++ b/packages-private/sfc-playground/src/download/download.ts @@ -5,8 +5,9 @@ import main from './template/main.js?raw' import pkg from './template/package.json?raw' import config from './template/vite.config.js?raw' import readme from './template/README.md?raw' +import type { ReplStore } from '@vue/repl' -export async function downloadProject(store: any) { +export async function downloadProject(store: ReplStore) { if (!confirm('Download project files?')) { return } @@ -26,7 +27,11 @@ export async function downloadProject(store: any) { const files = store.getFiles() for (const file in files) { - src.file(file, files[file]) + if (file !== 'import-map.json' && file !== 'tsconfig.json') { + src.file(file, files[file]) + } else { + zip.file(file, files[file]) + } } const blob = await zip.generateAsync({ type: 'blob' }) diff --git a/packages/sfc-playground/src/download/template/README.md b/packages-private/sfc-playground/src/download/template/README.md similarity index 60% rename from packages/sfc-playground/src/download/template/README.md rename to packages-private/sfc-playground/src/download/template/README.md index 39c47d255..91b21489f 100644 --- a/packages/sfc-playground/src/download/template/README.md +++ b/packages-private/sfc-playground/src/download/template/README.md @@ -1,6 +1,6 @@ # Vite Vue Starter -This is a project template using [Vite](https://vitejs.dev/). It requires [Node.js](https://nodejs.org) v12+. +This is a project template using [Vite](https://vitejs.dev/). It requires [Node.js](https://nodejs.org) version 18+ or 20+. To start: @@ -11,4 +11,8 @@ npm run dev # if using yarn: yarn yarn dev + +# if using pnpm: +pnpm install +pnpm run dev ``` diff --git a/packages/sfc-playground/src/download/template/index.html b/packages-private/sfc-playground/src/download/template/index.html similarity index 95% rename from packages/sfc-playground/src/download/template/index.html rename to packages-private/sfc-playground/src/download/template/index.html index 030a6ff51..e631329c1 100644 --- a/packages/sfc-playground/src/download/template/index.html +++ b/packages-private/sfc-playground/src/download/template/index.html @@ -1,4 +1,4 @@ - + diff --git a/packages/sfc-playground/src/download/template/main.js b/packages-private/sfc-playground/src/download/template/main.js similarity index 100% rename from packages/sfc-playground/src/download/template/main.js rename to packages-private/sfc-playground/src/download/template/main.js diff --git a/packages/sfc-playground/src/download/template/package.json b/packages-private/sfc-playground/src/download/template/package.json similarity index 63% rename from packages/sfc-playground/src/download/template/package.json rename to packages-private/sfc-playground/src/download/template/package.json index 4f6bdd4a4..1e8c5d68c 100644 --- a/packages/sfc-playground/src/download/template/package.json +++ b/packages-private/sfc-playground/src/download/template/package.json @@ -1,17 +1,17 @@ { "name": "vite-vue-starter", "version": "0.0.0", + "type": "module", "scripts": { "dev": "vite", "build": "vite build", "serve": "vite preview" }, "dependencies": { - "vue": "^3.2.0" + "vue": "^3.4.0" }, "devDependencies": { - "@vitejs/plugin-vue": "^1.4.0", - "@vue/compiler-sfc": "^3.2.0", - "vite": "^2.4.4" + "@vitejs/plugin-vue": "^5.1.4", + "vite": "^5.4.9" } -} \ No newline at end of file +} diff --git a/packages/sfc-playground/src/download/template/vite.config.js b/packages-private/sfc-playground/src/download/template/vite.config.js similarity index 87% rename from packages/sfc-playground/src/download/template/vite.config.js rename to packages-private/sfc-playground/src/download/template/vite.config.js index 315212d69..05c17402a 100644 --- a/packages/sfc-playground/src/download/template/vite.config.js +++ b/packages-private/sfc-playground/src/download/template/vite.config.js @@ -3,5 +3,5 @@ import vue from '@vitejs/plugin-vue' // https://vitejs.dev/config/ export default defineConfig({ - plugins: [vue()] + plugins: [vue()], }) diff --git a/packages-private/sfc-playground/src/icons/Copy.vue b/packages-private/sfc-playground/src/icons/Copy.vue new file mode 100644 index 000000000..f3851da63 --- /dev/null +++ b/packages-private/sfc-playground/src/icons/Copy.vue @@ -0,0 +1,14 @@ + diff --git a/packages/sfc-playground/src/icons/Download.vue b/packages-private/sfc-playground/src/icons/Download.vue similarity index 88% rename from packages/sfc-playground/src/icons/Download.vue rename to packages-private/sfc-playground/src/icons/Download.vue index a7c4ed184..c5caec709 100644 --- a/packages/sfc-playground/src/icons/Download.vue +++ b/packages-private/sfc-playground/src/icons/Download.vue @@ -1,6 +1,6 @@ diff --git a/packages-private/sfc-playground/src/icons/Moon.vue b/packages-private/sfc-playground/src/icons/Moon.vue new file mode 100644 index 000000000..21f393d4d --- /dev/null +++ b/packages-private/sfc-playground/src/icons/Moon.vue @@ -0,0 +1,8 @@ + diff --git a/packages-private/sfc-playground/src/icons/Reload.vue b/packages-private/sfc-playground/src/icons/Reload.vue new file mode 100644 index 000000000..5ec5be808 --- /dev/null +++ b/packages-private/sfc-playground/src/icons/Reload.vue @@ -0,0 +1,14 @@ + diff --git a/packages/sfc-playground/src/icons/Share.vue b/packages-private/sfc-playground/src/icons/Share.vue similarity index 93% rename from packages/sfc-playground/src/icons/Share.vue rename to packages-private/sfc-playground/src/icons/Share.vue index 829fcbe23..8dd9ccd84 100644 --- a/packages/sfc-playground/src/icons/Share.vue +++ b/packages-private/sfc-playground/src/icons/Share.vue @@ -2,7 +2,7 @@ + + + + + + + + + + + + diff --git a/packages/sfc-playground/src/main.ts b/packages-private/sfc-playground/src/main.ts similarity index 72% rename from packages/sfc-playground/src/main.ts rename to packages-private/sfc-playground/src/main.ts index e645bb2bd..7be634080 100644 --- a/packages/sfc-playground/src/main.ts +++ b/packages-private/sfc-playground/src/main.ts @@ -1,10 +1,9 @@ import { createApp } from 'vue' import App from './App.vue' -import '@vue/repl/style.css' // @ts-expect-error Custom window property window.VUE_DEVTOOLS_CONFIG = { - defaultSelectedAppId: 'id:repl' + defaultSelectedAppId: 'repl', } createApp(App).mount('#app') diff --git a/packages-private/sfc-playground/src/vue-dev-proxy-prod.ts b/packages-private/sfc-playground/src/vue-dev-proxy-prod.ts new file mode 100644 index 000000000..3b2faf195 --- /dev/null +++ b/packages-private/sfc-playground/src/vue-dev-proxy-prod.ts @@ -0,0 +1,2 @@ +// serve vue to the iframe sandbox during dev. +export * from 'vue/dist/vue.runtime.esm-browser.prod.js' diff --git a/packages/sfc-playground/src/vue-dev-proxy.ts b/packages-private/sfc-playground/src/vue-dev-proxy.ts similarity index 100% rename from packages/sfc-playground/src/vue-dev-proxy.ts rename to packages-private/sfc-playground/src/vue-dev-proxy.ts diff --git a/packages-private/sfc-playground/src/vue-server-renderer-dev-proxy.ts b/packages-private/sfc-playground/src/vue-server-renderer-dev-proxy.ts new file mode 100644 index 000000000..f2ceb2656 --- /dev/null +++ b/packages-private/sfc-playground/src/vue-server-renderer-dev-proxy.ts @@ -0,0 +1,2 @@ +// serve vue/server-renderer to the iframe sandbox during dev. +export * from 'vue/server-renderer' diff --git a/packages-private/sfc-playground/vercel.json b/packages-private/sfc-playground/vercel.json new file mode 100644 index 000000000..4511eb79d --- /dev/null +++ b/packages-private/sfc-playground/vercel.json @@ -0,0 +1,16 @@ +{ + "github": { + "silent": true + }, + "headers": [ + { + "source": "/assets/(.*)", + "headers": [ + { + "key": "Cache-Control", + "value": "max-age=31536000, immutable" + } + ] + } + ] +} diff --git a/packages-private/sfc-playground/vite.config.ts b/packages-private/sfc-playground/vite.config.ts new file mode 100644 index 000000000..2e77f1970 --- /dev/null +++ b/packages-private/sfc-playground/vite.config.ts @@ -0,0 +1,59 @@ +import fs from 'node:fs' +import path from 'node:path' +import { type Plugin, defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import { spawnSync } from 'node:child_process' + +const commit = spawnSync('git', ['rev-parse', '--short=7', 'HEAD']) + .stdout.toString() + .trim() + +export default defineConfig({ + plugins: [ + vue({ + script: { + fs: { + fileExists: fs.existsSync, + readFile: file => fs.readFileSync(file, 'utf-8'), + }, + }, + }), + copyVuePlugin(), + ], + define: { + __COMMIT__: JSON.stringify(commit), + __VUE_PROD_DEVTOOLS__: JSON.stringify(true), + }, + optimizeDeps: { + exclude: ['@vue/repl'], + }, +}) + +function copyVuePlugin(): Plugin { + return { + name: 'copy-vue', + generateBundle() { + const copyFile = (file: string) => { + const filePath = path.resolve(__dirname, '../../packages', file) + const basename = path.basename(file) + if (!fs.existsSync(filePath)) { + throw new Error( + `${basename} not built. ` + + `Run "nr build vue -f esm-browser" first.`, + ) + } + this.emitFile({ + type: 'asset', + fileName: basename, + source: fs.readFileSync(filePath, 'utf-8'), + }) + } + + copyFile(`vue/dist/vue.esm-browser.js`) + copyFile(`vue/dist/vue.esm-browser.prod.js`) + copyFile(`vue/dist/vue.runtime.esm-browser.js`) + copyFile(`vue/dist/vue.runtime.esm-browser.prod.js`) + copyFile(`server-renderer/dist/server-renderer.esm-browser.js`) + }, + } +} diff --git a/packages/template-explorer/README.md b/packages-private/template-explorer/README.md similarity index 61% rename from packages/template-explorer/README.md rename to packages-private/template-explorer/README.md index f21443d23..48d125713 100644 --- a/packages/template-explorer/README.md +++ b/packages-private/template-explorer/README.md @@ -7,4 +7,4 @@ To run: - `npm run dev-compiler` in repo root - When the compilation is done, in another terminal run `npm run open` -Note: `index.html` uses CDN for dependencies and is continuously deployed at [https://vue-next-template-explorer.netlify.com/](https://vue-next-template-explorer.netlify.com/). For local development, use the scripts above. +Note: `index.html` uses CDN for dependencies and is continuously deployed at [https://template-explorer.vuejs.org](https://template-explorer.vuejs.org). For local development, use the scripts above. diff --git a/packages-private/template-explorer/_redirects b/packages-private/template-explorer/_redirects new file mode 100644 index 000000000..9d570fb82 --- /dev/null +++ b/packages-private/template-explorer/_redirects @@ -0,0 +1,2 @@ +https://vue-next-template-explorer.netlify.app https://template-explorer.vuejs.org 301! +https://vue-next-template-explorer.netlify.app/* https://template-explorer.vuejs.org/:splat 301! diff --git a/packages-private/template-explorer/index.html b/packages-private/template-explorer/index.html new file mode 100644 index 000000000..d1db969f0 --- /dev/null +++ b/packages-private/template-explorer/index.html @@ -0,0 +1,24 @@ +Vue Template Explorer + + + + +
+
+ + + + + diff --git a/packages-private/template-explorer/local.html b/packages-private/template-explorer/local.html new file mode 100644 index 000000000..c86cdb6b3 --- /dev/null +++ b/packages-private/template-explorer/local.html @@ -0,0 +1,24 @@ +Vue Template Explorer + + + + +
+
+ + + + + diff --git a/packages/template-explorer/package.json b/packages-private/template-explorer/package.json similarity index 73% rename from packages/template-explorer/package.json rename to packages-private/template-explorer/package.json index bf7fc9272..e8bdf0bcc 100644 --- a/packages/template-explorer/package.json +++ b/packages-private/template-explorer/package.json @@ -1,7 +1,7 @@ { "name": "@vue/template-explorer", - "version": "3.2.23", "private": true, + "version": "0.0.0", "buildOptions": { "formats": [ "global" @@ -11,7 +11,7 @@ "enableNonBrowserBranches": true }, "dependencies": { - "monaco-editor": "^0.20.0", - "source-map": "^0.6.1" + "monaco-editor": "^0.52.0", + "source-map-js": "^1.2.1" } } diff --git a/packages/template-explorer/src/index.ts b/packages-private/template-explorer/src/index.ts similarity index 72% rename from packages/template-explorer/src/index.ts rename to packages-private/template-explorer/src/index.ts index d083d35ca..988712d62 100644 --- a/packages/template-explorer/src/index.ts +++ b/packages-private/template-explorer/src/index.ts @@ -1,9 +1,18 @@ -import * as m from 'monaco-editor' -import { compile, CompilerError, CompilerOptions } from '@vue/compiler-dom' +import type * as m from 'monaco-editor' +import { + type CompilerError, + type CompilerOptions, + compile, +} from '@vue/compiler-dom' import { compile as ssrCompile } from '@vue/compiler-ssr' -import { compilerOptions, initOptions, ssrMode } from './options' +import { + compilerOptions, + defaultOptions, + initOptions, + ssrMode, +} from './options' import { toRaw, watchEffect } from '@vue/runtime-dom' -import { SourceMapConsumer } from 'source-map' +import { SourceMapConsumer } from 'source-map-js' import theme from './theme' declare global { @@ -25,8 +34,8 @@ const sharedEditorOptions: m.editor.IStandaloneEditorConstructionOptions = { scrollBeyondLastLine: false, renderWhitespace: 'selection', minimap: { - enabled: false - } + enabled: false, + }, } window.init = () => { @@ -35,14 +44,32 @@ window.init = () => { monaco.editor.defineTheme('my-theme', theme) monaco.editor.setTheme('my-theme') - const persistedState: PersistedState = JSON.parse( - decodeURIComponent(window.location.hash.slice(1)) || - localStorage.getItem('state') || - `{}` - ) + let persistedState: PersistedState | undefined - ssrMode.value = persistedState.ssr - Object.assign(compilerOptions, persistedState.options) + try { + let hash = window.location.hash.slice(1) + try { + hash = escape(atob(hash)) + } catch (e) {} + persistedState = JSON.parse( + decodeURIComponent(hash) || localStorage.getItem('state') || `{}`, + ) + } catch (e: any) { + // bad stored state, clear it + console.warn( + 'Persisted state in localStorage seems to be corrupted, please reload.\n' + + e.message, + ) + localStorage.clear() + } + + if (persistedState) { + // functions are not persistable, so delete it in case we sometimes need + // to debug with custom nodeTransforms + delete persistedState.options?.nodeTransforms + ssrMode.value = persistedState.ssr + Object.assign(compilerOptions, persistedState.options) + } let lastSuccessfulCode: string let lastSuccessfulMap: SourceMapConsumer | undefined = undefined @@ -53,18 +80,18 @@ window.init = () => { const compileFn = ssrMode.value ? ssrCompile : compile const start = performance.now() const { code, ast, map } = compileFn(source, { - filename: 'ExampleTemplate.vue', ...compilerOptions, + filename: 'ExampleTemplate.vue', sourceMap: true, onError: err => { errors.push(err) - } + }, }) console.log(`Compiled in ${(performance.now() - start).toFixed(2)}ms.`) monaco.editor.setModelMarkers( editor.getModel()!, `@vue/compiler-dom`, - errors.filter(e => e.loc).map(formatError) + errors.filter(e => e.loc).map(formatError), ) console.log(`AST: `, ast) console.log(`Options: `, toRaw(compilerOptions)) @@ -87,20 +114,31 @@ window.init = () => { endLineNumber: loc.end.line, endColumn: loc.end.column, message: `Vue template compilation error: ${err.message}`, - code: String(err.code) + code: String(err.code), } } function reCompile() { const src = editor.getValue() // every time we re-compile, persist current state + + const optionsToSave = {} + let key: keyof CompilerOptions + for (key in compilerOptions) { + const val = compilerOptions[key] + if (typeof val !== 'object' && val !== defaultOptions[key]) { + // @ts-expect-error + optionsToSave[key] = val + } + } + const state = JSON.stringify({ src, ssr: ssrMode.value, - options: compilerOptions + options: optionsToSave, } as PersistedState) localStorage.setItem('state', state) - window.location.hash = encodeURIComponent(state) + window.location.hash = btoa(unescape(encodeURIComponent(state))) const res = compileCode(src) if (res) { output.setValue(res) @@ -108,24 +146,24 @@ window.init = () => { } const editor = monaco.editor.create(document.getElementById('source')!, { - value: persistedState.src || `
Hello World!
`, + value: persistedState?.src || `
Hello World
`, language: 'html', ...sharedEditorOptions, - wordWrap: 'bounded' + wordWrap: 'bounded', }) editor.getModel()!.updateOptions({ - tabSize: 2 + tabSize: 2, }) const output = monaco.editor.create(document.getElementById('output')!, { value: '', language: 'javascript', readOnly: true, - ...sharedEditorOptions + ...sharedEditorOptions, }) output.getModel()!.updateOptions({ - tabSize: 2 + tabSize: 2, }) // handle resize @@ -150,7 +188,7 @@ window.init = () => { const pos = lastSuccessfulMap.generatedPositionFor({ source: 'ExampleTemplate.vue', line: e.position.lineNumber, - column: e.position.column - 1 + column: e.position.column - 1, }) if (pos.line != null && pos.column != null) { prevOutputDecos = output.deltaDecorations(prevOutputDecos, [ @@ -159,22 +197,22 @@ window.init = () => { pos.line, pos.column + 1, pos.line, - pos.lastColumn ? pos.lastColumn + 2 : pos.column + 2 + pos.lastColumn ? pos.lastColumn + 2 : pos.column + 2, ), options: { - inlineClassName: `highlight` - } - } + inlineClassName: `highlight`, + }, + }, ]) output.revealPositionInCenter({ lineNumber: pos.line, - column: pos.column + 1 + column: pos.column + 1, }) } else { clearOutputDecos() } } - }, 100) + }, 100), ) let previousEditorDecos: string[] = [] @@ -188,7 +226,7 @@ window.init = () => { if (lastSuccessfulMap) { const pos = lastSuccessfulMap.originalPositionFor({ line: e.position.lineNumber, - column: e.position.column - 1 + column: e.position.column - 1, }) if ( pos.line != null && @@ -200,7 +238,7 @@ window.init = () => { ) { const translatedPos = { column: pos.column + 1, - lineNumber: pos.line + lineNumber: pos.line, } previousEditorDecos = editor.deltaDecorations(previousEditorDecos, [ { @@ -208,20 +246,20 @@ window.init = () => { pos.line, pos.column + 1, pos.line, - pos.column + 1 + pos.column + 1, ), options: { isWholeLine: true, - className: `highlight` - } - } + className: `highlight`, + }, + }, ]) editor.revealPositionInCenter(translatedPos) } else { clearEditorDecos() } } - }, 100) + }, 100), ) initOptions() @@ -230,7 +268,7 @@ window.init = () => { function debounce any>( fn: T, - delay: number = 300 + delay: number = 300, ): T { let prevTimer: number | null = null return ((...args: any[]) => { @@ -241,5 +279,5 @@ function debounce any>( fn(...args) prevTimer = null }, delay) - }) as any + }) as T } diff --git a/packages/template-explorer/src/options.ts b/packages-private/template-explorer/src/options.ts similarity index 84% rename from packages/template-explorer/src/options.ts rename to packages-private/template-explorer/src/options.ts index c5c5eba5a..e3cc6173a 100644 --- a/packages/template-explorer/src/options.ts +++ b/packages-private/template-explorer/src/options.ts @@ -1,10 +1,10 @@ -import { h, reactive, createApp, ref } from 'vue' -import { CompilerOptions } from '@vue/compiler-dom' +import { createApp, h, reactive, ref } from 'vue' +import type { CompilerOptions } from '@vue/compiler-dom' import { BindingTypes } from '@vue/compiler-core' export const ssrMode = ref(false) -export const compilerOptions: CompilerOptions = reactive({ +export const defaultOptions: CompilerOptions = { mode: 'module', filename: 'Foo.vue', prefixIdentifiers: false, @@ -22,9 +22,13 @@ export const compilerOptions: CompilerOptions = reactive({ setupLet: BindingTypes.SETUP_LET, setupMaybeRef: BindingTypes.SETUP_MAYBE_REF, setupProp: BindingTypes.PROPS, - vMySetupDir: BindingTypes.SETUP_CONST - } -}) + vMySetupDir: BindingTypes.SETUP_CONST, + }, +} + +export const compilerOptions: CompilerOptions = reactive( + Object.assign({}, defaultOptions), +) const App = { setup() { @@ -39,19 +43,19 @@ const App = { h( 'a', { - href: `https://github.com/vuejs/vue-next/tree/${__COMMIT__}`, - target: `_blank` + href: `https://github.com/vuejs/core/tree/${__COMMIT__}`, + target: `_blank`, }, - `@${__COMMIT__}` + `@${__COMMIT__}`, ), ' | ', h( 'a', { href: 'https://app.netlify.com/sites/vue-next-template-explorer/deploys', - target: `_blank` + target: `_blank`, }, - 'History' + 'History', ), h('div', { id: 'options-wrapper' }, [ @@ -67,7 +71,7 @@ const App = { checked: isModule, onChange() { compilerOptions.mode = 'module' - } + }, }), h('label', { for: 'mode-module' }, 'module'), ' ', @@ -78,9 +82,9 @@ const App = { checked: !isModule, onChange() { compilerOptions.mode = 'function' - } + }, }), - h('label', { for: 'mode-function' }, 'function') + h('label', { for: 'mode-function' }, 'function'), ]), // whitespace handling @@ -93,7 +97,7 @@ const App = { checked: compilerOptions.whitespace === 'condense', onChange() { compilerOptions.whitespace = 'condense' - } + }, }), h('label', { for: 'whitespace-condense' }, 'condense'), ' ', @@ -104,9 +108,9 @@ const App = { checked: compilerOptions.whitespace === 'preserve', onChange() { compilerOptions.whitespace = 'preserve' - } + }, }), - h('label', { for: 'whitespace-preserve' }, 'preserve') + h('label', { for: 'whitespace-preserve' }, 'preserve'), ]), // SSR @@ -118,9 +122,9 @@ const App = { checked: ssrMode.value, onChange(e: Event) { ssrMode.value = (e.target as HTMLInputElement).checked - } + }, }), - h('label', { for: 'ssr' }, 'SSR') + h('label', { for: 'ssr' }, 'SSR'), ]), // toggle prefixIdentifiers @@ -133,9 +137,9 @@ const App = { onChange(e: Event) { compilerOptions.prefixIdentifiers = (e.target as HTMLInputElement).checked || isModule - } + }, }), - h('label', { for: 'prefix' }, 'prefixIdentifiers') + h('label', { for: 'prefix' }, 'prefixIdentifiers'), ]), // toggle hoistStatic @@ -149,9 +153,9 @@ const App = { compilerOptions.hoistStatic = ( e.target as HTMLInputElement ).checked - } + }, }), - h('label', { for: 'hoist' }, 'hoistStatic') + h('label', { for: 'hoist' }, 'hoistStatic'), ]), // toggle cacheHandlers @@ -165,9 +169,9 @@ const App = { compilerOptions.cacheHandlers = ( e.target as HTMLInputElement ).checked - } + }, }), - h('label', { for: 'cache' }, 'cacheHandlers') + h('label', { for: 'cache' }, 'cacheHandlers'), ]), // toggle scopeId @@ -182,9 +186,9 @@ const App = { isModule && (e.target as HTMLInputElement).checked ? 'scope-id' : null - } + }, }), - h('label', { for: 'scope-id' }, 'scopeId') + h('label', { for: 'scope-id' }, 'scopeId'), ]), // inline mode @@ -197,9 +201,9 @@ const App = { compilerOptions.inline = ( e.target as HTMLInputElement ).checked - } + }, }), - h('label', { for: 'inline' }, 'inline') + h('label', { for: 'inline' }, 'inline'), ]), // compat mode @@ -214,15 +218,15 @@ const App = { ).checked ? 2 : 3 - } + }, }), - h('label', { for: 'compat' }, 'v2 compat mode') - ]) - ]) - ]) + h('label', { for: 'compat' }, 'v2 compat mode'), + ]), + ]), + ]), ] } - } + }, } export function initOptions() { diff --git a/packages/template-explorer/src/theme.ts b/packages-private/template-explorer/src/theme.ts similarity index 57% rename from packages/template-explorer/src/theme.ts rename to packages-private/template-explorer/src/theme.ts index 99da1081a..9027cd0c0 100644 --- a/packages/template-explorer/src/theme.ts +++ b/packages-private/template-explorer/src/theme.ts @@ -4,234 +4,234 @@ export default { rules: [ { foreground: 'de935f', - token: 'number' + token: 'number', }, { foreground: '969896', - token: 'comment' + token: 'comment', }, { foreground: 'ced1cf', - token: 'keyword.operator.class' + token: 'keyword.operator.class', }, { foreground: 'ced1cf', - token: 'constant.other' + token: 'constant.other', }, { foreground: 'ced1cf', - token: 'source.php.embedded.line' + token: 'source.php.embedded.line', }, { foreground: 'cc6666', - token: 'variable' + token: 'variable', }, { foreground: 'cc6666', - token: 'support.other.variable' + token: 'support.other.variable', }, { foreground: 'cc6666', - token: 'string.other.link' + token: 'string.other.link', }, { foreground: 'cc6666', - token: 'string.regexp' + token: 'string.regexp', }, { foreground: 'cc6666', - token: 'entity.name.tag' + token: 'entity.name.tag', }, { foreground: 'cc6666', - token: 'entity.other.attribute-name' + token: 'entity.other.attribute-name', }, { foreground: 'cc6666', - token: 'meta.tag' + token: 'meta.tag', }, { foreground: 'cc6666', - token: 'declaration.tag' + token: 'declaration.tag', }, { foreground: 'cc6666', - token: 'markup.deleted.git_gutter' + token: 'markup.deleted.git_gutter', }, { foreground: 'de935f', - token: 'constant.numeric' + token: 'constant.numeric', }, { foreground: 'de935f', - token: 'constant.language' + token: 'constant.language', }, { foreground: 'de935f', - token: 'support.constant' + token: 'support.constant', }, { foreground: 'de935f', - token: 'constant.character' + token: 'constant.character', }, { foreground: 'de935f', - token: 'variable.parameter' + token: 'variable.parameter', }, { foreground: 'de935f', - token: 'punctuation.section.embedded' + token: 'punctuation.section.embedded', }, { foreground: 'de935f', - token: 'keyword.other.unit' + token: 'keyword.other.unit', }, { foreground: 'f0c674', - token: 'entity.name.class' + token: 'entity.name.class', }, { foreground: 'f0c674', - token: 'entity.name.type.class' + token: 'entity.name.type.class', }, { foreground: 'f0c674', - token: 'support.type' + token: 'support.type', }, { foreground: 'f0c674', - token: 'support.class' + token: 'support.class', }, { foreground: 'b5bd68', - token: 'string' + token: 'string', }, { foreground: 'b5bd68', - token: 'constant.other.symbol' + token: 'constant.other.symbol', }, { foreground: 'b5bd68', - token: 'entity.other.inherited-class' + token: 'entity.other.inherited-class', }, { foreground: 'b5bd68', - token: 'markup.heading' + token: 'markup.heading', }, { foreground: 'b5bd68', - token: 'markup.inserted.git_gutter' + token: 'markup.inserted.git_gutter', }, { foreground: '8abeb7', - token: 'keyword.operator' + token: 'keyword.operator', }, { foreground: '8abeb7', - token: 'constant.other.color' + token: 'constant.other.color', }, { foreground: '81a2be', - token: 'entity.name.function' + token: 'entity.name.function', }, { foreground: '81a2be', - token: 'meta.function-call' + token: 'meta.function-call', }, { foreground: '81a2be', - token: 'support.function' + token: 'support.function', }, { foreground: '81a2be', - token: 'keyword.other.special-method' + token: 'keyword.other.special-method', }, { foreground: '81a2be', - token: 'meta.block-level' + token: 'meta.block-level', }, { foreground: '81a2be', - token: 'markup.changed.git_gutter' + token: 'markup.changed.git_gutter', }, { foreground: 'b294bb', - token: 'keyword' + token: 'keyword', }, { foreground: 'b294bb', - token: 'storage' + token: 'storage', }, { foreground: 'b294bb', - token: 'storage.type' + token: 'storage.type', }, { foreground: 'b294bb', - token: 'entity.name.tag.css' + token: 'entity.name.tag.css', }, { foreground: 'ced2cf', background: 'df5f5f', - token: 'invalid' + token: 'invalid', }, { foreground: 'ced2cf', background: '82a3bf', - token: 'meta.separator' + token: 'meta.separator', }, { foreground: 'ced2cf', background: 'b798bf', - token: 'invalid.deprecated' + token: 'invalid.deprecated', }, { foreground: 'ffffff', - token: 'markup.inserted.diff' + token: 'markup.inserted.diff', }, { foreground: 'ffffff', - token: 'markup.deleted.diff' + token: 'markup.deleted.diff', }, { foreground: 'ffffff', - token: 'meta.diff.header.to-file' + token: 'meta.diff.header.to-file', }, { foreground: 'ffffff', - token: 'meta.diff.header.from-file' + token: 'meta.diff.header.from-file', }, { foreground: '718c00', - token: 'markup.inserted.diff' + token: 'markup.inserted.diff', }, { foreground: '718c00', - token: 'meta.diff.header.to-file' + token: 'meta.diff.header.to-file', }, { foreground: 'c82829', - token: 'markup.deleted.diff' + token: 'markup.deleted.diff', }, { foreground: 'c82829', - token: 'meta.diff.header.from-file' + token: 'meta.diff.header.from-file', }, { foreground: 'ffffff', background: '4271ae', - token: 'meta.diff.header.from-file' + token: 'meta.diff.header.from-file', }, { foreground: 'ffffff', background: '4271ae', - token: 'meta.diff.header.to-file' + token: 'meta.diff.header.to-file', }, { foreground: '3e999f', fontStyle: 'italic', - token: 'meta.diff.range' - } + token: 'meta.diff.range', + }, ], colors: { 'editor.foreground': '#C5C8C6', @@ -239,6 +239,6 @@ export default { 'editor.selectionBackground': '#373B41', 'editor.lineHighlightBackground': '#282A2E', 'editorCursor.foreground': '#AEAFAD', - 'editorWhitespace.foreground': '#4B4E55' - } + 'editorWhitespace.foreground': '#4B4E55', + }, } diff --git a/packages/template-explorer/style.css b/packages-private/template-explorer/style.css similarity index 91% rename from packages/template-explorer/style.css rename to packages-private/template-explorer/style.css index 01a3e8b55..93f6f623c 100644 --- a/packages/template-explorer/style.css +++ b/packages-private/template-explorer/style.css @@ -1,7 +1,9 @@ body { margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; - --bg: #1D1F21; + overflow: hidden; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, + Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + --bg: #1d1f21; --border: #333; } diff --git a/packages-private/tsconfig.json b/packages-private/tsconfig.json new file mode 100644 index 000000000..1c287a750 --- /dev/null +++ b/packages-private/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "isolatedDeclarations": false + }, + "include": ["."] +} diff --git a/packages-private/vite-debug/App.vue b/packages-private/vite-debug/App.vue new file mode 100644 index 000000000..95b3be8ee --- /dev/null +++ b/packages-private/vite-debug/App.vue @@ -0,0 +1,15 @@ + + + + + diff --git a/packages-private/vite-debug/README.md b/packages-private/vite-debug/README.md new file mode 100644 index 000000000..4f035ae6f --- /dev/null +++ b/packages-private/vite-debug/README.md @@ -0,0 +1 @@ +This package is used for debugging issues that are related to `@vitejs/plugin-vue`, or can only be reproduced in a Vite-based setup. It aims to be as close to production as possible so Vue packages are resolved to the dist files instead of source. diff --git a/packages-private/vite-debug/index.html b/packages-private/vite-debug/index.html new file mode 100644 index 000000000..79052a023 --- /dev/null +++ b/packages-private/vite-debug/index.html @@ -0,0 +1,2 @@ + +
diff --git a/packages-private/vite-debug/main.ts b/packages-private/vite-debug/main.ts new file mode 100644 index 000000000..52668a0a5 --- /dev/null +++ b/packages-private/vite-debug/main.ts @@ -0,0 +1,6 @@ +import { createApp } from 'vue' +import App from './App.vue' + +const app = createApp(App) + +app.mount('#app') diff --git a/packages-private/vite-debug/package.json b/packages-private/vite-debug/package.json new file mode 100644 index 000000000..b0f2bad2b --- /dev/null +++ b/packages-private/vite-debug/package.json @@ -0,0 +1,15 @@ +{ + "name": "vite-debug", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "serve": "vite preview" + }, + "devDependencies": { + "@vitejs/plugin-vue": "catalog:", + "vite": "catalog:", + "vue": "workspace:*" + } +} diff --git a/packages-private/vite-debug/tsconfig.json b/packages-private/vite-debug/tsconfig.json new file mode 100644 index 000000000..ceecb1cde --- /dev/null +++ b/packages-private/vite-debug/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler" + }, + "include": ["./*"] +} diff --git a/packages-private/vite-debug/vite.config.ts b/packages-private/vite-debug/vite.config.ts new file mode 100644 index 000000000..c40aa3c36 --- /dev/null +++ b/packages-private/vite-debug/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +export default defineConfig({ + plugins: [vue()], +}) diff --git a/packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap index c292b0329..db268af4f 100644 --- a/packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap +++ b/packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap @@ -1,6 +1,6 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`compiler: codegen ArrayExpression 1`] = ` +exports[`compiler: codegen > ArrayExpression 1`] = ` " return function render(_ctx, _cache) { with (_ctx) { @@ -12,26 +12,26 @@ return function render(_ctx, _cache) { }" `; -exports[`compiler: codegen CacheExpression 1`] = ` +exports[`compiler: codegen > CacheExpression 1`] = ` " export function render(_ctx, _cache) { return _cache[1] || (_cache[1] = foo) }" `; -exports[`compiler: codegen CacheExpression w/ isVNode: true 1`] = ` +exports[`compiler: codegen > CacheExpression w/ isVOnce: true 1`] = ` " export function render(_ctx, _cache) { return _cache[1] || ( _setBlockTracking(-1), - _cache[1] = foo, + (_cache[1] = foo).cacheIndex = 1, _setBlockTracking(1), _cache[1] ) }" `; -exports[`compiler: codegen ConditionalExpression 1`] = ` +exports[`compiler: codegen > ConditionalExpression 1`] = ` " return function render(_ctx, _cache) { with (_ctx) { @@ -44,31 +44,31 @@ return function render(_ctx, _cache) { }" `; -exports[`compiler: codegen Element (callExpression + objectExpression + TemplateChildNode[]) 1`] = ` +exports[`compiler: codegen > Element (callExpression + objectExpression + TemplateChildNode[]) 1`] = ` " return function render(_ctx, _cache) { with (_ctx) { - return _createElementVNode(\\"div\\", { - id: \\"foo\\", + return _createElementVNode("div", { + id: "foo", [prop]: bar, [foo + bar]: bar }, [ - _createElementVNode(\\"p\\", { \\"some-key\\": \\"foo\\" }) - ], 16) + _createElementVNode("p", { "some-key": "foo" }) + ], 16 /* FULL_PROPS */) } }" `; -exports[`compiler: codegen assets + temps 1`] = ` +exports[`compiler: codegen > assets + temps 1`] = ` " return function render(_ctx, _cache) { with (_ctx) { - const _component_Foo = _resolveComponent(\\"Foo\\") - const _component_bar_baz = _resolveComponent(\\"bar-baz\\") - const _component_barbaz = _resolveComponent(\\"barbaz\\") - const _component_Qux = _resolveComponent(\\"Qux\\", true) - const _directive_my_dir_0 = _resolveDirective(\\"my_dir_0\\") - const _directive_my_dir_1 = _resolveDirective(\\"my_dir_1\\") + const _component_Foo = _resolveComponent("Foo") + const _component_bar_baz = _resolveComponent("bar-baz") + const _component_barbaz = _resolveComponent("barbaz") + const _component_Qux = _resolveComponent("Qux", true) + const _directive_my_dir_0 = _resolveDirective("my_dir_0") + const _directive_my_dir_1 = _resolveDirective("my_dir_1") let _temp0, _temp1, _temp2 return null @@ -76,16 +76,16 @@ return function render(_ctx, _cache) { }" `; -exports[`compiler: codegen comment 1`] = ` +exports[`compiler: codegen > comment 1`] = ` " return function render(_ctx, _cache) { with (_ctx) { - return _createCommentVNode(\\"foo\\") + return _createCommentVNode("foo") } }" `; -exports[`compiler: codegen compound expression 1`] = ` +exports[`compiler: codegen > compound expression 1`] = ` " return function render(_ctx, _cache) { with (_ctx) { @@ -94,16 +94,16 @@ return function render(_ctx, _cache) { }" `; -exports[`compiler: codegen forNode 1`] = ` +exports[`compiler: codegen > forNode 1`] = ` " return function render(_ctx, _cache) { with (_ctx) { - return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(), 1)) + return (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(), 1 /* TEXT */)) } }" `; -exports[`compiler: codegen forNode with constant expression 1`] = ` +exports[`compiler: codegen > forNode with constant expression 1`] = ` " return function render(_ctx, _cache) { with (_ctx) { @@ -112,7 +112,7 @@ return function render(_ctx, _cache) { }" `; -exports[`compiler: codegen function mode preamble 1`] = ` +exports[`compiler: codegen > function mode preamble 1`] = ` "const _Vue = Vue return function render(_ctx, _cache) { @@ -124,7 +124,7 @@ return function render(_ctx, _cache) { }" `; -exports[`compiler: codegen function mode preamble w/ prefixIdentifiers: true 1`] = ` +exports[`compiler: codegen > function mode preamble w/ prefixIdentifiers: true 1`] = ` "const { createVNode: _createVNode, resolveDirective: _resolveDirective } = Vue return function render(_ctx, _cache) { @@ -132,10 +132,10 @@ return function render(_ctx, _cache) { }" `; -exports[`compiler: codegen hoists 1`] = ` +exports[`compiler: codegen > hoists 1`] = ` " const _hoisted_1 = hello -const _hoisted_2 = { id: \\"foo\\" } +const _hoisted_2 = { id: "foo" } return function render(_ctx, _cache) { with (_ctx) { @@ -144,7 +144,7 @@ return function render(_ctx, _cache) { }" `; -exports[`compiler: codegen ifNode 1`] = ` +exports[`compiler: codegen > ifNode 1`] = ` " return function render(_ctx, _cache) { with (_ctx) { @@ -155,7 +155,7 @@ return function render(_ctx, _cache) { }" `; -exports[`compiler: codegen interpolation 1`] = ` +exports[`compiler: codegen > interpolation 1`] = ` " return function render(_ctx, _cache) { with (_ctx) { @@ -164,16 +164,16 @@ return function render(_ctx, _cache) { }" `; -exports[`compiler: codegen module mode preamble 1`] = ` -"import { createVNode as _createVNode, resolveDirective as _resolveDirective } from \\"vue\\" +exports[`compiler: codegen > module mode preamble 1`] = ` +"import { createVNode as _createVNode, resolveDirective as _resolveDirective } from "vue" export function render(_ctx, _cache) { return null }" `; -exports[`compiler: codegen module mode preamble w/ optimizeImports: true 1`] = ` -"import { createVNode, resolveDirective } from \\"vue\\" +exports[`compiler: codegen > module mode preamble w/ optimizeImports: true 1`] = ` +"import { createVNode, resolveDirective } from "vue" // Binding optimization for webpack code-split const _createVNode = createVNode, _resolveDirective = resolveDirective @@ -183,16 +183,16 @@ export function render(_ctx, _cache) { }" `; -exports[`compiler: codegen static text 1`] = ` +exports[`compiler: codegen > static text 1`] = ` " return function render(_ctx, _cache) { with (_ctx) { - return \\"hello\\" + return "hello" } }" `; -exports[`compiler: codegen temps 1`] = ` +exports[`compiler: codegen > temps 1`] = ` " return function render(_ctx, _cache) { with (_ctx) { diff --git a/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap index a72a43782..625485719 100644 --- a/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap +++ b/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap @@ -1,25 +1,25 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`compiler: integration tests function mode 1`] = ` +exports[`compiler: integration tests > function mode 1`] = ` "const _Vue = Vue return function render(_ctx, _cache) { with (_ctx) { const { toDisplayString: _toDisplayString, openBlock: _openBlock, createElementBlock: _createElementBlock, createCommentVNode: _createCommentVNode, createTextVNode: _createTextVNode, Fragment: _Fragment, renderList: _renderList, createElementVNode: _createElementVNode, normalizeClass: _normalizeClass } = _Vue - return (_openBlock(), _createElementBlock(\\"div\\", { - id: \\"foo\\", + return (_openBlock(), _createElementBlock("div", { + id: "foo", class: _normalizeClass(bar.baz) }, [ - _createTextVNode(_toDisplayString(world.burn()) + \\" \\", 1 /* TEXT */), + _createTextVNode(_toDisplayString(world.burn()) + " ", 1 /* TEXT */), ok - ? (_openBlock(), _createElementBlock(\\"div\\", { key: 0 }, \\"yes\\")) + ? (_openBlock(), _createElementBlock("div", { key: 0 }, "yes")) : (_openBlock(), _createElementBlock(_Fragment, { key: 1 }, [ - _createTextVNode(\\"no\\") - ], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */)), + _createTextVNode("no") + ], 64 /* STABLE_FRAGMENT */)), (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(list, (value, index) => { - return (_openBlock(), _createElementBlock(\\"div\\", null, [ - _createElementVNode(\\"span\\", null, _toDisplayString(value + index), 1 /* TEXT */) + return (_openBlock(), _createElementBlock("div", null, [ + _createElementVNode("span", null, _toDisplayString(value + index), 1 /* TEXT */) ])) }), 256 /* UNKEYED_FRAGMENT */)) ], 2 /* CLASS */)) @@ -27,46 +27,46 @@ return function render(_ctx, _cache) { }" `; -exports[`compiler: integration tests function mode w/ prefixIdentifiers: true 1`] = ` +exports[`compiler: integration tests > function mode w/ prefixIdentifiers: true 1`] = ` "const { toDisplayString: _toDisplayString, openBlock: _openBlock, createElementBlock: _createElementBlock, createCommentVNode: _createCommentVNode, createTextVNode: _createTextVNode, Fragment: _Fragment, renderList: _renderList, createElementVNode: _createElementVNode, normalizeClass: _normalizeClass } = Vue return function render(_ctx, _cache) { - return (_openBlock(), _createElementBlock(\\"div\\", { - id: \\"foo\\", + return (_openBlock(), _createElementBlock("div", { + id: "foo", class: _normalizeClass(_ctx.bar.baz) }, [ - _createTextVNode(_toDisplayString(_ctx.world.burn()) + \\" \\", 1 /* TEXT */), + _createTextVNode(_toDisplayString(_ctx.world.burn()) + " ", 1 /* TEXT */), (_ctx.ok) - ? (_openBlock(), _createElementBlock(\\"div\\", { key: 0 }, \\"yes\\")) + ? (_openBlock(), _createElementBlock("div", { key: 0 }, "yes")) : (_openBlock(), _createElementBlock(_Fragment, { key: 1 }, [ - _createTextVNode(\\"no\\") - ], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */)), + _createTextVNode("no") + ], 64 /* STABLE_FRAGMENT */)), (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.list, (value, index) => { - return (_openBlock(), _createElementBlock(\\"div\\", null, [ - _createElementVNode(\\"span\\", null, _toDisplayString(value + index), 1 /* TEXT */) + return (_openBlock(), _createElementBlock("div", null, [ + _createElementVNode("span", null, _toDisplayString(value + index), 1 /* TEXT */) ])) }), 256 /* UNKEYED_FRAGMENT */)) ], 2 /* CLASS */)) }" `; -exports[`compiler: integration tests module mode 1`] = ` -"import { toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock, createCommentVNode as _createCommentVNode, createTextVNode as _createTextVNode, Fragment as _Fragment, renderList as _renderList, createElementVNode as _createElementVNode, normalizeClass as _normalizeClass } from \\"vue\\" +exports[`compiler: integration tests > module mode 1`] = ` +"import { toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock, createCommentVNode as _createCommentVNode, createTextVNode as _createTextVNode, Fragment as _Fragment, renderList as _renderList, createElementVNode as _createElementVNode, normalizeClass as _normalizeClass } from "vue" export function render(_ctx, _cache) { - return (_openBlock(), _createElementBlock(\\"div\\", { - id: \\"foo\\", + return (_openBlock(), _createElementBlock("div", { + id: "foo", class: _normalizeClass(_ctx.bar.baz) }, [ - _createTextVNode(_toDisplayString(_ctx.world.burn()) + \\" \\", 1 /* TEXT */), + _createTextVNode(_toDisplayString(_ctx.world.burn()) + " ", 1 /* TEXT */), (_ctx.ok) - ? (_openBlock(), _createElementBlock(\\"div\\", { key: 0 }, \\"yes\\")) + ? (_openBlock(), _createElementBlock("div", { key: 0 }, "yes")) : (_openBlock(), _createElementBlock(_Fragment, { key: 1 }, [ - _createTextVNode(\\"no\\") - ], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */)), + _createTextVNode("no") + ], 64 /* STABLE_FRAGMENT */)), (_openBlock(true), _createElementBlock(_Fragment, null, _renderList(_ctx.list, (value, index) => { - return (_openBlock(), _createElementBlock(\\"div\\", null, [ - _createElementVNode(\\"span\\", null, _toDisplayString(value + index), 1 /* TEXT */) + return (_openBlock(), _createElementBlock("div", null, [ + _createElementVNode("span", null, _toDisplayString(value + index), 1 /* TEXT */) ])) }), 256 /* UNKEYED_FRAGMENT */)) ], 2 /* CLASS */)) diff --git a/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap index d7ac9888a..942eed4c4 100644 --- a/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap +++ b/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap @@ -1,303 +1,571 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`compiler: parse Errors ABRUPT_CLOSING_OF_EMPTY_COMMENT 1`] = ` -Object { - "cached": 0, - "children": Array [ - Object { - "children": Array [ - Object { - "content": "", - "loc": Object { - "end": Object { - "column": 16, - "line": 1, - "offset": 15, +exports[`compiler: parse > Edge Cases > invalid html 1`] = ` +{ + "cached": [], + "children": [ + { + "children": [ + { + "children": [], + "codegenNode": undefined, + "loc": { + "end": { + "column": 1, + "line": 3, + "offset": 13, }, - "source": "", - "start": Object { - "column": 11, - "line": 1, - "offset": 10, + "source": " +", + "start": { + "column": 1, + "line": 2, + "offset": 6, }, }, - "type": 3, + "ns": 0, + "props": [], + "tag": "span", + "tagType": 0, + "type": 1, }, ], "codegenNode": undefined, - "isSelfClosing": false, - "loc": Object { - "end": Object { - "column": 27, - "line": 1, - "offset": 26, + "loc": { + "end": { + "column": 7, + "line": 3, + "offset": 19, }, - "source": "", - "start": Object { + "source": "
+ +
", + "start": { "column": 1, "line": 1, "offset": 0, }, }, "ns": 0, - "props": Array [], - "tag": "template", + "props": [], + "tag": "div", "tagType": 0, "type": 1, }, ], "codegenNode": undefined, - "components": Array [], - "directives": Array [], - "helpers": Array [], - "hoists": Array [], - "imports": Array [], - "loc": Object { - "end": Object { - "column": 27, - "line": 1, - "offset": 26, - }, - "source": "", - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "temps": 0, - "type": 0, -} -`; - -exports[`compiler: parse Errors ABRUPT_CLOSING_OF_EMPTY_COMMENT 1`] = ` -Object { - "cached": 0, - "children": Array [ - Object { - "children": Array [ - Object { - "content": "", - "loc": Object { - "end": Object { - "column": 17, - "line": 1, - "offset": 16, - }, - "source": "", - "start": Object { - "column": 11, - "line": 1, - "offset": 10, - }, - }, - "type": 3, - }, - ], - "codegenNode": undefined, - "isSelfClosing": false, - "loc": Object { - "end": Object { - "column": 28, - "line": 1, - "offset": 27, - }, - "source": "", - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "ns": 0, - "props": Array [], - "tag": "template", - "tagType": 0, - "type": 1, - }, - ], - "codegenNode": undefined, - "components": Array [], - "directives": Array [], - "helpers": Array [], - "hoists": Array [], - "imports": Array [], - "loc": Object { - "end": Object { - "column": 28, - "line": 1, + "components": [], + "directives": [], + "helpers": Set {}, + "hoists": [], + "imports": [], + "loc": { + "end": { + "column": 8, + "line": 4, "offset": 27, }, - "source": "", - "start": Object { + "source": "
+ +
+
", + "start": { "column": 1, "line": 1, "offset": 0, }, }, + "source": "
+ +
+", "temps": 0, "type": 0, } `; -exports[`compiler: parse Errors ABRUPT_CLOSING_OF_EMPTY_COMMENT 1`] = ` -Object { - "cached": 0, - "children": Array [ - Object { - "children": Array [ - Object { - "content": "", - "loc": Object { - "end": Object { - "column": 18, - "line": 1, - "offset": 17, - }, - "source": "", - "start": Object { - "column": 11, - "line": 1, - "offset": 10, - }, - }, - "type": 3, - }, - ], +exports[`compiler: parse > Edge Cases > self closing multiple tag 1`] = ` +{ + "cached": [], + "children": [ + { + "children": [], "codegenNode": undefined, - "isSelfClosing": false, - "loc": Object { - "end": Object { - "column": 29, + "isSelfClosing": true, + "loc": { + "end": { + "column": 37, "line": 1, - "offset": 28, + "offset": 36, }, - "source": "", - "start": Object { + "source": "
", + "start": { "column": 1, "line": 1, "offset": 0, }, }, "ns": 0, - "props": Array [], - "tag": "template", + "props": [ + { + "arg": { + "constType": 3, + "content": "class", + "isStatic": true, + "loc": { + "end": { + "column": 12, + "line": 1, + "offset": 11, + }, + "source": "class", + "start": { + "column": 7, + "line": 1, + "offset": 6, + }, + }, + "type": 4, + }, + "exp": { + "constType": 0, + "content": "{ some: condition }", + "isStatic": false, + "loc": { + "end": { + "column": 33, + "line": 1, + "offset": 32, + }, + "source": "{ some: condition }", + "start": { + "column": 14, + "line": 1, + "offset": 13, + }, + }, + "type": 4, + }, + "loc": { + "end": { + "column": 34, + "line": 1, + "offset": 33, + }, + "source": ":class="{ some: condition }"", + "start": { + "column": 6, + "line": 1, + "offset": 5, + }, + }, + "modifiers": [], + "name": "bind", + "rawName": ":class", + "type": 7, + }, + ], + "tag": "div", + "tagType": 0, + "type": 1, + }, + { + "children": [], + "codegenNode": undefined, + "isSelfClosing": true, + "loc": { + "end": { + "column": 37, + "line": 2, + "offset": 73, + }, + "source": "

", + "start": { + "column": 1, + "line": 2, + "offset": 37, + }, + }, + "ns": 0, + "props": [ + { + "arg": { + "constType": 3, + "content": "style", + "isStatic": true, + "loc": { + "end": { + "column": 16, + "line": 2, + "offset": 52, + }, + "source": "style", + "start": { + "column": 11, + "line": 2, + "offset": 47, + }, + }, + "type": 4, + }, + "exp": { + "constType": 0, + "content": "{ color: 'red' }", + "isStatic": false, + "loc": { + "end": { + "column": 34, + "line": 2, + "offset": 70, + }, + "source": "{ color: 'red' }", + "start": { + "column": 18, + "line": 2, + "offset": 54, + }, + }, + "type": 4, + }, + "loc": { + "end": { + "column": 35, + "line": 2, + "offset": 71, + }, + "source": "v-bind:style="{ color: 'red' }"", + "start": { + "column": 4, + "line": 2, + "offset": 40, + }, + }, + "modifiers": [], + "name": "bind", + "rawName": "v-bind:style", + "type": 7, + }, + ], + "tag": "p", "tagType": 0, "type": 1, }, ], "codegenNode": undefined, - "components": Array [], - "directives": Array [], - "helpers": Array [], - "hoists": Array [], - "imports": Array [], - "loc": Object { - "end": Object { - "column": 29, - "line": 1, - "offset": 28, + "components": [], + "directives": [], + "helpers": Set {}, + "hoists": [], + "imports": [], + "loc": { + "end": { + "column": 37, + "line": 2, + "offset": 73, }, - "source": "", - "start": Object { + "source": "

+

", + "start": { "column": 1, "line": 1, "offset": 0, }, }, + "source": "

+

", "temps": 0, "type": 0, } `; -exports[`compiler: parse Errors CDATA_IN_HTML_CONTENT 1`] = ` -Object { - "cached": 0, - "children": Array [ - Object { - "children": Array [ - Object { - "content": "[CDATA[cdata]]", - "loc": Object { - "end": Object { - "column": 28, - "line": 1, - "offset": 27, +exports[`compiler: parse > Edge Cases > valid html 1`] = ` +{ + "cached": [], + "children": [ + { + "children": [ + { + "children": [], + "codegenNode": undefined, + "isSelfClosing": true, + "loc": { + "end": { + "column": 39, + "line": 2, + "offset": 73, }, - "source": "", - "start": Object { - "column": 11, - "line": 1, - "offset": 10, + "source": "

", + "start": { + "column": 3, + "line": 2, + "offset": 37, + }, + }, + "ns": 0, + "props": [ + { + "arg": { + "constType": 3, + "content": "style", + "isStatic": true, + "loc": { + "end": { + "column": 18, + "line": 2, + "offset": 52, + }, + "source": "style", + "start": { + "column": 13, + "line": 2, + "offset": 47, + }, + }, + "type": 4, + }, + "exp": { + "constType": 0, + "content": "{ color: 'red' }", + "isStatic": false, + "loc": { + "end": { + "column": 36, + "line": 2, + "offset": 70, + }, + "source": "{ color: 'red' }", + "start": { + "column": 20, + "line": 2, + "offset": 54, + }, + }, + "type": 4, + }, + "loc": { + "end": { + "column": 37, + "line": 2, + "offset": 71, + }, + "source": "v-bind:style="{ color: 'red' }"", + "start": { + "column": 6, + "line": 2, + "offset": 40, + }, + }, + "modifiers": [], + "name": "bind", + "rawName": "v-bind:style", + "type": 7, + }, + ], + "tag": "p", + "tagType": 0, + "type": 1, + }, + { + "content": " a comment with inside it ", + "loc": { + "end": { + "column": 43, + "line": 3, + "offset": 116, + }, + "source": "", + "start": { + "column": 3, + "line": 3, + "offset": 76, }, }, "type": 3, }, ], "codegenNode": undefined, - "isSelfClosing": false, - "loc": Object { - "end": Object { + "loc": { + "end": { + "column": 7, + "line": 4, + "offset": 123, + }, + "source": "

+

+ +

", + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "ns": 0, + "props": [ + { + "arg": { + "constType": 3, + "content": "class", + "isStatic": true, + "loc": { + "end": { + "column": 12, + "line": 1, + "offset": 11, + }, + "source": "class", + "start": { + "column": 7, + "line": 1, + "offset": 6, + }, + }, + "type": 4, + }, + "exp": { + "constType": 0, + "content": "{ some: condition }", + "isStatic": false, + "loc": { + "end": { + "column": 33, + "line": 1, + "offset": 32, + }, + "source": "{ some: condition }", + "start": { + "column": 14, + "line": 1, + "offset": 13, + }, + }, + "type": 4, + }, + "loc": { + "end": { + "column": 34, + "line": 1, + "offset": 33, + }, + "source": ":class="{ some: condition }"", + "start": { + "column": 6, + "line": 1, + "offset": 5, + }, + }, + "modifiers": [], + "name": "bind", + "rawName": ":class", + "type": 7, + }, + ], + "tag": "div", + "tagType": 0, + "type": 1, + }, + ], + "codegenNode": undefined, + "components": [], + "directives": [], + "helpers": Set {}, + "hoists": [], + "imports": [], + "loc": { + "end": { + "column": 7, + "line": 4, + "offset": 123, + }, + "source": "
+

+ +

", + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "source": "
+

+ +

", + "temps": 0, + "type": 0, +} +`; + +exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > 1`] = ` +{ + "cached": [], + "children": [ + { + "children": [], + "codegenNode": undefined, + "loc": { + "end": { "column": 39, "line": 1, "offset": 38, }, "source": "", - "start": Object { + "start": { "column": 1, "line": 1, "offset": 0, }, }, "ns": 0, - "props": Array [], + "props": [], "tag": "template", "tagType": 0, "type": 1, }, ], "codegenNode": undefined, - "components": Array [], - "directives": Array [], - "helpers": Array [], - "hoists": Array [], - "imports": Array [], - "loc": Object { - "end": Object { + "components": [], + "directives": [], + "helpers": Set {}, + "hoists": [], + "imports": [], + "loc": { + "end": { "column": 39, "line": 1, "offset": 38, }, "source": "", - "start": Object { + "start": { "column": 1, "line": 1, "offset": 0, }, }, + "source": "", "temps": 0, "type": 0, } `; -exports[`compiler: parse Errors CDATA_IN_HTML_CONTENT 1`] = ` -Object { - "cached": 0, - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { +exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > 1`] = ` +{ + "cached": [], + "children": [ + { + "children": [ + { + "children": [ + { "content": "cdata", - "loc": Object { - "end": Object { + "loc": { + "end": { "column": 30, "line": 1, "offset": 29, }, "source": "cdata", - "start": Object { + "start": { "column": 25, "line": 1, "offset": 24, @@ -307,124 +575,135 @@ Object { }, ], "codegenNode": undefined, - "isSelfClosing": false, - "loc": Object { - "end": Object { + "loc": { + "end": { "column": 39, "line": 1, "offset": 38, }, "source": "cdata", - "start": Object { + "start": { "column": 11, "line": 1, "offset": 10, }, }, "ns": 1, - "props": Array [], + "props": [], "tag": "svg", "tagType": 0, "type": 1, }, ], "codegenNode": undefined, - "isSelfClosing": false, - "loc": Object { - "end": Object { + "loc": { + "end": { "column": 50, "line": 1, "offset": 49, }, "source": "", - "start": Object { + "start": { "column": 1, "line": 1, "offset": 0, }, }, "ns": 0, - "props": Array [], + "props": [], "tag": "template", "tagType": 0, "type": 1, }, ], "codegenNode": undefined, - "components": Array [], - "directives": Array [], - "helpers": Array [], - "hoists": Array [], - "imports": Array [], - "loc": Object { - "end": Object { + "components": [], + "directives": [], + "helpers": Set {}, + "hoists": [], + "imports": [], + "loc": { + "end": { "column": 50, "line": 1, "offset": 49, }, "source": "", - "start": Object { + "start": { "column": 1, "line": 1, "offset": 0, }, }, + "source": "", "temps": 0, "type": 0, } `; -exports[`compiler: parse Errors DUPLICATE_ATTRIBUTE 1`] = ` -Object { - "cached": 0, - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [], +exports[`compiler: parse > Errors > DUPLICATE_ATTRIBUTE > 1`] = ` +{ + "cached": [], + "children": [ + { + "children": [ + { + "children": [], "codegenNode": undefined, - "isSelfClosing": false, - "loc": Object { - "end": Object { + "loc": { + "end": { "column": 34, "line": 1, "offset": 33, }, - "source": "
", - "start": Object { + "source": "
", + "start": { "column": 11, "line": 1, "offset": 10, }, }, "ns": 0, - "props": Array [ - Object { - "loc": Object { - "end": Object { + "props": [ + { + "loc": { + "end": { "column": 21, "line": 1, "offset": 20, }, - "source": "id=\\"\\"", - "start": Object { + "source": "id=""", + "start": { "column": 16, "line": 1, "offset": 15, }, }, "name": "id", + "nameLoc": { + "end": { + "column": 18, + "line": 1, + "offset": 17, + }, + "source": "id", + "start": { + "column": 16, + "line": 1, + "offset": 15, + }, + }, "type": 6, - "value": Object { + "value": { "content": "", - "loc": Object { - "end": Object { + "loc": { + "end": { "column": 21, "line": 1, "offset": 20, }, - "source": "\\"\\"", - "start": Object { + "source": """", + "start": { "column": 19, "line": 1, "offset": 18, @@ -433,32 +712,45 @@ Object { "type": 2, }, }, - Object { - "loc": Object { - "end": Object { + { + "loc": { + "end": { "column": 27, "line": 1, "offset": 26, }, - "source": "id=\\"\\"", - "start": Object { + "source": "id=""", + "start": { "column": 22, "line": 1, "offset": 21, }, }, "name": "id", + "nameLoc": { + "end": { + "column": 24, + "line": 1, + "offset": 23, + }, + "source": "id", + "start": { + "column": 22, + "line": 1, + "offset": 21, + }, + }, "type": 6, - "value": Object { + "value": { "content": "", - "loc": Object { - "end": Object { + "loc": { + "end": { "column": 27, "line": 1, "offset": 26, }, - "source": "\\"\\"", - "start": Object { + "source": """", + "start": { "column": 25, "line": 1, "offset": 24, @@ -474,219 +766,67 @@ Object { }, ], "codegenNode": undefined, - "isSelfClosing": false, - "loc": Object { - "end": Object { + "loc": { + "end": { "column": 45, "line": 1, "offset": 44, }, - "source": "", - "start": Object { + "source": "", + "start": { "column": 1, "line": 1, "offset": 0, }, }, "ns": 0, - "props": Array [], + "props": [], "tag": "template", "tagType": 0, "type": 1, }, ], "codegenNode": undefined, - "components": Array [], - "directives": Array [], - "helpers": Array [], - "hoists": Array [], - "imports": Array [], - "loc": Object { - "end": Object { + "components": [], + "directives": [], + "helpers": Set {}, + "hoists": [], + "imports": [], + "loc": { + "end": { "column": 45, "line": 1, "offset": 44, }, - "source": "", - "start": Object { + "source": "", + "start": { "column": 1, "line": 1, "offset": 0, }, }, + "source": "", "temps": 0, "type": 0, } `; -exports[`compiler: parse Errors END_TAG_WITH_ATTRIBUTES 1`] = ` -Object { - "cached": 0, - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [], - "codegenNode": undefined, - "isSelfClosing": false, - "loc": Object { - "end": Object { - "column": 28, - "line": 1, - "offset": 27, - }, - "source": "
", - "start": Object { - "column": 11, - "line": 1, - "offset": 10, - }, - }, - "ns": 0, - "props": Array [], - "tag": "div", - "tagType": 0, - "type": 1, - }, - ], - "codegenNode": undefined, - "isSelfClosing": false, - "loc": Object { - "end": Object { - "column": 39, - "line": 1, - "offset": 38, - }, - "source": "", - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "ns": 0, - "props": Array [], - "tag": "template", - "tagType": 0, - "type": 1, - }, - ], - "codegenNode": undefined, - "components": Array [], - "directives": Array [], - "helpers": Array [], - "hoists": Array [], - "imports": Array [], - "loc": Object { - "end": Object { - "column": 39, - "line": 1, - "offset": 38, - }, - "source": "", - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "temps": 0, - "type": 0, -} -`; - -exports[`compiler: parse Errors END_TAG_WITH_TRAILING_SOLIDUS 1`] = ` -Object { - "cached": 0, - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [], - "codegenNode": undefined, - "isSelfClosing": false, - "loc": Object { - "end": Object { - "column": 23, - "line": 1, - "offset": 22, - }, - "source": "
", - "start": Object { - "column": 11, - "line": 1, - "offset": 10, - }, - }, - "ns": 0, - "props": Array [], - "tag": "div", - "tagType": 0, - "type": 1, - }, - ], - "codegenNode": undefined, - "isSelfClosing": false, - "loc": Object { - "end": Object { - "column": 34, - "line": 1, - "offset": 33, - }, - "source": "", - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "ns": 0, - "props": Array [], - "tag": "template", - "tagType": 0, - "type": 1, - }, - ], - "codegenNode": undefined, - "components": Array [], - "directives": Array [], - "helpers": Array [], - "hoists": Array [], - "imports": Array [], - "loc": Object { - "end": Object { - "column": 34, - "line": 1, - "offset": 33, - }, - "source": "", - "start": Object { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "temps": 0, - "type": 0, -} -`; - -exports[`compiler: parse Errors EOF_BEFORE_TAG_NAME