Skip to content

enhancement: set up monorepo build tooling and CI/CD pipeline - #14

Merged
ViewFromTheBox merged 2 commits into
feature/react-packagefrom
enhancement/1-monorepo-build-tooling-ci-cd
Mar 28, 2026
Merged

ViewFromTheBox merged 2 commits into
feature/react-packagefrom
enhancement/1-monorepo-build-tooling-ci-cd

Conversation

@ViewFromTheBox

@ViewFromTheBox ViewFromTheBox commented Mar 27, 2026 •

Copy link
Copy Markdown
Member

Description

Set up the complete monorepo development infrastructure including ESLint, Prettier, Changesets, and a fully rewritten CI/CD pipeline for Node.js.

Closes: #1

Type of Change

  • Bug fix (fixes an issue)
  • New feature (adds new functionality)
  • Enhancement (improves existing functionality)
  • Refactoring (code improvement, no behavior change)
  • Documentation update
  • Performance improvement
  • Security fix
  • Breaking change (breaks backward compatibility)

Related Issue

Issue: #1

Motivation and Context

The React monorepo had no linting, formatting, or CI/CD configuration. The existing CI workflow was a copy-pasted PHP/Pest pipeline from another package. All other component work is blocked until this tooling foundation is in place.

Changes Made

  • Created eslint.config.js with ESLint 9 flat config, TypeScript, React, and React Hooks support
  • Created .prettierrc and .prettierignore for consistent code formatting
  • Initialized Changesets (.changeset/config.json) with public access and linked versioning across all three packages
  • Completely rewrote .github/workflows/ci.yml from PHP/Pest to Node.js with lint, type-check, test, build, and Changesets release jobs
  • Added "type": "module" to root package.json
  • Fixed lint script for ESLint 9 (removed deprecated --ext flag)
  • Added type-check and format:check scripts to root package.json
  • Added --if-present flag to workspace test script
  • Added explicit include patterns to root tsconfig.json
  • Added passWithNoTests: true to vitest configs for tokens and react packages
  • Installed missing jsdom dev dependency for react package tests
  • Added export {} to empty component index files to make them valid TypeScript modules
  • Removed non-functional test scripts from react-laravel package (no test files exist)
  • Installed ESLint plugins: @eslint/js, typescript-eslint, eslint-plugin-react, eslint-plugin-react-hooks

How Has This Been Tested?

Testing Environment:

  • Operating System: macOS Darwin 25.3.0
  • Node.js: v23.7.0
  • npm: 11.6.2

Tests Performed:

  1. npm run lint — ESLint passes with no errors
  2. npm run type-check — TypeScript type checking passes
  3. npm test — Vitest runs across workspaces (passes with no test files)
  4. npm run build — All three packages build successfully via tsup
  5. npm run format:check — Prettier formatting check passes

Accessibility Tests Run

  • N/A — tooling/config changes only, no UI

Tests Added

  • Unit tests added/updated
  • Integration tests added/updated
  • All tests passing

Test details: No new test files — this PR sets up the infrastructure for testing. Existing vitest configs now handle the "no test files" case gracefully.

Documentation

  • Inline code documentation added
  • README updated
  • Wiki updated
  • API documentation updated

Documentation details: N/A — tooling configuration, self-documenting via config files.

Pre-Submission Checklist

  • Followed contributing guidelines
  • Checked for other open PRs for same update
  • Code passes all tests
  • Code has been linted
  • Accessibility tests completed
  • Code follows project style guide
  • Self-review completed
  • Comments added for complex code
  • No new warnings generated

Summary by CodeRabbit

  • New Features

    • Added project-wide formatting and linting defaults and new quality-check commands (format check, type check).
  • Chores

    • Migrated CI to a Node/npm-based pipeline with automated linting, type checking, testing, and build gating.
    • Integrated Changesets for versioning and publishing from main.
    • Adjusted test configs to pass when no tests are present.

Configure ESLint 9 flat config with TypeScript and React support, Prettier
for consistent formatting, Changesets for version management, and rewrite
the CI/CD workflow from PHP/Pest to Node.js with lint, type-check, test,
build, and automated npm publishing via Changesets.

Closes #1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 27, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds project-wide developer tooling and CI/CD: Prettier, ESLint, TypeScript config, Vitest adjustments, Changesets for releases, repo package.json script updates, module boundary markers, and a revamped GitHub Actions workflow that uses Node/npm and Changesets to publish from main.

Changes

Cohort / File(s) Summary
Changesets
​.changeset/README.md, ​.changeset/config.json
Add Changesets README and config.json (changelog provider, commit:false, updateInternalDependencies:"patch", base:"main", access:"public", package linking rules).
CI/CD workflow
.github/workflows/ci.yml
Replace PHP/Composer pipeline with Node/npm jobs; add concurrency; split lint/type-check/test; run build after checks; change release trigger to main and publish via changesets/action with NODE_AUTH_TOKEN.
Formatting & Linting
.prettierignore, .prettierrc, eslint.config.js
Add Prettier config and ignore patterns; add ESLint flat config with TypeScript + React plugins and recommended rules; global ignore patterns set.
Root package & scripts
package.json
Set "type": "module"; adjust test and lint scripts; add format:check and type-check; update devDependencies for ESLint/TS tooling.
Per-package package.json edits
packages/react/package.json, packages/react-laravel/package.json
react: add @vitejs/plugin-react and jsdom devDeps; react-laravel: remove vitest and test scripts.
Vitest config changes
packages/react/vitest.config.ts, packages/tokens/vitest.config.ts
Set test.passWithNoTests: true to allow success when no tests exist.
Module boundary markers
packages/react-laravel/src/index.ts, packages/react/src/components/.../index.ts
Add export {}; to several package index files to enforce ES module boundaries.
TypeScript config
tsconfig.json
Add explicit include for packages/*/src/** and keep exclude for node_modules and dist.
Formatting ignore
.prettierignore
Exclude dist/, node_modules/, coverage/, storybook-static/, *.config.js, *.config.ts, package-lock.json.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant GitHub as "GitHub Actions"
participant Repo as "Repository"
participant Changesets as "changesets/action"
participant NPM as "npm Registry"
Note over GitHub,Repo: PRs trigger lint/type-check/test jobs
GitHub->>Repo: checkout
GitHub->>GitHub: run lint / type-check / tests
alt All checks pass on main
GitHub->>Changesets: run npx changeset publish
Changesets->>NPM: publish packages (uses NODE_AUTH_TOKEN)
Changesets-->>GitHub: create changelog / tags
end

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰
Hop, I stitched the configs bright,
Linters, builds, and tests take flight,
Changesets stack the carrots high,
CI hums beneath the sky,
I nibble badges — publish tonight! 🥕✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately and specifically describes the main changes: setting up monorepo build tooling and CI/CD pipeline, which aligns with the primary focus of the changeset.
Linked Issues check ✅ Passed The PR successfully implements all core requirements from issue #1: TypeScript config with tsconfig.json, build system setup (via ESLint/Prettier/Vitest configs), ESLint and Prettier configuration, Vitest with passWithNoTests config, Changesets setup with .changeset/config.json, and GitHub Actions CI/CD pipeline with lint, type-check, test, build, and automated release workflows.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #1 objectives: tooling setup (ESLint, Prettier, Vitest, Changesets), CI/CD pipeline updates, TypeScript configuration, and necessary workspace package adjustments. No unrelated or extraneous changes were introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch enhancement/1-monorepo-build-tooling-ci-cd

Comment @coderabbitai help to get the list of available commands and usage tips.

@ViewFromTheBox
ViewFromTheBox marked this pull request as ready for review March 27, 2026 22:54
@ViewFromTheBox

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 27, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (4)
packages/tokens/vitest.config.ts (1)

6-6: Consider adding a test coverage gate in CI as packages mature beyond bootstrap.

passWithNoTests: true is appropriate during initial setup, but it can hide accidental test deletion over time. As packages/tokens develops, add a CI check that fails the build if the package still has zero test files after the bootstrap phase (e.g., on releases or after a certain date). This ensures tests become a required part of the package lifecycle.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/tokens/vitest.config.ts` at line 6, The vitest config currently sets
passWithNoTests: true which hides missing tests; update CI to enforce a test
presence/coverage gate for packages/tokens by (1) adding a workflow step that
checks for the existence of test files (e.g., glob like
**/packages/tokens/**/__tests__/**/* or **/*.test.{ts,tsx,js,jsx}) and fails if
none are found, or (2) run Vitest in CI with passWithNoTests disabled for
packages/tokens (set passWithNoTests to false in the CI run) and/or enforce a
minimum coverage threshold so the build fails when coverage is zero; locate the
setting named passWithNoTests in vitest.config.ts and adjust the CI workflow or
job to run the stricter check only after bootstrap/maturation (e.g., gated by
branch, tag, or date).
packages/react-laravel/package.json (1)

18-18: Consider removing unused vitest devDependency.

The test scripts were removed, but vitest remains in devDependencies (line 29). If this package has no tests and won't have tests in the near term, consider removing the vitest devDependency to keep the dependency tree clean.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react-laravel/package.json` at line 18, The devDependency "vitest"
is unused after removing test scripts; remove the "vitest" entry from
package.json's devDependencies and any related configuration (e.g., vitest
config or scripts referencing vitest) to keep the dependency tree clean—locate
the "vitest" string in package.json and delete that entry, then run
npm/yarn/pnpm install to update lockfile and ensure no build scripts (e.g.,
"build": "tsup") or CI steps reference vitest.
.github/workflows/ci.yml (1)

33-34: Use the defined npm script for consistency.

Line 34 runs Prettier directly via npx, but package.json already defines a format:check script. Using the script ensures the CI and local development stay in sync.

♻️ Proposed fix
       - name: Check formatting
-        run: npx prettier --check "packages/*/src/**/*.{ts,tsx}"
+        run: npm run format:check
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/ci.yml around lines 33 - 34, The CI step named "Check
formatting" currently invokes Prettier directly; replace that run command to use
the project's npm script (format:check) instead so CI uses the same entrypoint
as local dev. Locate the "Check formatting" job/step and change its run
invocation from the direct npx call to running the npm script (e.g., npm run
format:check) so formatting checks remain consistent.
package.json (1)

22-30: Consider removing redundant @typescript-eslint/* packages.

Lines 23-24 declare @typescript-eslint/eslint-plugin and @typescript-eslint/parser as separate dependencies, but typescript-eslint (line 30) re-exports both. Since eslint.config.js only imports from typescript-eslint, the separate packages appear unused.

♻️ Proposed cleanup
   "devDependencies": {
     "@changesets/cli": "^2.27.0",
     "@eslint/js": "^9.39.4",
-    "@typescript-eslint/eslint-plugin": "^8.0.0",
-    "@typescript-eslint/parser": "^8.0.0",
     "eslint": "^9.0.0",
     "eslint-plugin-react": "^7.37.5",
     "eslint-plugin-react-hooks": "^7.0.1",
     "prettier": "^3.4.0",
     "typescript": "^5.7.0",
     "typescript-eslint": "^8.57.2"
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@package.json` around lines 22 - 30, package.json declares
"@typescript-eslint/eslint-plugin" and "@typescript-eslint/parser" separately
but you already depend on "typescript-eslint" which re-exports them and
eslint.config.js imports only from "typescript-eslint"; remove the two redundant
packages ("@typescript-eslint/eslint-plugin" and "@typescript-eslint/parser")
from package.json, run your package manager to update lockfile, and scan for any
direct imports/usages of those two package names (e.g., in eslint configs or
scripts) to replace with imports from "typescript-eslint" if found before
committing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/react/package.json`:
- Around line 52-53: The package.json currently uses "@vitejs/plugin-react":
"^4.3.0" which requires Vite 6+ and conflicts with Vitest 2.1's Vite ^5.x; fix
by either downgrading "@vitejs/plugin-react" to a Vite-5-compatible release (pin
"@vitejs/plugin-react" to a 4.x range known to support Vite 5) or upgrading
"vitest" to a 3.x release that supports Vite 6+, and also bump "jsdom" to
"^29.0.1"; update the dependencies entries for "@vitejs/plugin-react", "vitest",
and "jsdom" in package.json accordingly and run a reinstall and type-check to
verify the conflict is resolved.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 33-34: The CI step named "Check formatting" currently invokes
Prettier directly; replace that run command to use the project's npm script
(format:check) instead so CI uses the same entrypoint as local dev. Locate the
"Check formatting" job/step and change its run invocation from the direct npx
call to running the npm script (e.g., npm run format:check) so formatting checks
remain consistent.

In `@package.json`:
- Around line 22-30: package.json declares "@typescript-eslint/eslint-plugin"
and "@typescript-eslint/parser" separately but you already depend on
"typescript-eslint" which re-exports them and eslint.config.js imports only from
"typescript-eslint"; remove the two redundant packages
("@typescript-eslint/eslint-plugin" and "@typescript-eslint/parser") from
package.json, run your package manager to update lockfile, and scan for any
direct imports/usages of those two package names (e.g., in eslint configs or
scripts) to replace with imports from "typescript-eslint" if found before
committing.

In `@packages/react-laravel/package.json`:
- Line 18: The devDependency "vitest" is unused after removing test scripts;
remove the "vitest" entry from package.json's devDependencies and any related
configuration (e.g., vitest config or scripts referencing vitest) to keep the
dependency tree clean—locate the "vitest" string in package.json and delete that
entry, then run npm/yarn/pnpm install to update lockfile and ensure no build
scripts (e.g., "build": "tsup") or CI steps reference vitest.

In `@packages/tokens/vitest.config.ts`:
- Line 6: The vitest config currently sets passWithNoTests: true which hides
missing tests; update CI to enforce a test presence/coverage gate for
packages/tokens by (1) adding a workflow step that checks for the existence of
test files (e.g., glob like **/packages/tokens/**/__tests__/**/* or
**/*.test.{ts,tsx,js,jsx}) and fails if none are found, or (2) run Vitest in CI
with passWithNoTests disabled for packages/tokens (set passWithNoTests to false
in the CI run) and/or enforce a minimum coverage threshold so the build fails
when coverage is zero; locate the setting named passWithNoTests in
vitest.config.ts and adjust the CI workflow or job to run the stricter check
only after bootstrap/maturation (e.g., gated by branch, tag, or date).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97db07fe-0ac8-40fa-8d5c-67b0b24feb69

📥 Commits

Reviewing files that changed from the base of the PR and between db68265 and 15b6c25.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (19)
  • .changeset/README.md
  • .changeset/config.json
  • .github/workflows/ci.yml
  • .prettierignore
  • .prettierrc
  • eslint.config.js
  • package.json
  • packages/react-laravel/package.json
  • packages/react-laravel/src/index.ts
  • packages/react/package.json
  • packages/react/src/components/data/index.ts
  • packages/react/src/components/display/index.ts
  • packages/react/src/components/form/index.ts
  • packages/react/src/components/layout/index.ts
  • packages/react/src/components/navigation/index.ts
  • packages/react/src/components/utility/index.ts
  • packages/react/vitest.config.ts
  • packages/tokens/vitest.config.ts
  • tsconfig.json

Comment on lines +52 to +53
"@vitejs/plugin-react": "^4.3.0",
"jsdom": "^27.0.1",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Is @vitejs/plugin-react version 4.3.0 compatible with React 19 and Vitest 2.1?

💡 Result:

No, @vitejs/plugin-react version 4.3.0 is not fully compatible with both React 19 and Vitest 2.1. It is compatible with React 19: The plugin's changelog and development dependencies explicitly support React Compiler for React 19 (target: '19'), with fixes in 4.3.0 and later for React compiler support. PRs update @types/react and react to ^19.x versions. However, it has compatibility issues with Vitest 2.1: Vitest 2.1 does not fully support Vite 6, which is added to the plugin's peerDependencies in 4.3.4. Users report TypeScript errors like "Type 'PluginOption[]' is not assignable to type 'PluginOption'" when using the React plugin in Vitest config, due to Vite version mismatches. Vitest 2.x requires Vite ^5.x, while plugin 4.3.0 targets Vite 6+.

Citations:


🌐 Web query:

What is the latest stable version of jsdom and is version 27.0.1 appropriate for testing with React 19?

💡 Result:

The latest stable version of jsdom is 29.0.1. Version 27.0.1 is a stable release from October 2025 but is outdated compared to the current latest. It can be used for testing with React 19, as React 19 works with jsdom versions supported by Jest (which added v27 support), and no specific incompatibilities are noted for v27.0.1 with React 19; issues in testing environments are typically resolved via dependency overrides like for pretty-format/react-is.

Citations:


Resolve Vite version conflict between @vitejs/plugin-react and Vitest 2.1.

@vitejs/plugin-react@^4.3.0 is compatible with React 19, but it targets Vite 6+, which conflicts with Vitest 2.1's requirement for Vite ^5.x. This causes TypeScript errors when using the React plugin in Vitest configuration. Either downgrade the React plugin to a version compatible with Vite 5, or upgrade Vitest to 3.x which supports Vite 6.

Additionally, upgrade jsdom to ^29.0.1 (latest stable), as version 27.0.1 is outdated though still functional with React 19.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/react/package.json` around lines 52 - 53, The package.json currently
uses "@vitejs/plugin-react": "^4.3.0" which requires Vite 6+ and conflicts with
Vitest 2.1's Vite ^5.x; fix by either downgrading "@vitejs/plugin-react" to a
Vite-5-compatible release (pin "@vitejs/plugin-react" to a 4.x range known to
support Vite 5) or upgrading "vitest" to a 3.x release that supports Vite 6+,
and also bump "jsdom" to "^29.0.1"; update the dependencies entries for
"@vitejs/plugin-react", "vitest", and "jsdom" in package.json accordingly and
run a reinstall and type-check to verify the conflict is resolved.

- Use npm run format:check in CI instead of direct npx prettier call
- Remove redundant @typescript-eslint/eslint-plugin and @typescript-eslint/parser
  (already provided by typescript-eslint)
- Remove unused vitest from react-laravel devDependencies

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ViewFromTheBox

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 28, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)

94-128: Ensure NPM_TOKEN secret is configured; consider build artifact optimization.

Two observations:

  1. Required secret: The NPM_TOKEN secret must be configured in repository settings (Settings → Secrets and variables → Actions) for npm publishing to work. Verify this is set up.

  2. Optional optimization: The build step (lines 117-118) duplicates work already done in the build job. You could upload the dist artifacts from the build job and download them here to save ~1-2 minutes of CI time. This is optional since the current approach is correct and simpler.

♻️ Optional: Share build artifacts between jobs

In the build job, add after the build step:

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dist
          path: packages/*/dist

In the release job, replace the build step with:

      - name: Download build artifacts
        uses: actions/download-artifact@v4
        with:
          name: dist
          path: packages
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/ci.yml around lines 94 - 128, The release job currently
requires the NPM_TOKEN secret and rebuilds artifacts; ensure the NPM_TOKEN
repository secret is configured (Settings → Secrets and variables → Actions) so
the changesets/action publish step can authenticate, and optionally optimize CI
by uploading the build artifacts from the build job and downloading them in the
release job: in the build job add an "Upload build artifacts" step that uploads
packages/*/dist (used by the Build all packages step), and in the release job
replace the "Build all packages" step with a "Download build artifacts" step to
restore the dist artifacts before running changesets/action (refer to the
release job name "release", the "Build all packages" step, and the
changesets/action step).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 94-128: The release job currently requires the NPM_TOKEN secret
and rebuilds artifacts; ensure the NPM_TOKEN repository secret is configured
(Settings → Secrets and variables → Actions) so the changesets/action publish
step can authenticate, and optionally optimize CI by uploading the build
artifacts from the build job and downloading them in the release job: in the
build job add an "Upload build artifacts" step that uploads packages/*/dist
(used by the Build all packages step), and in the release job replace the "Build
all packages" step with a "Download build artifacts" step to restore the dist
artifacts before running changesets/action (refer to the release job name
"release", the "Build all packages" step, and the changesets/action step).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 747c053b-4a03-41a5-b39f-6ce14267afef

📥 Commits

Reviewing files that changed from the base of the PR and between 15b6c25 and 1a236c7.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • package.json
  • packages/react-laravel/package.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/react-laravel/package.json
  • package.json

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant