From d092712bc00132ab1c030ba647806c0a96aceefa Mon Sep 17 00:00:00 2001 From: lazarv Date: Mon, 2 Sep 2024 01:25:12 +0200 Subject: [PATCH] feat: ci/cd --- .eslintignore | 10 + .eslintrc.cjs | 72 -- .eslintrc.json | 77 ++ .github/ISSUE_TEMPLATE/bug_report.yml | 86 ++ .github/ISSUE_TEMPLATE/config.yml | 6 + .github/ISSUE_TEMPLATE/docs.yml | 44 + .github/ISSUE_TEMPLATE/feature_request.yml | 48 + .github/PULL_REQUEST_TEMPLATE.md | 12 + .github/commit-convention.md | 37 + .github/workflows/ci.yml | 150 +++ .github/workflows/docs.yml | 71 ++ .github/workflows/issue-close-require.yml | 20 + .github/workflows/issue-labeled.yml | 50 + .github/workflows/lock-closed-issues.yml | 26 + .github/workflows/publish-commit.yml | 106 ++ .github/workflows/release-experimental.yml | 115 +++ .github/workflows/semantic-pull-request.yml | 57 ++ .gitignore | 3 +- .prettierignore | 4 + .prettierrc | 11 + .vscode/settings.json | 2 +- commitlint.config.mjs | 1 + docs/src/components/AlgoliaSearch.jsx | 3 +- docs/src/components/CopyToClipboard.jsx | 3 +- docs/src/components/Sidebar.jsx | 1 + docs/src/components/TableOfContents.jsx | 3 +- .../[[lang]]/(sidebar).[...slug].page.jsx | 10 +- examples/express/src/app/index.jsx | 2 +- examples/nestjs/.eslintrc.js | 25 - examples/nestjs/.prettierrc | 4 - examples/nestjs/src/app.controller.spec.ts | 13 +- examples/nestjs/src/app.controller.ts | 5 +- examples/nestjs/src/app.module.ts | 17 +- examples/nestjs/src/app.service.ts | 4 +- examples/nestjs/src/app/Counter.tsx | 4 +- examples/nestjs/src/app/index.tsx | 4 +- examples/nestjs/src/main.ts | 5 +- .../nestjs/src/react-server-dev.middleware.ts | 8 +- .../src/react-server-prod.middleware.ts | 8 +- examples/nestjs/test/app.e2e-spec.ts | 17 +- examples/photos/src/app/(root).layout.tsx | 1 + examples/react-router/src/index.jsx | 6 +- examples/react-router/src/routes/contact.jsx | 10 +- examples/react-router/src/routes/destroy.jsx | 1 + examples/react-router/src/routes/edit.jsx | 3 +- examples/react-router/src/routes/root.jsx | 9 +- examples/remote/index.jsx | 1 + examples/remote/remote.jsx | 13 +- examples/remote/streaming.jsx | 3 +- examples/spa/postcss.config.js | 2 +- examples/spa/src/index.jsx | 6 +- examples/tanstack-router/postcss.config.js | 2 +- examples/tanstack-router/src/app/layout.tsx | 3 +- .../tanstack-router/src/components/App.tsx | 4 +- examples/todo/postcss.config.js | 2 +- examples/todo/src/AddTodo.tsx | 1 + package.json | 28 +- .../react-server-adapter-vercel/README.md | 2 +- .../react-server-adapter-vercel/index.mjs | 13 +- packages/react-server-router/README.md | 2 +- packages/react-server-router/index.jsx | 8 +- packages/react-server-router/plugin.mjs | 117 +-- packages/react-server/bin/cli.mjs | 1 + packages/react-server/bin/commands/help.mjs | 2 +- packages/react-server/bin/help.mjs | 250 ++--- .../react-server/client/ClientProvider.jsx | 1 + .../react-server/client/ErrorBoundary.jsx | 1 + packages/react-server/client/entry.client.jsx | 8 +- packages/react-server/client/navigation.jsx | 1 + packages/react-server/config/index.mjs | 4 +- .../react-server/lib/async-local-storage.mjs | 1 + packages/react-server/lib/build/action.mjs | 1 - packages/react-server/lib/build/server.mjs | 17 +- packages/react-server/lib/build/static.mjs | 19 +- packages/react-server/lib/dev/action.mjs | 2 +- .../react-server/lib/dev/create-logger.mjs | 1 + .../react-server/lib/dev/create-server.mjs | 9 +- packages/react-server/lib/dev/index.d.ts | 1 + packages/react-server/lib/dev/index.mjs | 2 +- .../react-server/lib/dev/render-stream.mjs | 7 +- packages/react-server/lib/dev/ssr-handler.mjs | 2 +- packages/react-server/lib/handlers/error.mjs | 14 +- .../lib/handlers/static-watch.mjs | 1 + packages/react-server/lib/handlers/static.mjs | 1 + .../react-server/lib/loader/module-alias.mjs | 3 +- packages/react-server/lib/loader/utils.mjs | 2 +- .../lib/plugins/react-server-eval.mjs | 2 +- .../lib/plugins/react-server-runtime.mjs | 1 + .../react-server/lib/plugins/use-client.mjs | 4 +- .../lib/plugins/use-server-inline.mjs | 4 +- .../react-server/lib/plugins/use-server.mjs | 5 +- packages/react-server/lib/start/action.mjs | 4 +- packages/react-server/lib/start/manifest.mjs | 23 +- packages/react-server/lib/start/node.mjs | 2 +- .../react-server/server/ErrorBoundary.jsx | 3 +- .../react-server/server/RemoteComponent.jsx | 4 +- .../react-server/server/action-register.mjs | 1 + packages/react-server/server/action-state.mjs | 7 +- .../react-server/server/create-worker.mjs | 1 + packages/react-server/server/dom-flight.mjs | 4 +- .../react-server/server/error-boundary.jsx | 1 + .../react-server/server/module-loader.mjs | 1 + packages/react-server/server/prerender.jsx | 2 +- packages/react-server/server/render-dom.mjs | 12 +- packages/react-server/server/render-rsc.jsx | 19 +- packages/react-server/server/router.d.ts | 2 +- packages/react-server/server/router.jsx | 2 +- pnpm-lock.yaml | 936 +++++++++++++++++- test/__test__/basic.spec.mjs | 3 +- test/__test__/memory-cache.spec.mjs | 2 +- test/fixtures/client-only.jsx | 1 + test/fixtures/error-boundary.jsx | 3 +- test/fixtures/html-client-only.jsx | 3 +- test/fixtures/html-counter.jsx | 2 +- test/fixtures/html-use-action-state.jsx | 2 +- test/fixtures/router-actionstate.jsx | 2 +- test/fixtures/use-action-state.jsx | 1 + test/package.json | 2 +- test/vitest.config.build.mjs | 6 + test/vitest.config.mjs | 5 + test/vitestGlobalSetup.mjs | 1 + test/vitestSetup.mjs | 1 + 122 files changed, 2281 insertions(+), 525 deletions(-) create mode 100644 .eslintignore delete mode 100644 .eslintrc.cjs create mode 100644 .eslintrc.json create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/docs.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/commit-convention.md create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/docs.yml create mode 100644 .github/workflows/issue-close-require.yml create mode 100644 .github/workflows/issue-labeled.yml create mode 100644 .github/workflows/lock-closed-issues.yml create mode 100644 .github/workflows/publish-commit.yml create mode 100644 .github/workflows/release-experimental.yml create mode 100644 .github/workflows/semantic-pull-request.yml create mode 100644 .prettierignore create mode 100644 .prettierrc create mode 100644 commitlint.config.mjs delete mode 100644 examples/nestjs/.eslintrc.js delete mode 100644 examples/nestjs/.prettierrc create mode 100644 test/vitest.config.build.mjs diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..a597769 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,10 @@ +node_modules +dist +build +.react-server +.vercel +packages/react-server-router/react-server-router.d.ts +*.mdx +*.md +*.json +*-lock.* diff --git a/.eslintrc.cjs b/.eslintrc.cjs deleted file mode 100644 index 450f1dd..0000000 --- a/.eslintrc.cjs +++ /dev/null @@ -1,72 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true, - node: true, - }, - extends: [ - "eslint:recommended", - "plugin:react/recommended", - "plugin:react/jsx-runtime", - "plugin:jsx-a11y/recommended", - "prettier", - ], - overrides: [ - { - env: { - node: true, - }, - files: [".eslintrc.{js,cjs}"], - parserOptions: { - sourceType: "script", - }, - }, - { - env: { - node: true, - }, - files: ["*.{ts,tsx}"], - extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - parser: "@typescript-eslint/parser", - plugins: ["@typescript-eslint"], - rules: { - "@typescript-eslint/no-unused-vars": [ - "error", - { argsIgnorePattern: "^_" }, - ], - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/explicit-module-boundary-types": "off", - }, - }, - ], - parser: "@babel/eslint-parser", - parserOptions: { - requireConfigFile: false, - babelOptions: { - presets: ["@babel/preset-react"], - plugins: ["@babel/plugin-syntax-import-assertions"], - }, - ecmaFeatures: { - jsx: true, - }, - sourceType: "module", - }, - plugins: ["react", "simple-import-sort", "jsx-a11y"], - settings: { - react: { - version: "experimental", - }, - }, - rules: { - "react/prop-types": "off", - "simple-import-sort/imports": ["error"], - }, - exclude: [ - "node_modules", - "dist", - "build", - ".eslintrc.{js,cjs}", - ".react-server", - ".vercel", - ], -}; diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..bd7927c --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,77 @@ +{ + "env": { + "browser": true, + "es2021": true, + "node": true + }, + "globals": { + "Deno": "readonly" + }, + "extends": [ + "eslint:recommended", + "plugin:react/recommended", + "plugin:react/jsx-runtime", + "plugin:jsx-a11y/recommended", + "plugin:prettier/recommended" + ], + "overrides": [ + { + "env": { + "node": true + }, + "files": [".eslintrc.{js,cjs}"], + "parserOptions": { + "sourceType": "script" + } + }, + { + "env": { + "node": true + }, + "files": ["*.{ts,tsx}"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "rules": { + "@typescript-eslint/no-unused-vars": [ + "error", + { "argsIgnorePattern": "^_" } + ], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + } + } + ], + "parser": "@babel/eslint-parser", + "parserOptions": { + "requireConfigFile": false, + "babelOptions": { + "presets": ["@babel/preset-react"], + "plugins": ["@babel/plugin-syntax-import-assertions"] + }, + "ecmaFeatures": { + "jsx": true + }, + "sourceType": "module" + }, + "plugins": ["react", "simple-import-sort", "prettier", "jsx-a11y"], + "settings": { + "react": { + "version": "19.0.0" + } + }, + "rules": { + "react/prop-types": "off", + "simple-import-sort/imports": [ + "error", + { + "groups": [["^\\u0000"], ["^node:"], ["^react"], ["^[^.]"], ["^\\."]] + } + ], + "no-async-promise-executor": "off", + "prettier/prettier": ["error", { "endOfLine": "auto" }] + } +} diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..db5202d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,86 @@ +# This issue template is based on https://github.com/vitejs/vite/tree/main/.github/ISSUE_TEMPLATE +name: "\U0001F41E Bug report" +description: Report an issue with @lazarv/react-server +labels: [pending triage] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: textarea + id: bug-description + attributes: + label: Describe the bug + description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks! + placeholder: I am doing ... What I expect is ... What actually happening is ... + validations: + required: true + - type: input + id: reproduction + attributes: + label: Reproduction + description: Please provide a link to a repo that can reproduce the problem you ran into. Please provide a [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) if possible. + placeholder: Reproduction URL + - type: textarea + id: reproduction-steps + attributes: + label: Steps to reproduce + description: Please provide any reproduction steps that may need to be described. E.g. if it happens only when running the dev or build script make sure it's clear which one to use. + placeholder: Run `npm install` followed by `npm run dev` + - type: textarea + id: system-info + attributes: + label: System Info + description: Output of `npx envinfo --system --npmPackages '{@lazarv/react-server,@lazarv/react-server-*,react,react-dom,react-server-dom-webpack,vite}' --binaries --browsers` + render: shell + placeholder: System, Binaries, Browsers + validations: + required: true + - type: dropdown + id: package-manager + attributes: + label: Used Package Manager + description: Select the used package manager + options: + - npm + - yarn + - pnpm + validations: + required: true + - type: textarea + id: logs + attributes: + label: Logs + description: | + Optional if provided reproduction. Please try not to insert an image but copy paste the log text. + + 1. Run `react-server` or `react-server build` with the `DEBUG=*` environment variable set. + 2. Provide the error log here in the format below. + + ```` +
+ Click to expand! + + ```shell + // paste the log text here + ``` +
+ ```` + - type: checkboxes + id: checkboxes + attributes: + label: Validations + description: Before submitting the issue, please make sure you do the following + options: + - label: Follow our [Code of Conduct](https://github.com/lazarv/react-server/blob/main/CODE_OF_CONDUCT.md) + required: true + - label: Read the [Contributing Guidelines](https://github.com/lazarv/react-server/blob/main/CONTRIBUTING.md). + required: true + - label: Read the [docs](https://react-server.dev). + required: true + - label: Check that there isn't [already an issue](https://github.com/lazarv/react-server/issues) that reports the same bug to avoid creating a duplicate. + required: true + - label: Check that this is a concrete bug. For Q&A open a [GitHub Discussion](https://github.com/lazarv/react-server/discussions). + required: true + - label: The provided reproduction is a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) of the bug. + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..80c10f7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,6 @@ +# This issue template is based on https://github.com/vitejs/vite/tree/main/.github/ISSUE_TEMPLATE +blank_issues_enabled: false +contact_links: + - name: Questions & Discussions + url: https://github.com/lazarv/react-server/discussions + about: Use GitHub discussions for message-board style questions and discussions. diff --git a/.github/ISSUE_TEMPLATE/docs.yml b/.github/ISSUE_TEMPLATE/docs.yml new file mode 100644 index 0000000..bbd28a6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/docs.yml @@ -0,0 +1,44 @@ +# This issue template is based on https://github.com/vitejs/vite/tree/main/.github/ISSUE_TEMPLATE +name: "\U0001F4DA Documentation" +description: Suggest a change or new page to be added to react-server.dev +labels: [documentation] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this issue! + - type: checkboxes + id: documentation_is + attributes: + label: Documentation is + options: + - label: Missing + - label: Outdated + - label: Confusing + - label: Not sure? + - type: textarea + id: description + attributes: + label: Explain in Detail + description: A clear and concise description of your suggestion. If you intend to submit a PR for this issue, tell us in the description. Thanks! + placeholder: The description of ... page is not clear. I thought it meant ... but it wasn't. + validations: + required: true + - type: textarea + id: suggestion + attributes: + label: Your Suggestion for Changes + validations: + required: true + - type: input + id: reproduction + attributes: + label: Reproduction + description: If you have a reproduction, please provide a link to a repo that can reproduce the problem you ran into. + placeholder: Reproduction URL + - type: textarea + id: reproduction-steps + attributes: + label: Steps to reproduce + description: Please provide any reproduction steps that may need to be described. E.g. if it happens only when running the dev or build script make sure it's clear which one to use. + placeholder: Run `npm install` followed by `npm run dev` diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..4373b6c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,48 @@ +# This issue template is based on https://github.com/vitejs/vite/tree/main/.github/ISSUE_TEMPLATE +name: "\U0001F680 New feature proposal" +description: Propose a new feature to be added to @lazarv/react-server +labels: ["enhancement: pending triage"] +body: + - type: markdown + attributes: + value: | + Thanks for your interest in the project and taking the time to fill out this feature report! + - type: textarea + id: feature-description + attributes: + label: Description + description: "Clear and concise description of the problem. Please make the reason and usecases as detailed as possible. If you intend to submit a PR for this issue, tell us in the description. Thanks!" + placeholder: As a developer using @lazarv/react-server I want [goal / wish] so that [benefit]. + validations: + required: true + - type: textarea + id: suggested-solution + attributes: + label: Suggested solution + description: "In module [xy] we could provide following implementation..." + validations: + required: true + - type: textarea + id: alternative + attributes: + label: Alternative + description: Clear and concise description of any alternative solutions or features you've considered. + - type: textarea + id: additional-context + attributes: + label: Additional context + description: Any other context or screenshots about the feature request here. + - type: checkboxes + id: checkboxes + attributes: + label: Validations + description: Before submitting the issue, please make sure you do the following + options: + - label: Follow our [Code of Conduct](https://github.com/lazarv/react-server/blob/main/CODE_OF_CONDUCT.md) + required: true + - label: Read the [Contributing Guidelines](https://github.com/lazarv/react-server/blob/main/CONTRIBUTING.md). + required: true + - label: Read the [docs](https://react-server.dev). + required: true + - label: Check that there isn't already an issue that request the same feature to avoid creating a duplicate. + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..096e6a6 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ + + + diff --git a/.github/commit-convention.md b/.github/commit-convention.md new file mode 100644 index 0000000..4971cff --- /dev/null +++ b/.github/commit-convention.md @@ -0,0 +1,37 @@ +## Git Commit Message Convention + +> This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-angular). + +#### TL;DR: + +Messages must be matched by the following regex: + + +```js +/^(revert: )?(feat|fix|docs|style|refactor|perf|test|build|ci|chore)(\(.+\))?!?: .{1,50}/ +``` + +#### Examples + +``` +feat(dev): add 'comments' option +fix(dev): fix dev error +perf(build)!: remove 'foo' option +revert: feat(compiler): add 'comments' option +``` + +### Revert + +If the PR reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit + +### Scope + +The scope could be anything specifying the place of the commit change. For example `dev`, `build`, `workflow`, `cli` etc... + +### Subject + +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 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..4c09e97 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,150 @@ +# This workflow is based on https://github.com/vitejs/vite/tree/main/.github/workflows +name: CI ๐Ÿงช + +env: + # 7 GiB by default on GitHub, setting to 6 GiB + # https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources + NODE_OPTIONS: --max-old-space-size=6144 + # install playwright binary manually (because pnpm only runs install script once) + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1" + # Vitest auto retry on flaky segfault + VITEST_SEGFAULT_RETRY: 3 + +# Remove default permissions of GITHUB_TOKEN for security +# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs +permissions: {} + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.number || github.sha }} + cancel-in-progress: true + +jobs: + changed: + name: Get changed files ๐Ÿ“‚ + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.changed-files.outputs.any_changed != 'true' }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Assume PRs are less than 50 commits + fetch-depth: 50 + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v45 + with: + files: | + packages/** + test/** + .github/workflows/ci.yml + + test: + needs: changed + if: needs.changed.outputs.should_skip != 'true' + timeout-minutes: 20 + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + node_version: [20, 22] + include: + # Active LTS + other OS + - os: macos-latest + node_version: 20 + - os: windows-latest + node_version: 20 + fail-fast: false + + name: "Test ๐Ÿงช node.js v${{ matrix.node_version }} on ${{ matrix.os }}" + steps: + - name: Checkout + uses: actions/checkout@v4 + + - run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + + - name: Set node version to ${{ matrix.node_version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node_version }} + cache: "pnpm" + + - name: Install deps + run: pnpm install + + # Install playwright's binary under custom directory to cache + - name: (non-windows) Set Playwright path and Get playwright version + if: runner.os != 'Windows' + run: | + echo "PLAYWRIGHT_BROWSERS_PATH=$HOME/.cache/playwright-bin" >> $GITHUB_ENV + PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')" + echo "PLAYWRIGHT_VERSION=$PLAYWRIGHT_VERSION" >> $GITHUB_ENV + - name: (windows) Set Playwright path and Get playwright version + if: runner.os == 'Windows' + run: | + echo "PLAYWRIGHT_BROWSERS_PATH=$HOME\.cache\playwright-bin" >> $env:GITHUB_ENV + $env:PLAYWRIGHT_VERSION="$(pnpm ls --depth 0 --json -w playwright-chromium | jq --raw-output '.[0].devDependencies["playwright-chromium"].version')" + echo "PLAYWRIGHT_VERSION=$env:PLAYWRIGHT_VERSION" >> $env:GITHUB_ENV + + - name: Cache Playwright's binary + uses: actions/cache@v4 + with: + key: ${{ runner.os }}-playwright-bin-v1-${{ env.PLAYWRIGHT_VERSION }} + path: ${{ env.PLAYWRIGHT_BROWSERS_PATH }} + restore-keys: | + ${{ runner.os }}-playwright-bin-v1- + + - name: Install Playwright + working-directory: ./test + # does not need to explicitly set chromium after https://github.com/microsoft/playwright/issues/14862 is solved + run: pnpm playwright install chromium + + - name: Test development + working-directory: ./test + run: pnpm test-dev + + - name: Test build and production mode + working-directory: ./test + run: pnpm test-build-start + + lint: + timeout-minutes: 10 + runs-on: ubuntu-latest + name: Lint ๐Ÿงน + steps: + - uses: actions/checkout@v4 + + - run: corepack enable + - name: Set node version to 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + + - name: Install deps + run: pnpm install + + - name: Lint + run: pnpm run lint + + - name: Check formatting + run: pnpm prettier --check . + + # From https://github.com/rhysd/actionlint/blob/main/docs/usage.md#use-actionlint-on-github-actions + - name: Check workflow files + run: | + bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) + ./actionlint -color -shellcheck="" diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..2b663be --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,71 @@ +# This workflow is based on https://github.com/vitejs/vite/tree/main/.github/workflows +name: Documentation ๐Ÿ“š + +on: + push: + branches: + - main + paths: + - "docs/**" + pull_request: + types: [opened, synchronize, reopened] + paths: + - "docs/**" + workflow_dispatch: + +jobs: + deploy: + name: Deploy ๐Ÿš€ + if: github.repository == 'lazarv/react-server-testing' + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + steps: + - uses: actions/checkout@v4 + + - run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + + - name: Install deps + run: pnpm install + + - name: Install Vercel CLI + run: npm install -g vercel@latest + + - name: Pull Vercel Environment Information + working-directory: ./docs + env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} + + - name: Build docs + run: pnpm run docs:build + + - name: Deploy Project Artifacts to Vercel + if: ${{ github.event_name == 'pull_request' }} + working-directory: ./docs + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + run: | + url=$(vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }}) + echo "VERCEL_URL=${url}" >> $GITHUB_ENV + + - uses: marocchino/sticky-pull-request-comment@v2 + if: github.event_name == 'pull_request' + with: + header: pr-docs-preview-url + message: | + โœ… Documentation preview deployed to: ${{ env.VERCEL_URL }} + + - name: Deploy Project Artifacts to Vercel Production Environment + if: ${{ github.ref == 'refs/heads/main' }} + working-directory: ./docs + env: + VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} + run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} diff --git a/.github/workflows/issue-close-require.yml b/.github/workflows/issue-close-require.yml new file mode 100644 index 0000000..b9c9efc --- /dev/null +++ b/.github/workflows/issue-close-require.yml @@ -0,0 +1,20 @@ +# This workflow is based on https://github.com/vitejs/vite/tree/main/.github/workflows +name: Issue Close Require ๐Ÿ”’ + +on: + schedule: + - cron: "0 0 * * *" + +jobs: + close-issues: + name: Close issues ๐Ÿ”’ + if: github.repository == 'lazarv/react-server-testing' + runs-on: ubuntu-latest + steps: + - name: needs reproduction + uses: actions-cool/issues-helper@v3 + with: + actions: "close-issues" + token: ${{ secrets.GITHUB_TOKEN }} + labels: "needs reproduction" + inactive-day: 30 diff --git a/.github/workflows/issue-labeled.yml b/.github/workflows/issue-labeled.yml new file mode 100644 index 0000000..80d5190 --- /dev/null +++ b/.github/workflows/issue-labeled.yml @@ -0,0 +1,50 @@ +# This workflow is based on https://github.com/vitejs/vite/tree/main/.github/workflows +name: Issue Labeled ๐Ÿ”– + +on: + issues: + types: [labeled] + +jobs: + reply-labeled: + name: Reply to labeled issue ๐Ÿ’ฌ + if: github.repository == 'lazarv/react-server-testing' + runs-on: ubuntu-latest + steps: + - name: contribution welcome + if: github.event.label.name == 'contribution welcome' || github.event.label.name == 'help wanted' + uses: actions-cool/issues-helper@v3 + with: + actions: "remove-labels" + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + labels: "pending triage, needs reproduction" + + - name: remove pending + if: contains(github.event.label.description, '(priority)') && contains(github.event.issue.labels.*.name, 'pending triage') + uses: actions-cool/issues-helper@v3 + with: + actions: "remove-labels" + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + labels: "pending triage" + + - name: remove enhancement pending + if: "(github.event.label.name == 'enhancement' || contains(github.event.label.description, '(priority)')) && contains(github.event.issue.labels.*.name, 'enhancement: pending triage')" + uses: actions-cool/issues-helper@v3 + with: + actions: "remove-labels" + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + labels: "enhancement: pending triage" + + - name: needs reproduction + if: github.event.label.name == 'needs reproduction' + uses: actions-cool/issues-helper@v3 + with: + actions: "create-comment, remove-labels" + token: ${{ secrets.GITHUB_TOKEN }} + issue-number: ${{ github.event.issue.number }} + body: | + Hello @${{ github.event.issue.user.login }}. Please provide a [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) using a GitHub repository. Issues marked with `needs reproduction` will be closed if they have no activity within 30 days. + labels: "pending triage" diff --git a/.github/workflows/lock-closed-issues.yml b/.github/workflows/lock-closed-issues.yml new file mode 100644 index 0000000..c022faf --- /dev/null +++ b/.github/workflows/lock-closed-issues.yml @@ -0,0 +1,26 @@ +# This workflow is based on https://github.com/vitejs/vite/tree/main/.github/workflows +name: Lock Closed Issues ๐Ÿ”’ + +on: + schedule: + - cron: "0 0 * * *" + +permissions: + issues: write + +jobs: + action: + name: Lock closed issues ๐Ÿ”’ + if: github.repository == 'lazarv/react-server-testing' + runs-on: ubuntu-latest + steps: + - uses: dessant/lock-threads@v5 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + issue-inactive-days: "30" + issue-comment: | + This issue has been locked since it has been closed for more than 30 days. + + If you have found a concrete bug or regression related to it, please open a new [bug report](https://github.com/lazarv/react-server/issues/new/choose) with a reproduction against the latest version of @lazarv/react-server. If you have any other comments you should create a new [discussion](https://github.com/lazarv/react-server/discussions). + issue-lock-reason: "" + process-only: "issues" diff --git a/.github/workflows/publish-commit.yml b/.github/workflows/publish-commit.yml new file mode 100644 index 0000000..1c8aacc --- /dev/null +++ b/.github/workflows/publish-commit.yml @@ -0,0 +1,106 @@ +# This workflow is based on https://github.com/vitejs/vite/tree/main/.github/workflows +name: Publish Any Commit ๐Ÿš€ + +env: + # install playwright binary manually (because pnpm only runs install script once) + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1" + +on: + push: + branches: + - main + tags: + - "!**" + issue_comment: + types: [created] + +jobs: + changed: + name: Get changed files ๐Ÿ“‚ + runs-on: ubuntu-latest + outputs: + all_changed_files: ${{ steps.changed-files.outputs.all_changed_files }} + should_skip: ${{ steps.changed-files.outputs.any_changed != 'true' }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Assume PRs are less than 50 commits + fetch-depth: 50 + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v45 + with: + files: | + packages/** + + build: + name: Build ๐Ÿš€ + needs: changed + if: github.repository == 'lazarv/react-server-testing' && needs.changed.outputs.should_skip != 'true' && (github.event_name == 'push' || github.event.issue.pull_request && startsWith(github.event.comment.body, '/pkg-pr-new')) + runs-on: ubuntu-latest + + steps: + - if: github.event.issue.pull_request + uses: actions/github-script@v7 + with: + script: | + const user = context.payload.sender.login + console.log(`Validate user: ${user}`) + + let hasTriagePermission = false + try { + const { data } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: user, + }); + hasTriagePermission = data.user.permissions.triage + } catch (e) { + console.warn(e) + } + + if (hasTriagePermission) { + 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: Checkout code + uses: actions/checkout@v4 + + - run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + + - name: Install dependencies + run: pnpm install + + - name: Publish @lazarv/react-server + if: contains(needs.changed.outputs.all_changed_files, 'packages/react-server/') + run: pnpm dlx pkg-pr-new@0.0 publish --compact --pnpm ./packages/react-server --comment=update + + - name: Publish @lazarv/react-server-router + if: contains(needs.changed.outputs.all_changed_files, 'packages/react-server-router/') + run: pnpm dlx pkg-pr-new@0.0 publish --compact --pnpm ./packages/react-server-router --comment=update + + - name: Publish @lazarv/react-server-adapter-vercel + if: contains(needs.changed.outputs.all_changed_files, 'packages/react-server-adapter-vercel/') + run: pnpm dlx pkg-pr-new@0.0 publish --compact --pnpm ./packages/react-server-adapter-vercel --comment=update diff --git a/.github/workflows/release-experimental.yml b/.github/workflows/release-experimental.yml new file mode 100644 index 0000000..fd792c8 --- /dev/null +++ b/.github/workflows/release-experimental.yml @@ -0,0 +1,115 @@ +name: Release (experimental) ๐Ÿ“ฆ + +on: + workflow_run: + workflows: ["CI ๐Ÿงช"] + types: + - completed + workflow_dispatch: + +permissions: + actions: write # Necessary to cancel workflow executions + checks: write # Necessary to write reports + pull-requests: write # Necessary to comment on PRs + contents: write # Necessary to create a release + +concurrency: + group: ${{ github.workflow }}-${{ github.sha }} + cancel-in-progress: true + +jobs: + changed: + name: Get changed files ๐Ÿ“‚ + if: ${{ github.repository == 'lazarv/react-server-testing' }} + runs-on: ubuntu-latest + outputs: + should_skip: ${{ steps.changed-files.outputs.any_changed != 'true' }} + all_changed_files: ${{ steps.changed-files.outputs.all_changed_files }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + # Assume PRs are less than 50 commits + fetch-depth: 50 + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v45 + with: + files: | + packages/** + + release: + name: Release ๐Ÿ“ฆ + needs: changed + if: github.repository == 'lazarv/react-server-testing' && needs.changed.outputs.should_skip != 'true' && github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'main' && github.event.workflow_run.event == 'push' + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - run: corepack enable + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: "pnpm" + registry-url: https://registry.npmjs.org + + - name: Install dependencies + run: pnpm install + + - name: Generate version + run: | + VERSION="0.0.0-experimental-$(git rev-parse --short HEAD)-$(date +'%Y%m%d')-$(openssl rand -hex 4)" + echo "VERSION=$VERSION" >> $GITHUB_ENV + + - name: Prepare @lazarv/react-server + if: contains(needs.changed.outputs.all_changed_files, 'packages/react-server') + working-directory: ./packages/react-server + run: | + jq --arg new_version "${{ env.VERSION }}" '.version = $new_version' package.json > tmp.json && mv tmp.json package.json + rm ./README.md + cp ../../README.md ./README.md + + - name: Publish @lazarv/react-server + id: publish-react-server + if: contains(needs.changed.outputs.all_changed_files, 'packages/react-server') + working-directory: ./packages/react-server + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: pnpm publish --access=public --no-git-checks + + - name: Create release + if: steps.publish-react-server.outcome == 'success' + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "v${{ env.VERSION }}" --generate-notes + + - name: Prepare @lazarv/react-server-router + if: contains(needs.changed.outputs.all_changed_files, 'packages/react-server-router') + working-directory: ./packages/react-server-router + run: | + jq --arg new_version "${{ env.VERSION }}" '.version = $new_version' package.json > tmp.json && mv tmp.json package.json + + - name: Publish @lazarv/react-server-router + if: contains(needs.changed.outputs.all_changed_files, 'packages/react-server-router') + working-directory: ./packages/react-server-router + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: pnpm publish --access=public --no-git-checks + + - name: Prepare @lazarv/react-server-adapter-vercel + if: contains(needs.changed.outputs.all_changed_files, 'packages/react-server-adapter-vercel') + working-directory: ./packages/react-server-adapter-vercel + run: | + jq --arg new_version "${{ env.VERSION }}" '.version = $new_version' package.json > tmp.json && mv tmp.json package.json + + - name: Publish @lazarv/react-server-adapter-vercel + if: contains(needs.changed.outputs.all_changed_files, 'packages/react-server-adapter-vercel') + working-directory: ./packages/react-server-adapter-vercel + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_ACCESS_TOKEN }} + run: pnpm publish --access=public --no-git-checks diff --git a/.github/workflows/semantic-pull-request.yml b/.github/workflows/semantic-pull-request.yml new file mode 100644 index 0000000..10d58cf --- /dev/null +++ b/.github/workflows/semantic-pull-request.yml @@ -0,0 +1,57 @@ +# This workflow is based on https://github.com/vitejs/vite/tree/main/.github/workflows +name: Semantic Pull Request ๐Ÿ” + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +permissions: + actions: write # Necessary to cancel workflow executions + checks: write # Necessary to write reports + pull-requests: write # Necessary to comment on PRs + contents: read + +jobs: + main: + if: github.repository == 'lazarv/react-server-testing' + runs-on: ubuntu-latest + name: Semantic Pull Request ๐Ÿ” + steps: + - name: Validate PR title + uses: amannn/action-semantic-pull-request@v5 + id: lint_pr_title + with: + subjectPattern: ^(?![A-Z]).+$ + subjectPatternError: | + The subject "{subject}" found in the pull request title "{title}" + didn't match the configured pattern. Please ensure that the subject + doesn't start with an uppercase character. + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - uses: marocchino/sticky-pull-request-comment@v2 + # When the previous steps fails, the workflow would stop. By adding this + # condition you can continue the execution with the populated error message. + if: always() && (steps.lint_pr_title.outputs.error_message != null) + with: + header: pr-title-lint-error + message: | + Hey there and thank you for opening this pull request! ๐Ÿ‘‹๐Ÿผ + + We require pull request titles to follow the [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/) and it looks like your proposed title needs to be adjusted. + + Details: + + ``` + ${{ steps.lint_pr_title.outputs.error_message }} + ``` + + # Delete a previous comment when the issue has been resolved + - if: ${{ steps.lint_pr_title.outputs.error_message == null }} + uses: marocchino/sticky-pull-request-comment@v2 + with: + header: pr-title-lint-error + delete: true diff --git a/.gitignore b/.gitignore index f3db319..3b872ea 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ node_modules .vercel *.pem *.sqlite -*.log \ No newline at end of file +*.log +.eslintcache diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..e09fbd7 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,4 @@ +*.mdx +*.md +*.gen.ts +*-lock.* \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..269281c --- /dev/null +++ b/.prettierrc @@ -0,0 +1,11 @@ +{ + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": false, + "quoteProps": "as-needed", + "trailingComma": "es5", + "bracketSpacing": true, + "bracketSameLine": false +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 1d35bbd..f36fb3c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,7 @@ { "typescript.tsdk": "node_modules/typescript/lib", "editor.codeActionsOnSave": { - "source.organizeImports": "always" + "source.fixAll.eslint": "always" }, "[mdx]": { "editor.codeActionsOnSave": { diff --git a/commitlint.config.mjs b/commitlint.config.mjs new file mode 100644 index 0000000..fa584fb --- /dev/null +++ b/commitlint.config.mjs @@ -0,0 +1 @@ +export default { extends: ["@commitlint/config-conventional"] }; diff --git a/docs/src/components/AlgoliaSearch.jsx b/docs/src/components/AlgoliaSearch.jsx index 4b9a4de..57fcddd 100644 --- a/docs/src/components/AlgoliaSearch.jsx +++ b/docs/src/components/AlgoliaSearch.jsx @@ -1,8 +1,9 @@ "use client"; -import { DocSearch } from "@docsearch/react"; import "./AlgoliaSearch.css"; +import { DocSearch } from "@docsearch/react"; + export default function AlgoliaSearch() { return (