Add playground-to-example sync infrastructure#468
Conversation
|
|
Important Review skippedBot user detected. To trigger a single review, invoke the You can disable this status message by setting the WalkthroughImplements a playground-to-examples synchronization system where playgrounds serve as the canonical source of truth. A new sync script automatically generates standalone examples from playgrounds by copying files, transforming dependencies from workspace references to published versions, and adjusting package.json configurations per target package manager. Changes
Sequence DiagramsequenceDiagram
participant CLI as CLI Entry
participant Script as sync-examples.js
participant Catalog as pnpm-workspace.yaml
participant Playgrounds as Playgrounds (arkenvExamples)
participant Transformer as Transform Logic
participant Examples as Examples Directory
CLI->>Script: npm run sync:examples [--check]
Script->>Catalog: Load catalog versions
Catalog-->>Script: Parsed version map
Script->>Playgrounds: Enumerate playgrounds with arkenvExamples
loop For each playground + example config
Playgrounds-->>Script: Playground files + metadata
alt Check Mode
Script->>Playgrounds: Read playground files
Script->>Examples: Compare with existing examples
Examples-->>Script: Current example files
Script->>Transformer: Transform playground package.json
Transformer-->>Script: Transformed for comparison
Script->>Script: Detect differences (Missing/Modified/Extra)
Script-->>Script: Accumulate changes
else Sync Mode
Script->>Transformer: Transform package.json<br/>(deps, workspace → published, packageManager)
Transformer-->>Script: Transformed package.json
Script->>Examples: Copy playground files recursively
Script->>Examples: Write transformed package.json
Examples-->>Script: Files written
Script->>Examples: Create/update .gitignore
end
end
alt Check Mode + Differences Detected
Script-->>CLI: Exit code 1 + Report changes
else Sync Mode
Script-->>CLI: Exit code 0 + Success
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Co-authored-by: yamcodes <2014360+yamcodes@users.noreply.github.com>
Co-authored-by: yamcodes <2014360+yamcodes@users.noreply.github.com>
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
examples/with-vite-react/package.json (1)
11-11: Addrimrafas a devDependency.The
cleanscript usesrimrafbut the package is not declared indevDependencies. This will cause the script to fail when executed.Apply this diff to add the missing dependency:
"devDependencies": { "@julr/vite-plugin-validate-env": "2.2.0", "@types/react": "^19.2.7", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^5.1.1", "globals": "^16.5.0", + "rimraf": "^6.0.1", "typescript": "^5.9.3", "vite": "npm:rolldown-vite@latest", "vite-tsconfig-paths": "^5.1.4" },
🧹 Nitpick comments (6)
examples/with-vite-react/.env.development (1)
1-4: Env keys look good; consider satisfying dotenv-linter hintsThe new variables and values align with typical Vite usage and the described Env schema. To avoid dotenv-linter noise (if you run it), you might:
- Alphabetize the
VITE_keys (e.g.,VITE_MY_BOOLEAN,VITE_MY_NUMBER,VITE_MY_VAR).- Add a trailing newline at the end of the file.
Both are purely stylistic and optional.
examples/with-vite-react/vite.config.ts (1)
22-22: Remove or conditionalize the debug console.log.The console.log statement will execute during every config load in both development and production builds. Consider removing it or making it conditional on development mode.
- console.log(`${env.VITE_MY_NUMBER} ${typeof env.VITE_MY_NUMBER}`); + if (mode === "development") { + console.log(`${env.VITE_MY_NUMBER} ${typeof env.VITE_MY_NUMBER}`); + }examples/with-vite-react/src/app.tsx (1)
12-17: Consider security implications ofrelattribute change.Changed from
noreferrertonoopener. Whilenoopenerpreventswindow.openeraccess, it allows the referrer header to be sent. For public documentation sites like vite.dev and react.dev, this is acceptable. However, be aware that the referrer header will now be included.bin/sync-examples.js (3)
52-83: Custom YAML parsing is fragile but acceptable for this use case.The line-by-line parsing works for pnpm's flat catalog structure, but it won't handle edge cases like multi-line values, comments on the same line as values, or nested structures. Consider using a YAML parser like
js-yamlif the catalog format becomes more complex in the future.
88-106: Hardcoded package mapping requires manual updates.When new workspace packages are added (e.g., a future
@arkenv/next-plugin), this mapping must be updated manually. Consider dynamically discovering packages from thepackages/directory for better maintainability.-function getWorkspacePackageVersion(packageName) { - // Map package names to their directories - const packageDirs = { - arkenv: join(ROOT_DIR, "packages", "arkenv"), - "@arkenv/vite-plugin": join(ROOT_DIR, "packages", "vite-plugin"), - "@arkenv/bun-plugin": join(ROOT_DIR, "packages", "bun-plugin"), - }; - - const packageDir = packageDirs[packageName]; +function getWorkspacePackageVersion(packageName) { + // Dynamically find package directory + const packagesDir = join(ROOT_DIR, "packages"); + const packageDirs = readdirSync(packagesDir, { withFileTypes: true }) + .filter((d) => d.isDirectory()) + .map((d) => join(packagesDir, d.name)); + + const packageDir = packageDirs.find((dir) => { + const pkgPath = join(dir, "package.json"); + if (!existsSync(pkgPath)) return false; + const pkg = JSON.parse(readFileSync(pkgPath, "utf-8")); + return pkg.name === packageName; + });
117-124: Consider warning when workspace dependency cannot be resolved.When
getWorkspacePackageVersionreturns null at line 118, the dependency is kept asworkspace:*which won't work in standalone examples. A warning here would help developers catch configuration issues.if (version === "workspace:*" || version.startsWith("workspace:")) { const publishedVersion = getWorkspacePackageVersion(name); if (publishedVersion) { transformed[name] = `^${publishedVersion}`; } else { + console.warn(`Warning: Could not resolve workspace dependency ${name}`); // Keep as-is if we can't find the version transformed[name] = version; }
|
@copilot all examples should be synced from the playgrounds. even the "basic" example, which should be synced through the "node playground", and the "basic-js" example, which we can sync via a new playground called "js-playground" which is like the node playground but in vanilla js (see basic-js example for setup) |
Co-authored-by: yamcodes <2014360+yamcodes@users.noreply.github.com>
…rs, package.json transformation, and workspace dependency resolution.
…logic in the sync script.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai do you approve? |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 1230 🏁 Script executed: Length of output: 3879 🏁 Script executed: Length of output: 887 @yamcodes, I've reviewed the PR implementation and verified that the sync infrastructure works correctly for the examples you mentioned. The However, I've identified an inconsistency that needs to be addressed before I can approve: Issue:
|
… example dependencies, and clean up its gitignore and example environment file.
|
@coderabbitai LGTY? |
🧩 Analysis chain🏁 Script executed: Length of output: 1556 @yamcodes Yes, LGTM! 🎉 All my previous concerns have been addressed: ✅ The sync infrastructure is working perfectly—all examples are now generated from playgrounds as intended. Great work consolidating the codebase! ✅ Actions performedComments resolved and changes approved. |
Playgrounds and examples were maintained separately, causing drift and duplication. This adds tooling to make playgrounds the source of truth and auto-generate examples from them.
New
bin/sync-examples.jsscriptarkenvExamplesmetadata from playgroundpackage.jsonworkspace:*→^<version>andcatalog:→^<version>--checkflag for CI verificationPlayground metadata
{ "arkenvExamples": [ { "name": "with-bun", "packageManager": "bun" } ] }Mappings
All examples are now synced from playgrounds:
nodebasicjsbasic-jsbunwith-bunbun-reactwith-bun-reactvitewith-vite-reactNew
jsplaygroundCreated a new
jsplayground for plain JavaScript examples, mirroring thenodeplayground but without TypeScript.CI workflow
New
.github/workflows/sync-examples.ymlverifies examples are in sync on PRs touching playgrounds or examples.Usage
Original prompt
This section details on the original issue you should resolve
<issue_title>Consolidate Playgrounds and Examples</issue_title>
<issue_description>It's too much trouble to maintain both the playgrounds and the examples. We need to consolidate them somehow.
The thing is, examples need to be isolated and standalone so they can be easily set up using
git cloneor a CLI tool. On the other hand, playgrounds need to use workspace packages so we can test new features in them before we publish our packages.More info
We maintain two sets of consumer apps in this repo:
Playgrounds (under apps/playgrounds/)
Used for local development and testing unpublished changes via workspace:*
Examples (under examples/)
Standalone templates intended for users to clone and run directly
To avoid duplication and drift, playgrounds are the source of truth and examples are automatically generated from them.
Goals
Update example apps automatically when playgrounds change
Allow some playgrounds to remain internal-only
Support multi-example generation from a single playground
Allow per-example configuration (package manager, name, etc.)
Keep README.md and code consistent between environments
Metadata in Playground
package.json
Playgrounds that should generate examples declare metadata in package.json:
Behavior:
If arkenvExamples is missing → no example is generated
Each object in the array → one generated example
Optional future metadata fields:
Sync Script
A script (e.g. bin/sync-examples.ts) will:
Iterate through playgrounds with arkenvExamples
Copy their content into examples/<name>
Modify package.json in the example:
Remove "private": true
Replace internal deps:
Adjust scripts if needed based on packageManager
Copy README.md from playground, unchanged (must work in both contexts)
Example folder structure after sync:
Continuous Integration
PR Validation (Required)
Run the sync ...
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.
Summary by CodeRabbit
Release Notes
New Features
Chores
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.