Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Prepare Release

on:
workflow_dispatch:
inputs:
package:
description: Package to release
required: true
default: vite
type: choice
options:
- vite
- create-vite
- plugin-legacy
release:
description: Release type
required: true
default: next
type: choice
options:
- next
- patch
- minor
- major
- prepatch
- preminor
- premajor
version:
description: Specify exact version instead of release type
required: false
type: string

concurrency:
group: ${{ github.workflow }}-${{ inputs.package }}-${{ inputs.version || inputs.release }}
cancel-in-progress: false

permissions: {}

jobs:
prepare:
if: github.repository == 'vitejs/vite'
name: Prepare release PR
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: main
fetch-depth: 0
persist-credentials: false

- name: Install pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9

- name: Set node version to 24
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 24
package-manager-cache: false

- name: Install deps
run: pnpm install
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"

- name: Prepare release
id: prepare
env:
RELEASE: ${{ inputs.version || inputs.release }}
RELEASE_PACKAGE: ${{ inputs.package }}
run: |
node scripts/prepare-release.ts "$RELEASE_PACKAGE" "$RELEASE" >> "$GITHUB_OUTPUT"

- name: Open release PR
uses: vitejs/release-scripts/action/release-pr@005dab4c647ff12519bfd076a595b2be33be8f6b # v1.9.2
with:
token: ${{ github.token }}
package-name: ${{ inputs.package }}
package-path: packages/${{ inputs.package }}
pr-body: ${{ steps.prepare.outputs.pr_body }}
tag: ${{ steps.prepare.outputs.tag }}
version: ${{ steps.prepare.outputs.version }}
85 changes: 76 additions & 9 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,70 @@ name: Publish Package

on:
push:
tags:
- "v*" # Push events to matching v*, i.e. v1.0, v20.15.10
- "plugin-*" # Push events to matching plugin-*, i.e. plugin-(vue|vue-jsx|react|legacy)@1.0.0
- "create-vite*" # # Push events to matching create-vite*, i.e. create-vite@1.0.0
branches:
- main

permissions: {}

jobs:
publish:
# prevents this action from running on forks
detect-release:
if: github.repository == 'vitejs/vite'
name: Detect release commit
runs-on: ubuntu-slim
outputs:
package: ${{ steps.detect.outputs.package }}
release: ${{ steps.detect.outputs.release }}
tag: ${{ steps.detect.outputs.tag }}
version: ${{ steps.detect.outputs.version }}
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false

- name: Install pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9

- name: Set node version to 24
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 24
package-manager-cache: false

- name: Install deps
run: pnpm install
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"

- name: Detect release
id: detect
run: node scripts/detect-release.ts "$(git log -1 --format=%s)" >> "$GITHUB_OUTPUT"

publish-release:
if: needs.detect-release.outputs.release == 'true'
needs: detect-release
name: Publish ${{ needs.detect-release.outputs.tag }}
runs-on: ubuntu-latest
permissions:
contents: read
contents: write
id-token: write
environment: Release
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
fetch-depth: 0
persist-credentials: false

- name: Check release tag
env:
TAG: ${{ needs.detect-release.outputs.tag }}
run: |
if git rev-parse --verify --quiet "refs/tags/$TAG"; then
echo "Tag $TAG already exists"
exit 1
fi

- name: Install pnpm
uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10

Expand All @@ -42,6 +86,29 @@ jobs:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"

- name: Publish package
run: npm i -g npm@^11.5.2 && pnpm run ci-publish "$REF_NAME"
env:
REF_NAME: ${{ github.ref_name }}
TAG: ${{ needs.detect-release.outputs.tag }}
# npm 11.5.2+ is required for trusted publishing.
# zizmor: ignore[adhoc-packages]
run: npm i -g npm@^11.5.2 && pnpm run ci-publish "$TAG"

- name: Create GitHub release
env:
GH_TOKEN: ${{ github.token }}
NOTES_FILE: ${{ runner.temp }}/release-notes.md
PACKAGE: ${{ needs.detect-release.outputs.package }}
TAG: ${{ needs.detect-release.outputs.tag }}
VERSION: ${{ needs.detect-release.outputs.version }}
run: |
node scripts/extract-changelog.ts "packages/$PACKAGE/CHANGELOG.md" "$VERSION" > "$NOTES_FILE"

prerelease=()
if [[ "${VERSION%%+*}" == *-* ]]; then
prerelease+=(--prerelease)
fi

gh release create "$TAG" \
--target "$GITHUB_SHA" \
--title "$TAG" \
--notes-file "$NOTES_FILE" \
"${prerelease[@]}"
52 changes: 0 additions & 52 deletions .github/workflows/release-tag.yml

This file was deleted.

39 changes: 26 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -336,22 +336,35 @@ flowchart TD

### Release

If you have publish access, the steps below explain how to cut a release for a package. There are two phases for the release step: "Release" and "Publish".
All publishable packages in this repository use a pull-request-driven release flow. GitHub Actions prepares a release PR containing the version bump and changelog, and merging that PR triggers publishing.

"Release" is done locally to generate the changelogs and git tags:
#### Prepare a Release

1. Make sure the git remote for https://github.com/vitejs/vite is set as `origin`.
2. In the `vite` project root `main` branch, run `git pull` and `pnpm i` to get it up-to-date. Then run `pnpm build`.
3. Run `pnpm release` and follow the prompts to cut a release for a package. It will generate the changelog, a git release tag, and push them to `origin`. You can run with the `--dry` flag to test it out.
4. When the command finishes, it will provide a link to https://github.com/vitejs/vite/actions/workflows/publish.yml.
5. Click the link to visit the page, and follow the next steps below.
1. Run the [Prepare Release](.github/workflows/prepare-release.yml) workflow from the `main` branch.
2. Select `vite`, `create-vite`, or `plugin-legacy`.
3. Select a `release` type. The default `next` creates the next patch for a stable version or advances an existing prerelease. Alternatively, select another supported release type or enter an exact `version`, which takes precedence over `release`.
4. Wait for the action to open the release PR. The PR contains the selected package's version bump and changelog entry. A `create-vite` release also updates template Vite dependency versions when appropriate.

"Publish" is done on GitHub Actions to publish the package to npm:
#### Review and Publish

1. Shortly in the workflows page, a new workflow will appear for the released package and is waiting for approval to publish to npm.
2. Click on the workflow to open its page.
3. Click on the "Review deployments" button in the yellow box, a popup will appear.
4. Check "Release" and click "Approve and deploy".
5. The package will start publishing to npm.
1. Review the generated version and changelog, and wait for the release PR checks to pass.
2. Merge the PR while retaining its `release: <tag>` commit subject. Vite uses `release: v<version>`; other packages use `release: <package>@<version>`. A matching commit at the tip of `main` triggers the publish job.
3. Open the [Publish Package](.github/workflows/publish.yml) run and approve its `Release` environment deployment.
4. Wait for the workflow to publish the package, create its tag, and create the corresponding GitHub release.
5. Verify the new version on npm.

#### Repository Configuration

The release flow depends on configuration outside this repository:

- The `Release` environment must require maintainer approval before publishing.
- The npm trusted publishers for `vite`, `create-vite`, and `@vitejs/plugin-legacy` must be restricted to `vitejs/vite`, `.github/workflows/publish.yml`, and the `Release` environment.

#### Recovery

- If release preparation fails, fix the cause and rerun the preparation workflow. Each run creates a uniquely named branch.
- If publishing fails before npm accepts the package, fix the cause and rerun the failed workflow.
- If npm publishing succeeds but tag or GitHub release creation fails, do not rerun the entire publish job blindly because npm versions are immutable. Confirm the package state first, then manually create the tag at the original release commit and create the GitHub release from the corresponding changelog entry.
- If the release tag already exists, investigate whether the package was previously published before retrying or changing any release state.

To learn more about how and when Vite does releases, check out the [Releases](https://vite.dev/releases) documentation.
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
"docs-serve": "pnpm --filter=./docs run docs-serve",
"build": "pnpm -r --filter='./packages/*' run build",
"dev": "pnpm -r --parallel --filter='./packages/*' run dev",
"release": "tsx scripts/release.ts",
"ci-publish": "tsx scripts/publishCI.ts",
"ci-docs": "pnpm build && pnpm docs-build",
"merge-changelog": "tsx scripts/mergeChangelog.ts"
Expand All @@ -54,7 +53,7 @@
"@types/picomatch": "^4.0.3",
"@types/stylus": "^0.48.43",
"@types/ws": "^8.18.1",
"@vitejs/release-scripts": "^1.9.1",
"@vitejs/release-scripts": "^1.9.2",
"eslint": "^9.39.5",
"eslint-plugin-import-x": "^4.17.1",
"eslint-plugin-n": "^18.3.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/create-vite/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const argv = mri<{
})
const cwd = process.cwd()

// prettier-ignore
// oxfmt-ignore
const helpMessage = `\
Usage: create-vite [OPTION]... [DIRECTORY]

Expand Down
25 changes: 15 additions & 10 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
type OutputChunk,
type PluginContextMeta,
type RolldownOptions,
type RolldownOutput,
rolldown,
} from 'rolldown'
import { isDynamicPattern } from 'tinyglobby'
Expand Down Expand Up @@ -2652,16 +2653,20 @@ export async function bundleConfigFile(
},
],
})
const result = await bundle.generate({
format: isESM ? 'esm' : 'cjs',
sourcemap: 'inline',
sourcemapPathTransform(relative, sourcemapPath) {
return path.resolve(path.dirname(sourcemapPath), relative)
},
// we want to generate a single chunk like esbuild does with `splitting: false`
codeSplitting: false,
})
await bundle.close()
let result: RolldownOutput
try {
result = await bundle.generate({
format: isESM ? 'esm' : 'cjs',
sourcemap: 'inline',
sourcemapPathTransform(relative, sourcemapPath) {
return path.resolve(path.dirname(sourcemapPath), relative)
},
// we want to generate a single chunk like esbuild does with `splitting: false`
codeSplitting: false,
})
} finally {
await bundle.close()
}

const entryChunk = result.output.find(
(chunk): chunk is OutputChunk => chunk.type === 'chunk' && chunk.isEntry,
Expand Down
2 changes: 1 addition & 1 deletion playground/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ export const formatSourcemapForSnapshot = (
}
const normalized = Object.fromEntries(
Object.keys(m)
.filter((key) => m[key] !== null)
.filter((key) => m[key] != null)
.sort()
.map((key) => [key, m[key]]),
)
Expand Down
Loading
Loading