Skip to content
Open
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
87 changes: 87 additions & 0 deletions .github/actions/deploy-docs/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
name: 'Build and deploy docs'
description: >-
Build the VitePress docs site (which bundles install.sh / install.ps1 into
its public assets) and deploy it to a void.app project. Run on a Linux
runner after checkout. See rfcs/deploy-docs-on-release.md for which
workflow deploys to which project.

inputs:
void-project:
description: 'void.app project to deploy to (e.g. viteplus, viteplus-main).'
required: true
void-token:
description: 'void.app deploy token (pass secrets.VOID_TOKEN).'
required: true
cache-ref:
description: >-
Ref-scoped segment of the Vite Task cache key: main, or pr-<number> for
PR previews. Non-main refs fall back to the main cache on restore.
required: false
default: 'main'
cache-sha:
description: 'Commit sha that scopes the primary cache key.'
required: false
default: ${{ github.sha }}
site-origin:
description: >-
Origin of this deploy when it is not production viteplus.dev
(e.g. https://main.viteplus.dev). When set, the docs build rewrites the
https://vite.plus installer URLs to this origin's install scripts.
Leave empty for production.
required: false
default: ''

runs:
using: 'composite'
steps:
- uses: voidzero-dev/setup-vp@250f29ce396baf5e8f24498e17c0dfdebabc26eb # main
with:
cache: true
working-directory: docs
cache-dependency-path: docs/pnpm-lock.yaml

- name: Compute Vite Task cache keys
id: cache-keys
shell: bash
env:
CACHE_REF: ${{ inputs.cache-ref }}
CACHE_SHA: ${{ inputs.cache-sha }}
run: |
prefix="vite-task-docs-${RUNNER_OS}-${RUNNER_ARCH}"
{
echo "key=${prefix}-${CACHE_REF}-${CACHE_SHA}"
echo 'restore-keys<<EOF'
echo "${prefix}-${CACHE_REF}-"
if [ "$CACHE_REF" != 'main' ]; then
echo "${prefix}-main-"
fi
echo 'EOF'
} >> "$GITHUB_OUTPUT"

- name: Restore docs Vite Task cache
id: vite-task-cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: docs/node_modules/.vite/task-cache
key: ${{ steps.cache-keys.outputs.key }}
# Prefer this ref's newest cache; Vite Task fingerprints decide reuse.
restore-keys: ${{ steps.cache-keys.outputs.restore-keys }}

- run: vp run build
shell: bash
working-directory: docs
env:
DOCS_SITE_ORIGIN: ${{ inputs.site-origin }}

- name: Save docs Vite Task cache
if: success() && steps.vite-task-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: docs/node_modules/.vite/task-cache
key: ${{ steps.vite-task-cache.outputs.cache-primary-key }}

- run: vpx void deploy --dir docs/.vitepress/dist
shell: bash
env:
VOID_PROJECT: ${{ inputs.void-project }}
VOID_TOKEN: ${{ inputs.void-token }}
40 changes: 40 additions & 0 deletions .github/workflows/deploy-docs-main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Deploy Docs Main Preview

permissions: {}

# Deploys the docs at the head of main to main.viteplus.dev (the viteplus-main
# void.app project) so developers can preview unreleased docs. Production
# viteplus.dev deploys from release.yml instead.
# See rfcs/deploy-docs-on-release.md.
on:
push:
branches: [main]
paths:
- 'docs/**'
- 'packages/cli/install.sh'
- 'packages/cli/install.ps1'
- '.github/workflows/deploy-docs-main.yml'
- '.github/actions/deploy-docs/**'

concurrency:
group: deploy-docs-main
cancel-in-progress: true

defaults:
run:
shell: bash

jobs:
deploy:
if: github.repository == 'voidzero-dev/vite-plus'
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- uses: ./.github/actions/deploy-docs
with:
void-project: viteplus-main
void-token: ${{ secrets.VOID_TOKEN }}
site-origin: https://main.viteplus.dev
37 changes: 7 additions & 30 deletions .github/workflows/deploy-docs-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
- 'packages/cli/install.sh'
- 'packages/cli/install.ps1'
- '.github/workflows/deploy-docs-preview.yml'
- '.github/actions/deploy-docs/**'

concurrency:
group: deploy-docs-preview-${{ github.event.pull_request.number }}
Expand All @@ -28,41 +29,17 @@ jobs:
contents: read
pull-requests: write
env:
VOID_PROJECT: viteplus-staging
PREVIEW_URL: https://viteplus-staging.void.app/
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- uses: voidzero-dev/setup-vp@250f29ce396baf5e8f24498e17c0dfdebabc26eb # main
- uses: ./.github/actions/deploy-docs
with:
cache: true
working-directory: docs
cache-dependency-path: docs/pnpm-lock.yaml

- name: Restore docs Vite Task cache
id: vite-task-cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: docs/node_modules/.vite/task-cache
key: vite-task-docs-${{ runner.os }}-${{ runner.arch }}-pr-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }}
# Prefer this PR's newest cache, then fall back to main for new PRs.
restore-keys: |
vite-task-docs-${{ runner.os }}-${{ runner.arch }}-pr-${{ github.event.pull_request.number }}-
vite-task-docs-${{ runner.os }}-${{ runner.arch }}-main-

- run: vp run build
working-directory: docs

- name: Save docs Vite Task cache
if: success() && steps.vite-task-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: docs/node_modules/.vite/task-cache
key: ${{ steps.vite-task-cache.outputs.cache-primary-key }}

- run: vpx void deploy --dir docs/.vitepress/dist
env:
VOID_TOKEN: ${{ secrets.VOID_TOKEN }}
void-project: viteplus-staging
void-token: ${{ secrets.VOID_TOKEN }}
cache-ref: pr-${{ github.event.pull_request.number }}
cache-sha: ${{ github.event.pull_request.head.sha }}
site-origin: https://viteplus-staging.void.app

- name: Comment on PR
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
Expand Down
49 changes: 12 additions & 37 deletions .github/workflows/deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ name: Deploy Docs

permissions: {}

# Deploys production viteplus.dev, which also serves install.sh / install.ps1
# behind https://vite.plus. Runs from release.yml after a stable release is
# published, or manually here for urgent updates. Pushes to main deploy to
# main.viteplus.dev via deploy-docs-main.yml instead.
# See rfcs/deploy-docs-on-release.md.
on:
push:
branches: [main]
paths:
- 'docs/**'
- 'packages/cli/install.sh'
- 'packages/cli/install.ps1'
- '.github/workflows/deploy-docs.yml'
workflow_dispatch:

# Shared with the deploy-docs job in release.yml so production deploys
# serialize across both entry paths. GitHub keeps only the newest pending run
# in the group (a queued deploy replaces a pending one), so production
# converges to the newest queued content; the running deploy always completes.
concurrency:
group: deploy-docs
cancel-in-progress: false
Expand All @@ -26,37 +28,10 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
env:
VOID_PROJECT: viteplus
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- uses: voidzero-dev/setup-vp@250f29ce396baf5e8f24498e17c0dfdebabc26eb # main
- uses: ./.github/actions/deploy-docs
with:
cache: true
working-directory: docs
cache-dependency-path: docs/pnpm-lock.yaml

- name: Restore docs Vite Task cache
id: vite-task-cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: docs/node_modules/.vite/task-cache
key: vite-task-docs-${{ runner.os }}-${{ runner.arch }}-main-${{ github.sha }}
# Restore the latest main cache; Vite Task fingerprints decide reuse.
restore-keys: |
vite-task-docs-${{ runner.os }}-${{ runner.arch }}-main-

- run: vp run build
working-directory: docs

- name: Save docs Vite Task cache
if: success() && steps.vite-task-cache.outputs.cache-hit != 'true'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: docs/node_modules/.vite/task-cache
key: ${{ steps.vite-task-cache.outputs.cache-primary-key }}

- run: vpx void deploy --dir docs/.vitepress/dist
env:
VOID_TOKEN: ${{ secrets.VOID_TOKEN }}
void-project: viteplus
void-token: ${{ secrets.VOID_TOKEN }}
45 changes: 40 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,34 @@ jobs:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh release edit "v${VERSION}" --draft=false --repo "${{ github.repository }}"

# Deploy viteplus.dev from the release commit after the npm packages and the
# GitHub release are published, so the site and the install scripts always
# match the released vp. Skipped for prereleases: production docs must keep
# describing the latest stable release. See rfcs/deploy-docs-on-release.md.
deploy-docs:
name: Deploy docs
runs-on: ubuntu-latest
needs: [check, Release]
if: >-
needs.check.outputs.version_changed == 'true' &&
!contains(needs.check.outputs.version, '-')
# Shared with deploy-docs.yml so production deploys serialize across both
# entry paths. Only the newest pending run survives in the group; if this
# job's pending run is replaced by a manual dispatch, the canceled job
# holds back discord-notify and the deploy must be re-run.
concurrency:
group: deploy-docs
cancel-in-progress: false
Comment thread
fengmk2 marked this conversation as resolved.
permissions:
contents: read
steps:
- uses: taiki-e/checkout-action@7d1e50e93dc4fb3bba58f85018fadf77898aee8b # v1.4.2

- uses: ./.github/actions/deploy-docs
with:
void-project: viteplus
void-token: ${{ secrets.VOID_TOKEN }}

# Build and push the official toolchain Docker image to GHCR after the npm
# release is published (the image installs vp from npm, so the version must
# exist first). See docker/Dockerfile and docs/guide/docker.md.
Expand Down Expand Up @@ -266,15 +294,22 @@ jobs:
VP_VERSION=${{ env.VERSION }}
provenance: false

# Announce the release on Discord last, after the Docker images are published,
# so the message can include the GHCR image. Runs after the npm release
# (Release) and the images (publish-docker).
# Announce the release on Discord last, after the Docker images and the docs
# are published, so the message never points at a missing image or a site
# that still shows the previous release.
discord-notify:
name: Notify Discord
runs-on: ubuntu-latest
# publish-docker already needs Release, so depending on it orders this last.
needs: [check, publish-docker]
if: needs.check.outputs.version_changed == 'true'
# deploy-docs is skipped for prereleases; gate on its result explicitly so
# prerelease announcements still go out, while a failed docs deploy on a
# stable release holds the announcement back.
needs: [check, publish-docker, deploy-docs]
if: >-
!cancelled() &&
needs.check.outputs.version_changed == 'true' &&
needs.publish-docker.result == 'success' &&
(needs.deploy-docs.result == 'success' || needs.deploy-docs.result == 'skipped')
env:
VERSION: ${{ needs.check.outputs.version }}
IMAGE: ghcr.io/voidzero-dev/vite-plus
Expand Down
50 changes: 50 additions & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,26 @@ import { groupIconMdPlugin, groupIconVitePlugin } from 'vitepress-plugin-group-i
import llmstxt from 'vitepress-plugin-llms';
import { withMermaid } from 'vitepress-plugin-mermaid';

// Non-production deploys (the main preview, PR staging) serve their own
// copies of the install scripts and llms dumps, so the https://vite.plus
// installer shortcuts and absolute site URLs must point at the deploy's
// origin instead of production. The deploy workflows set DOCS_SITE_ORIGIN via
// the deploy-docs composite action; markdown content is rewritten through
// markdown-it below, and Vue components read the __DOCS_*__ define constants.
const siteOrigin = process.env.DOCS_SITE_ORIGIN;
const docsOrigin = siteOrigin || 'https://viteplus.dev';
const installShUrl = siteOrigin ? `${siteOrigin}/install.sh` : 'https://vite.plus';
const installPs1Url = siteOrigin ? `${siteOrigin}/install.ps1` : 'https://vite.plus/ps1';

function rewriteInstallUrls(text: string): string {
if (!siteOrigin) {
return text;
}
return text
.replaceAll('https://vite.plus/ps1', installPs1Url)
.replaceAll('https://vite.plus', installShUrl);
}

const taskRunnerGuideItems = [
{
text: 'Run',
Expand Down Expand Up @@ -113,6 +133,11 @@ export default extendConfig(
['meta', { name: 'twitter:site', content: '@voidzerodev' }],
],
vite: {
define: {
__DOCS_ORIGIN__: JSON.stringify(docsOrigin),
__DOCS_INSTALL_SH_URL__: JSON.stringify(installShUrl),
__DOCS_INSTALL_PS1_URL__: JSON.stringify(installPs1Url),
},
optimizeDeps: {
include: ['mermaid > @braintree/sanitize-url'],
},
Expand Down Expand Up @@ -258,6 +283,31 @@ export default extendConfig(
markdown: {
config(md) {
md.use(groupIconMdPlugin);
if (siteOrigin) {
md.core.ruler.push('rewrite-install-urls', (state) => {
const walk = (tokens: typeof state.tokens) => {
for (const token of tokens) {
if (
token.type === 'fence' ||
token.type === 'code_inline' ||
token.type === 'text'
) {
token.content = rewriteInstallUrls(token.content);
}
if (token.type === 'link_open') {
const href = token.attrGet('href');
if (href) {
token.attrSet('href', rewriteInstallUrls(href));
}
}
if (token.children) {
walk(token.children);
}
}
};
walk(state.tokens);
});
}
},
},
}),
Expand Down
10 changes: 10 additions & 0 deletions docs/.vitepress/env.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
// Build-time constants injected via vite.define in config.mts. They point at
// the current deploy's origin (production, main preview, or PR staging). The
// dunder names follow the Vite convention for compile-time replaced globals.
// oxlint-disable-next-line no-underscore-dangle
declare const __DOCS_ORIGIN__: string;
// oxlint-disable-next-line no-underscore-dangle
declare const __DOCS_INSTALL_SH_URL__: string;
// oxlint-disable-next-line no-underscore-dangle
declare const __DOCS_INSTALL_PS1_URL__: string;

// Vue SFC module declaration
declare module '*.vue' {
import type { DefineComponent } from 'vue';
Expand Down
Loading
Loading