Skip to content

Conversation

@PupilTong
Copy link
Collaborator

@PupilTong PupilTong commented Sep 23, 2025

#1806

Summary by CodeRabbit

  • New Features

    • Web platform preview added alongside Lynx; QR display and console shortcuts now support both Lynx and Web URLs. Dev URL generation improved to compute web base URLs automatically.
  • Documentation

    • Added guidance and example config for enabling Web preview (environments.web / environments.lynx).
  • Tests

    • Updated tests to cover multi-platform previews, entry/env permutations, and dual-URL onPrint behavior.
  • Chores

    • Added middleware dependency, TypeScript project references, and a changeset entry.

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).
  • Changeset added, and when a BREAKING CHANGE occurs, it needs to be clearly marked (or not required).

@changeset-bot
Copy link

changeset-bot bot commented Sep 23, 2025

🦋 Changeset detected

Latest commit: 4ed1eae

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@lynx-js/qrcode-rsbuild-plugin Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@PupilTong PupilTong changed the title P/hw/web qrcode url feat: enhance QR code plugin with web environment support and middleware integration Sep 23, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 23, 2025

📝 Walkthrough

Walkthrough

Adds web-platform preview support to the rspeedy QRCode plugin: generates separate Lynx and Web dev URLs, integrates web virtual-files middleware, updates shortcuts and QR rendering to handle dual URLs, updates tests, example config, package deps, and TypeScript project references.

Changes

Cohort / File(s) Summary
Changeset
.changeset/tricky-lamps-battle.md
New changeset entry for @lynx-js/qrcode-rsbuild-plugin documenting web platform preview support and example rspeedy settings.
Example config
examples/react/lynx.config.js
Adds environments object with web and lynx entries to example config.
Package & TS refs
packages/rspeedy/plugin-qrcode/package.json, packages/rspeedy/plugin-qrcode/tsconfig.json, packages/rspeedy/plugin-qrcode/tsconfig.build.json
Adds runtime dependency @lynx-js/web-rsbuild-server-middleware and adds project references to the web middleware TS project.
Dev URL generation
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts
Replaces default export with helpers: generateFileNameBase, generateExplorerDevUrls, generateWebDevUrls; moves assetPublicPath/port handling into base helper and emits separate explorer and web URL maps.
Plugin integration
packages/rspeedy/plugin-qrcode/src/index.ts
Main now accepts full environments map, computes per-environment entries, wires web virtual-files middleware when web exists, and adapts QR printing/shortcuts to both platforms.
Shortcuts & QR rendering
packages/rspeedy/plugin-qrcode/src/shortcuts.ts, packages/rspeedy/plugin-qrcode/src/showQRCode.ts
Options now accepts webEntries; onPrint widened to (lynx?: string, web?: Record<string,string>); QR display updated to conditionally render Lynx and multiple Web previews.
Tests
packages/rspeedy/plugin-qrcode/test/preview.test.ts, packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts
Adjusts tests for environment/entry presence, port-range changes, and verifies onPrint receives lynx URL and an (possibly empty) web map.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • colinaaa
  • Sherry-hue
  • upupming

Poem

I twitch my whiskers, two routes to share,
One Lynx-bound, one floating in web air.
QR squares hop from paw to screen,
Two previews gleam in a dev-time dream.
I munch a carrot — preview ready! 🥕🐇

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.09% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title accurately describes that the change is a feature addition enhancing the QR code plugin with web environment support and middleware integration, matching the main modifications in the changeset.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 81dcb1e and 4ed1eae.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • .changeset/tricky-lamps-battle.md (1 hunks)
  • examples/react/lynx.config.js (1 hunks)
  • packages/rspeedy/plugin-qrcode/package.json (1 hunks)
  • packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2 hunks)
  • packages/rspeedy/plugin-qrcode/src/index.ts (4 hunks)
  • packages/rspeedy/plugin-qrcode/src/shortcuts.ts (9 hunks)
  • packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1 hunks)
  • packages/rspeedy/plugin-qrcode/test/preview.test.ts (5 hunks)
  • packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts (2 hunks)
  • packages/rspeedy/plugin-qrcode/tsconfig.build.json (1 hunks)
  • packages/rspeedy/plugin-qrcode/tsconfig.json (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .changeset/tricky-lamps-battle.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • examples/react/lynx.config.js
  • packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts
  • packages/rspeedy/plugin-qrcode/test/preview.test.ts
  • packages/rspeedy/plugin-qrcode/src/showQRCode.ts
  • packages/rspeedy/plugin-qrcode/tsconfig.build.json
  • packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts
  • packages/rspeedy/plugin-qrcode/package.json
🧰 Additional context used
🧬 Code graph analysis (2)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (3)
packages/rspeedy/plugin-qrcode/src/index.ts (1)
  • CustomizedSchemaFn (22-24)
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2)
  • generateExplorerDevUrls (40-58)
  • generateWebDevUrls (60-82)
packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1)
  • showQRCode (8-22)
packages/rspeedy/plugin-qrcode/src/index.ts (2)
packages/web-platform/web-rsbuild-server-middleware/src/node/index.ts (1)
  • createWebVirtualFilesMiddleware (22-89)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (1)
  • registerConsoleShortcuts (32-75)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: test-rust / Test (Ubuntu)
🔇 Additional comments (7)
packages/rspeedy/plugin-qrcode/src/index.ts (2)

106-110: LGTM!

The web middleware integration is correctly gated on the presence of the web environment.


158-166: LGTM!

The changes correctly pass separate lynxEntries and webEntries to registerConsoleShortcuts, aligning with the dual-environment support.

packages/rspeedy/plugin-qrcode/src/shortcuts.ts (5)

8-11: LGTM!

The imports correctly align with the refactored generateDevUrls.ts helpers.


17-30: LGTM!

The Options interface correctly extends with webEntries and updates the onPrint signature to handle both Lynx and web URLs.


41-64: LGTM!

The initialization correctly handles optional Lynx entries and unconditionally generates web URLs, then passes both to the print functions.


117-157: LGTM!

The guards on lines 117 and 137 correctly ensure currentSchema and currentEntry exist before switching, making the subsequent non-null assertions safe.


174-183: LGTM!

The getCurrentUrl function safely handles missing currentEntry or currentSchema by returning an empty string, making the non-null assertion on line 181 valid.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@PupilTong PupilTong moved this to In Progress in Lynx for Web Sep 23, 2025
@codecov
Copy link

codecov bot commented Sep 23, 2025

Codecov Report

❌ Patch coverage is 96.03960% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/rspeedy/plugin-qrcode/src/index.ts 84.61% 2 Missing ⚠️
...kages/rspeedy/plugin-qrcode/src/generateDevUrls.ts 97.05% 1 Missing ⚠️
packages/rspeedy/plugin-qrcode/src/shortcuts.ts 97.50% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (16)
packages/web-platform/web-rsbuild-server-middleware/turbo.json (1)

1-16: Broaden inputs to rebuild on config changes.

Include common config files so build re-runs when they change.

Apply:

-      "inputs": [
-        "src/**"
-      ],
+      "inputs": [
+        "src/**",
+        "package.json",
+        "rslib.config.ts",
+        "rsbuild.config.ts",
+        "tsconfig.json",
+        "vitest.config.ts"
+      ],
packages/rspeedy/core/test/plugins/dev.plugin.test.ts (1)

102-121: Tighten assertions to ensure alias is absent.

.not.toHaveProperty with an expected value can pass even if the property exists with a different value. Check absence explicitly.

Apply:

-    expect(config.resolve?.alias).not.toHaveProperty(
-      '@rspack/core/hot/dev-server',
-      expect.stringContaining('hot/dev-server.js'.replaceAll('/', path.sep)),
-    )
-    expect(config.resolve?.alias).not.toHaveProperty(
-      '@lynx-js/webpack-dev-transport/client',
-      expect.stringContaining(
-        'packages/webpack/webpack-dev-transport'.replaceAll('/', path.sep),
-      ),
-    )
+    expect(config.resolve?.alias?.['@rspack/core/hot/dev-server']).toBeUndefined()
+    expect(config.resolve?.alias?.['@lynx-js/webpack-dev-transport/client']).toBeUndefined()
packages/web-platform/web-rsbuild-server-middleware/README.md (1)

3-3: Fix grammar and article

Use “An Rsbuild … that provides a … on the dev server.” for clarity.

Apply:

-A rsbuild dev server middleware for providing mocked Lynx Web Platform installation on dev server.
+An Rsbuild dev server middleware that provides a mocked Lynx Web Platform installation on the dev server.
packages/web-platform/web-rsbuild-server-middleware/src/web/index.css (1)

5-8: Ensure custom element fills viewport

Custom elements are inline by default; width/height won’t apply reliably. Make it block-level.

Apply:

 lynx-view {
+  display: block;
   width: 100vw;
   height: 100vh;
 }
packages/web-platform/web-tests/rspack.config.js (1)

20-21: Avoid ambiguous “main” naming; use descriptive middleware identifier

Rename to prevent confusion with the “main” entry chunk and improve readability.

Apply:

-const main = createWebVirtualFilesMiddleware('/middleware');
+const webMiddleware = createWebVirtualFilesMiddleware('/middleware');
...
-      middlewares.push(main);
+      middlewares.push(webMiddleware);

Optional: mount with explicit devServer metadata for clarity:

middlewares.push({
  name: 'web-virtual-files',
  path: '/middleware',
  middleware: webMiddleware,
});

Also applies to: 208-209

packages/web-platform/web-rsbuild-server-middleware/Notice.txt (1)

1-1: Standardize NOTICE filename across repo

Repo contains a top-level NOTICE and many package Notice.txt files (including packages/web-platform/web-rsbuild-server-middleware/Notice.txt). Choose one convention (prefer uppercase NOTICE for Apache attribution), rename files and update any references.

packages/web-platform/web-tests/tests/middleware.spec.ts (2)

38-47: Use an absolute path for stability in goto.

Prefix the path with / to avoid baseURL/path merging issues in different runners.

-  let url = `middleware?casename=/dist/${testname}/index.web.json`;
+  let url = `/middleware?casename=/dist/${testname}/index.web.json`;

55-64: Prefer auto‑waiting assertions over fixed sleeps.

Replace manual wait(100) with Playwright’s auto-waiting assertions to reduce flakiness.

-    await wait(100);
-    const target = page.locator('#target');
-    await target.click();
-    await wait(100);
-    await expect(await target.getAttribute('style')).toContain('green');
-    await target.click();
-    await wait(100);
-    await expect(await target.getAttribute('style')).toContain('pink');
+    const target = page.locator('#target');
+    await target.click();
+    await expect(target).toHaveAttribute('style', /green/);
+    await target.click();
+    await expect(target).toHaveAttribute('style', /pink/);
packages/web-platform/web-rsbuild-server-middleware/vitest.config.ts (1)

5-7: Capture nested tests too.

Broaden the include pattern to match nested spec files under test/.

-    include: ['**/test/*.spec.ts'],
+    include: ['**/test/**/*.spec.ts'],
packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1)

8-16: Consider rendering a QR for the web URL as well (consistency).

Currently only the Lynx URL gets a QR. Printing a QR for web can help mobile-to-desktop handoff and keeps output consistent.

 export default function showQRCode(lynxUrl?: string, webUrl?: string): void {
   if (lynxUrl) {
     log.info(color.green('Scan with Lynx'))
     log.success(renderUnicodeCompact(lynxUrl))
     log.success('Lynx Explorer: ' + lynxUrl)
   }
   if (webUrl) {
-    log.success('Lynx Web Platform: ' + webUrl)
+    log.info(color.green('Open in Browser'))
+    log.success(renderUnicodeCompact(webUrl))
+    log.success('Lynx Web Platform: ' + webUrl)
   }
 }
packages/web-platform/web-rsbuild-server-middleware/test/basic.spec.ts (1)

19-26: Avoid double slashes in request URLs.

Sanitize the path or let the helper handle leading slashes uniformly.

-const GET = async (path: string) => {
+const GET = async (path: string) => {
+  path = path.startsWith('/') ? path.slice(1) : path;
   // Make an HTTP request over the IPC socket
   const result = await fetch(`http://localhost:${port}/${path}`);
   if (result.status !== 200) {
     throw new Error(`Request failed with status ${result.status}`);
   }
   return result;
};
packages/web-platform/web-rsbuild-server-middleware/package.json (1)

14-16: Prefer types over typings and consider exports map.

For consistency with the repo and TypeScript conventions, use types. Optionally add an exports map to control entry points.

-  "main": "dist/index.js",
-  "typings": "dist/node/index.d.ts",
+  "main": "dist/index.js",
+  "types": "dist/node/index.d.ts",

Optionally:

{
  "exports": {
    ".": {
      "types": "./dist/node/index.d.ts",
      "default": "./dist/index.js"
    }
  }
}
packages/web-platform/web-rsbuild-server-middleware/src/node/index.ts (1)

63-76: Correct Content-Length calculation and disable caching in dev

For Buffers, use .length; also set no-store to avoid stale assets during dev.

Apply this diff:

-          res.setHeader('Content-Length', Buffer.byteLength(fileContent));
+          const len = typeof fileContent === 'string'
+            ? Buffer.byteLength(fileContent)
+            : fileContent.length;
+          res.setHeader('Content-Length', len);
           res.setHeader('Content-Type', contextType);
+          res.setHeader('Cache-Control', 'no-store');
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (3)

71-74: Simplify types for value/devUrls

value.lynx is never a cancel token; it’s set to URLs only. Remove symbol from types to avoid unnecessary casts and confusion.

Apply this diff:

-  value: { lynx: string | symbol | undefined, web: string | undefined },
-  devUrls: { lynx: Record<string, string | symbol>, web: string },
+  value: { lynx: string | undefined, web: string | undefined },
+  devUrls: { lynx: Record<string, string>, web: string },

85-89: Fix loop condition; current use of isCancel on URLs is a no-op

isCancel(value.lynx/web) always returns false for strings. Use an unconditional loop with internal breaks.

Apply this diff:

-  while (
-    !(value.lynx && isCancel(value.lynx) || value.web && isCancel(value.web))
-  ) {
+  while (true) {

The existing breaks on isCancel(name)/'q'/restart already control loop exit.


157-159: Drop unnecessary casts after type simplification

Once value types are simplified to strings, these casts are not needed.

-    await options.onPrint?.(value.lynx as string | undefined, value.web)
-    showQRCode(value.lynx as string, value.web)
+    await options.onPrint?.(value.lynx, value.web)
+    showQRCode(value.lynx, value.web)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69e0dc4 and a4d4f03.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (31)
  • .changeset/config.json (1 hunks)
  • .changeset/crazy-jeans-hunt.md (1 hunks)
  • .changeset/slow-radios-rescue.md (1 hunks)
  • .changeset/tricky-lamps-battle.md (1 hunks)
  • examples/react/lynx.config.js (2 hunks)
  • packages/rspeedy/core/src/plugins/dev.plugin.ts (2 hunks)
  • packages/rspeedy/core/test/plugins/dev.plugin.test.ts (1 hunks)
  • packages/rspeedy/plugin-qrcode/package.json (1 hunks)
  • packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2 hunks)
  • packages/rspeedy/plugin-qrcode/src/index.ts (4 hunks)
  • packages/rspeedy/plugin-qrcode/src/shortcuts.ts (8 hunks)
  • packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1 hunks)
  • packages/rspeedy/plugin-qrcode/test/preview.test.ts (5 hunks)
  • packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts (2 hunks)
  • packages/web-platform/tsconfig.json (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/LICENSE.txt (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/Notice.txt (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/README.md (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/package.json (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/rsbuild.config.ts (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/rslib.config.ts (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/src/node/index.ts (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/src/web/index.css (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/src/web/index.ts (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/test/basic.spec.ts (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/tsconfig.json (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/turbo.json (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/vitest.config.ts (1 hunks)
  • packages/web-platform/web-tests/package.json (1 hunks)
  • packages/web-platform/web-tests/rspack.config.js (2 hunks)
  • packages/web-platform/web-tests/tests/middleware.spec.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

For contributions, always generate a changeset and commit the resulting markdown file(s)

Files:

  • .changeset/tricky-lamps-battle.md
  • .changeset/crazy-jeans-hunt.md
  • .changeset/slow-radios-rescue.md
packages/web-platform/web-tests/**

📄 CodeRabbit inference engine (AGENTS.md)

Place Playwright E2E tests in the web platform’s web-tests suite

Files:

  • packages/web-platform/web-tests/rspack.config.js
  • packages/web-platform/web-tests/tests/middleware.spec.ts
  • packages/web-platform/web-tests/package.json
🧠 Learnings (14)
📚 Learning: 2025-09-22T11:07:32.317Z
Learnt from: PupilTong
PR: lynx-family/lynx-stack#1807
File: packages/web-platform/web-rsbuild-server-middleware/src/node/index.ts:44-47
Timestamp: 2025-09-22T11:07:32.317Z
Learning: Development server middleware packages (like rsbuild dev server middleware) can appropriately use permissive CORS settings like "Access-Control-Allow-Origin: *" since they are intended for local development and testing, not production use.

Applied to files:

  • packages/web-platform/web-rsbuild-server-middleware/README.md
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • packages/web-platform/web-rsbuild-server-middleware/README.md
  • packages/rspeedy/core/src/plugins/dev.plugin.ts
  • .changeset/crazy-jeans-hunt.md
  • packages/web-platform/web-rsbuild-server-middleware/package.json
  • packages/rspeedy/plugin-qrcode/package.json
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
PR: lynx-family/lynx-stack#1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • examples/react/lynx.config.js
  • packages/rspeedy/core/src/plugins/dev.plugin.ts
  • .changeset/crazy-jeans-hunt.md
  • .changeset/slow-radios-rescue.md
  • .changeset/config.json
  • packages/web-platform/web-rsbuild-server-middleware/package.json
  • packages/web-platform/web-tests/package.json
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/react/testing-library/src/vitest.config.js` is source code for the testing library that gets exported for users, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • examples/react/lynx.config.js
  • packages/web-platform/web-rsbuild-server-middleware/vitest.config.ts
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
PR: lynx-family/lynx-stack#1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • .changeset/tricky-lamps-battle.md
  • .changeset/crazy-jeans-hunt.md
  • .changeset/slow-radios-rescue.md
  • .changeset/config.json
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Applied to files:

  • .changeset/tricky-lamps-battle.md
  • .changeset/config.json
📚 Learning: 2025-07-22T09:23:07.797Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.

Applied to files:

  • .changeset/tricky-lamps-battle.md
  • .changeset/crazy-jeans-hunt.md
  • .changeset/slow-radios-rescue.md
  • .changeset/config.json
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
PR: lynx-family/lynx-stack#1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • packages/rspeedy/core/src/plugins/dev.plugin.ts
  • .changeset/config.json
📚 Learning: 2025-08-21T08:46:54.494Z
Learnt from: upupming
PR: lynx-family/lynx-stack#1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.

Applied to files:

  • packages/rspeedy/core/src/plugins/dev.plugin.ts
  • .changeset/crazy-jeans-hunt.md
📚 Learning: 2025-08-07T04:00:59.645Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1454
File: pnpm-workspace.yaml:46-46
Timestamp: 2025-08-07T04:00:59.645Z
Learning: In the lynx-family/lynx-stack repository, the webpack patch (patches/webpack5.101.0.patch) was created to fix issues with webpack5.99.9 but only takes effect on webpack5.100.0 and later versions. The patchedDependencies entry should use "webpack@^5.100.0" to ensure the patch applies to the correct version range.

Applied to files:

  • .changeset/slow-radios-rescue.md
📚 Learning: 2025-08-19T11:25:36.127Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1558
File: .changeset/solid-squids-fall.md:2-2
Timestamp: 2025-08-19T11:25:36.127Z
Learning: In the lynx-family/lynx-stack repository, changesets should use the exact package name from package.json#name, not generic or unscoped names. Each package has its own specific scoped name (e.g., "lynx-js/react-transform" for packages/react/transform).

Applied to files:

  • .changeset/config.json
  • packages/web-platform/web-rsbuild-server-middleware/package.json
📚 Learning: 2025-09-09T12:38:10.450Z
Learnt from: CR
PR: lynx-family/lynx-stack#0
File: AGENTS.md:0-0
Timestamp: 2025-09-09T12:38:10.450Z
Learning: Applies to packages/web-platform/web-tests/** : Place Playwright E2E tests in the web platform’s web-tests suite

Applied to files:

  • packages/web-platform/web-rsbuild-server-middleware/test/basic.spec.ts
  • packages/web-platform/web-tests/tests/middleware.spec.ts
  • packages/web-platform/web-tests/package.json
  • packages/web-platform/web-rsbuild-server-middleware/vitest.config.ts
📚 Learning: 2025-08-14T12:54:51.143Z
Learnt from: upupming
PR: lynx-family/lynx-stack#1370
File: .changeset/brave-melons-add.md:1-7
Timestamp: 2025-08-14T12:54:51.143Z
Learning: In the lynx-family/lynx-stack repository, packages use 0.x.x versioning where minor version bumps indicate breaking changes (not major bumps), following pre-1.0 semantic versioning conventions.

Applied to files:

  • packages/web-platform/web-rsbuild-server-middleware/Notice.txt
📚 Learning: 2025-08-06T13:28:57.182Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1453
File: vitest.config.ts:49-61
Timestamp: 2025-08-06T13:28:57.182Z
Learning: In the lynx-family/lynx-stack repository, the file `packages/rspeedy/create-rspeedy/template-react-vitest-rltl-js/vitest.config.js` is a template file for scaffolding new Rspeedy projects, not a test configuration that should be included in the main vitest projects array.

Applied to files:

  • packages/web-platform/web-rsbuild-server-middleware/vitest.config.ts
🧬 Code graph analysis (10)
packages/rspeedy/core/src/plugins/dev.plugin.ts (1)
packages/rspeedy/core/src/utils/is-lynx.ts (1)
  • isLynx (7-11)
packages/web-platform/web-rsbuild-server-middleware/src/web/index.ts (1)
packages/web-platform/web-tests/server.js (1)
  • lynxView (16-33)
packages/rspeedy/core/test/plugins/dev.plugin.test.ts (1)
packages/rspeedy/core/test/createStubRspeedy.ts (1)
  • createStubRspeedy (20-64)
packages/web-platform/web-rsbuild-server-middleware/src/node/index.ts (2)
packages/web-platform/web-tests/rspack.config.js (2)
  • __filename (14-14)
  • __dirname (15-15)
packages/web-platform/web-style-transformer/scripts/build.js (1)
  • packageRoot (7-7)
packages/web-platform/web-tests/rspack.config.js (1)
packages/web-platform/web-rsbuild-server-middleware/src/node/index.ts (1)
  • createWebVirtualFilesMiddleware (22-89)
packages/rspeedy/plugin-qrcode/test/preview.test.ts (1)
packages/rspeedy/plugin-qrcode/src/index.ts (1)
  • pluginQRCode (93-180)
packages/web-platform/web-rsbuild-server-middleware/rsbuild.config.ts (1)
packages/web-platform/web-tests/rspack.config.js (1)
  • __dirname (15-15)
packages/web-platform/web-rsbuild-server-middleware/test/basic.spec.ts (1)
packages/web-platform/web-rsbuild-server-middleware/src/node/index.ts (1)
  • createWebVirtualFilesMiddleware (22-89)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (3)
packages/rspeedy/plugin-qrcode/src/index.ts (1)
  • CustomizedSchemaFn (22-24)
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (1)
  • generateDevUrls (10-69)
packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1)
  • showQRCode (8-17)
packages/rspeedy/plugin-qrcode/src/index.ts (2)
packages/web-platform/web-rsbuild-server-middleware/src/node/index.ts (1)
  • createWebVirtualFilesMiddleware (22-89)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (1)
  • registerConsoleShortcuts (30-67)
🪛 GitHub Check: code-style-check
packages/rspeedy/plugin-qrcode/src/index.ts

[failure] 13-13:
Cannot find module '@lynx-js/web-rsbuild-server-middleware' or its corresponding type declarations.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: test-rust / Test (Ubuntu)
🔇 Additional comments (32)
.changeset/crazy-jeans-hunt.md (1)

1-6: Good patch entry.

Clear fix note for web platform error.

.changeset/tricky-lamps-battle.md (1)

1-15: Feature changeset reads well.

Message and example align with adding web preview support.

examples/react/lynx.config.js (3)

8-13: Two entries pointing to the same file—intentional?

Duplicating entry to the same path can create duplicate bundles unless used to exercise multi-entry behavior.

If unintentional, remove main2:

   entry: {
     main: './src/index.tsx',
-    main2: './src/index.tsx',
   },

16-21: Confirm schema callback signature with new QR code URLs.

If the plugin now passes a composite URLs object, adjust the example accordingly; otherwise current string mapping is fine.

If composite is passed:

-      schema(url) {
-        return `${url}?fullscreen=true`;
-      },
+      schema(urls) {
+        if (typeof urls === 'string') return `${urls}?fullscreen=true`;
+        return {
+          ...urls,
+          web: `${urls.web}?fullscreen=true`,
+          lynx: Object.fromEntries(
+            Object.entries(urls.lynx).map(([k, v]) => [k, `${v}?fullscreen=true`]),
+          ),
+        };
+      },

26-29: Environments block LGTM.

Matches the new web and lynx split.

packages/rspeedy/core/src/plugins/dev.plugin.ts (2)

15-15: Import of isLynx is appropriate.

Sets up environment gating cleanly.


123-171: HMR aliases and ProvidePlugin gated to Lynx—LGTM.

Matches new behavior and corresponding tests; chaining looks correct.

Please confirm web still gets a working dev experience without these aliases (no unintended regressions in live reload/HMR expectations for web).

packages/web-platform/web-rsbuild-server-middleware/rslib.config.ts (2)

22-32: Type-check/publish plugins usage looks good.

Conditional ATTW and publint integration is appropriate.


12-14: dts.tsgo is a valid (experimental) Rslib option — no change required
Rslib supports dts.tsgo (boolean) to enable tsgo/@typescript/native-preview for faster .d.ts generation; it defaults to false and requires installing @typescript/native-preview and a recent Node.js runtime.

.changeset/slow-radios-rescue.md (1)

1-6: Approve changeset — package is public; patch OK.
package.json shows "private": false, so a patch changeset for an initial publish is appropriate.

packages/web-platform/tsconfig.json (1)

25-26: LGTM — project reference wired

Reference to web-rsbuild-server-middleware is correctly added.

packages/web-platform/web-rsbuild-server-middleware/LICENSE.txt (1)

1-203: LGTM — Apache-2.0 included

License content present and consistent with repo licensing.

packages/web-platform/web-tests/rspack.config.js (1)

13-14: LGTM — imports middleware

Import is correct and scoped to devServer usage.

packages/web-platform/web-tests/package.json (1)

40-41: LGTM — Playwright tests target the mounted "/middleware" path

rspack.config.js mounts createWebVirtualFilesMiddleware('/middleware'); middleware.spec.ts navigates to "middleware?casename=…"(relative), so the tests will hit the same subPath (see packages/web-platform/web-tests/rspack.config.js and packages/web-platform/web-tests/tests/middleware.spec.ts).

packages/web-platform/web-tests/tests/middleware.spec.ts (1)

49-53: Tests are correctly placed under web-tests suite.

Placement aligns with repository testing conventions.

packages/rspeedy/plugin-qrcode/package.json (1)

50-52: Dependency addition looks correct (runtime usage).

Using a runtime dependency makes sense for dev-server integration.

Please confirm this package is intended as a runtime dep (not dev/peer). If it’s only needed during development of this plugin, consider devDependency. Also ensure a changeset is added for this package if publishable versions change due to the new dep.

.changeset/config.json (1)

18-20: Adding the new public package to the fixed group looks good.

Ensure this PR includes a changeset for introducing @lynx-js/web-rsbuild-server-middleware and any packages with meaningful user-facing changes.

packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1)

8-16: Call sites updated to the new signature (lynxUrl?, webUrl?)

showQRCode is called as showQRCode(lynxUrl, webUrl) in packages/rspeedy/plugin-qrcode/src/shortcuts.ts (lines ~56 and ~158).

packages/web-platform/web-rsbuild-server-middleware/rsbuild.config.ts (1)

20-22: Confirm config option name and intent.

  • output.overrideBrowserslist is a valid rsbuild option and will override .browserslistrc / package.json; rsbuild recommends using a .browserslistrc for portability.
  • Verify assetPrefix 'http://lynx-web-core-mocked.localhost/' exactly matches the replacement string used by the middleware.

Location: packages/web-platform/web-rsbuild-server-middleware/rsbuild.config.ts (lines 20–22)

packages/rspeedy/plugin-qrcode/src/index.ts (5)

106-110: Middleware mount is correct; confirm no route conflicts

Mounting at '/web' looks fine. Verify no existing dev-server routes use '/web' and ensure this executes before any catch-all/static handlers that could shadow it.


111-113: LGTM

Prod preview path now prints QR consistently using the environments map.


132-133: LGTM

Dev compile hook guards against duplicate prints; good integration with environments map and server port.


147-159: Entry aggregation looks good

Union of lynx/web entries with unique deduping is correct.


160-177: Console shortcuts registration looks good

Structured entries { all, lynx, web } flow matches updated consumers.

packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2)

38-47: Base URL normalization is solid

Replacing and falling back to localhost is robust.


64-69: LGTM

Return shape { lynx, web } and lynx schema handling are correct.

packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts (1)

41-57: Tests updated correctly for new API

entries shape and onPrint(lynx, web) expectations align with implementation.

packages/rspeedy/plugin-qrcode/test/preview.test.ts (2)

180-214: Preview without entry behavior verified

No QR render when entries empty; updated port range is fine.


215-248: Preview without lynx env behavior verified

Skips QR rendering as expected when lynx/web not configured.

packages/web-platform/web-rsbuild-server-middleware/src/web/index.ts (2)

11-15: LGTM

Init of lynx-view and reading casename from query looks correct.


16-44: LGTM

LocalStorage-backed initData/globalProps with safe parsing is sound.

packages/rspeedy/plugin-qrcode/src/shortcuts.ts (1)

39-41: Default entry selection is fine; guard is upstream

Relies on index.ts ensuring there’s at least one lynx/web entry.

Comment on lines 55 to 63
const outputPathname = new URL(
name.replace('[name]', entry).replace('[platform]', 'web'),
base,
).pathname
const web = new URL(
`/web?casename=${outputPathname}`,
base,
).toString()

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Encode query parameter to avoid broken URLs

outputPathname can contain slashes and special chars; it should be URL-encoded when used as a query param.

Apply this diff:

-  const web = new URL(
-    `/web?casename=${outputPathname}`,
-    base,
-  ).toString()
+  const web = new URL(
+    `/web?casename=${encodeURIComponent(outputPathname)}`,
+    base,
+  ).toString()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const outputPathname = new URL(
name.replace('[name]', entry).replace('[platform]', 'web'),
base,
).pathname
const web = new URL(
`/web?casename=${outputPathname}`,
base,
).toString()
const outputPathname = new URL(
name.replace('[name]', entry).replace('[platform]', 'web'),
base,
).pathname
const web = new URL(
`/web?casename=${encodeURIComponent(outputPathname)}`,
base,
).toString()
🤖 Prompt for AI Agents
In packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts around lines 55 to 63,
the code inserts outputPathname directly into the query string which can break
URLs when outputPathname contains slashes or special characters; update the code
to URL-encode the path before adding it to the query (e.g. use
encodeURIComponent(outputPathname)) so the generated /web?casename=... parameter
is safe and correctly formed.

Comment on lines +13 to +14
import { createWebVirtualFilesMiddleware } from '@lynx-js/web-rsbuild-server-middleware'

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

Fix missing dependency/exports for web middleware import

Type-check fails: Cannot find module '@lynx-js/web-rsbuild-server-middleware'. Ensure the package is part of the workspace, exported correctly, and added as a dependency of this plugin. If the package exposes a node entry, import it explicitly.

Apply one of:

- import { createWebVirtualFilesMiddleware } from '@lynx-js/web-rsbuild-server-middleware'
+ import { createWebVirtualFilesMiddleware } from '@lynx-js/web-rsbuild-server-middleware/node'

Or add dependency and proper exports/types to the workspace package.

Run this script to verify dependency wiring and exports:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Check plugin dependency..."
PLUGIN_PKG=$(fd -a -t f '^package\.json$' | rg -n 'packages/rspeedy/plugin-qrcode/package.json' -N | cut -d: -f1 || true)
WEB_PKG=$(fd -a -t f '^package\.json$' | rg -n 'packages/web-platform/web-rsbuild-server-middleware/package.json' -N | cut -d: -f1 || true)

if [[ -z "$PLUGIN_PKG" || -z "$WEB_PKG" ]]; then
  echo "Missing package.json files. Found:"
  echo "plugin: $PLUGIN_PKG"
  echo "web   : $WEB_PKG"
  exit 1
fi

echo "Plugin depends on web middleware?"
jq -r '.dependencies["@lynx-js/web-rsbuild-server-middleware"], .devDependencies["@lynx-js/web-rsbuild-server-middleware"]' "$PLUGIN_PKG"

echo "Web middleware package name and exports:"
jq -r '.name, .exports, .main, .types' "$WEB_PKG"

echo "Look for a 'node' export subpath:"
jq -r '.exports["./node"], .exports["node"]' "$WEB_PKG" 2>/dev/null || true

Length of output: 225


Expose a node entry and type declarations from @lynx-js/web-rsbuild-server-middleware

  • packages/rspeedy/plugin-qrcode/package.json depends on @lynx-js/web-rsbuild-server-middleware (workspace:*).
  • packages/web-platform/web-rsbuild-server-middleware/package.json has no "exports" and no "types" (main: dist/index.js) and does not expose a "./node" subpath — add an "exports" mapping (include "./node" if you intend to import '/node') and publish TypeScript declarations or set "types" so the module can be resolved by type-checking.
🧰 Tools
🪛 GitHub Check: code-style-check

[failure] 13-13:
Cannot find module '@lynx-js/web-rsbuild-server-middleware' or its corresponding type declarations.

🤖 Prompt for AI Agents
In packages/rspeedy/plugin-qrcode/src/index.ts around lines 13 to 14, the import
from '@lynx-js/web-rsbuild-server-middleware' fails type-resolution because the
source package (packages/web-platform/web-rsbuild-server-middleware) does not
declare "exports" (including a "./node" subpath if you intend to import a
node-specific entry) nor does it publish TypeScript declarations or set "types".
Fix package.json of web-rsbuild-server-middleware by adding an "exports" map
that exposes the default entry and a "./node" subpath (pointing to the built JS
files), and add a "types" field or publish .d.ts files from the dist so
TypeScript and consumers can resolve imports and typings correctly; then
rebuild/publish the package and update workspace deps if needed.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
.changeset/tricky-lamps-battle.md (2)

2-3: Use a minor bump for a user-facing feature

This enables a new user-facing capability (web platform preview). Recommend minor instead of patch.

---
-"@lynx-js/qrcode-rsbuild-plugin": patch
+"@lynx-js/qrcode-rsbuild-plugin": minor
---

2-3: Add changeset entries for other touched packages (core dev plugin)

Core dev plugin changes (gating HMR by environment) affect users and live under src/**. Add a changeset (patch) for the core package to satisfy CI and release the behavior change.

packages/rspeedy/core/test/plugins/dev.plugin.test.ts (1)

102-121: Tighten the “no HMR for web” assertions

Using not.toHaveProperty(key, value) passes if the value differs, even when the property exists. If the intent is “property absent”, omit the second arg.

-    expect(config.resolve?.alias).not.toHaveProperty(
-      '@rspack/core/hot/dev-server',
-      expect.stringContaining('hot/dev-server.js'.replaceAll('/', path.sep)),
-    )
-    expect(config.resolve?.alias).not.toHaveProperty(
-      '@lynx-js/webpack-dev-transport/client',
-      expect.stringContaining(
-        'packages/webpack/webpack-dev-transport'.replaceAll('/', path.sep),
-      ),
-    )
+    expect(config.resolve?.alias).not.toHaveProperty('@rspack/core/hot/dev-server')
+    expect(config.resolve?.alias).not.toHaveProperty('@lynx-js/webpack-dev-transport/client')
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (2)

111-125: Show environment-appropriate hints in “Switch entries”

Don’t hint a Lynx URL for web-only entries.

-        options: options.entries.all.map(entry => {
-          const newDevUrls = generateDevUrls(
+        options: options.entries.all.map(entry => {
+          const newDevUrls = generateDevUrls(
             options.api,
             entry,
             options.schema,
             options.port,
           )
-          return {
-            value: entry,
-            label: entry,
-            hint: (newDevUrls.lynx[currentSchema] ?? newDevUrls.web),
-          }
+          const lynxEnabled = options.entries.lynx.includes(entry)
+          const webEnabled = options.entries.web.includes(entry)
+          return {
+            value: entry,
+            label: entry,
+            hint: lynxEnabled
+              ? newDevUrls.lynx[currentSchema]
+              : webEnabled
+              ? newDevUrls.web
+              : undefined,
+          }
         }),

85-89: Loop guard uses cancel checks on URL values

value.lynx/web are URLs, not clack cancel symbols. The inner menu break handles cancel/quit; this outer guard can be simplified.

-  while (
-    !(value.lynx && isCancel(value.lynx) || value.web && isCancel(value.web))
-  ) {
+  while (true) {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6b0e0a2 and 709e3c0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • .changeset/crazy-jeans-hunt.md (1 hunks)
  • .changeset/tricky-lamps-battle.md (1 hunks)
  • examples/react/lynx.config.js (2 hunks)
  • packages/rspeedy/core/src/plugins/dev.plugin.ts (2 hunks)
  • packages/rspeedy/core/test/plugins/dev.plugin.test.ts (1 hunks)
  • packages/rspeedy/plugin-qrcode/package.json (1 hunks)
  • packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2 hunks)
  • packages/rspeedy/plugin-qrcode/src/index.ts (4 hunks)
  • packages/rspeedy/plugin-qrcode/src/shortcuts.ts (8 hunks)
  • packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1 hunks)
  • packages/rspeedy/plugin-qrcode/test/preview.test.ts (5 hunks)
  • packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts
  • .changeset/crazy-jeans-hunt.md
  • packages/rspeedy/plugin-qrcode/package.json
  • examples/react/lynx.config.js
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

For contributions, always generate a changeset and commit the resulting markdown file(s)

Files:

  • .changeset/tricky-lamps-battle.md
🧠 Learnings (8)
📓 Common learnings
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
PR: lynx-family/lynx-stack#1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • .changeset/tricky-lamps-battle.md
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Applied to files:

  • .changeset/tricky-lamps-battle.md
📚 Learning: 2025-07-22T09:23:07.797Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.

Applied to files:

  • .changeset/tricky-lamps-battle.md
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
PR: lynx-family/lynx-stack#1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • packages/rspeedy/core/src/plugins/dev.plugin.ts
  • packages/rspeedy/plugin-qrcode/src/index.ts
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • packages/rspeedy/core/src/plugins/dev.plugin.ts
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
PR: lynx-family/lynx-stack#1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • packages/rspeedy/core/src/plugins/dev.plugin.ts
📚 Learning: 2025-08-21T08:46:54.494Z
Learnt from: upupming
PR: lynx-family/lynx-stack#1370
File: packages/webpack/cache-events-webpack-plugin/src/LynxCacheEventsRuntimeModule.ts:23-27
Timestamp: 2025-08-21T08:46:54.494Z
Learning: In Lynx webpack runtime modules, the team prioritizes performance and simplicity over defensive runtime error handling. They prefer relying on compile-time type safety (TypeScript) rather than adding runtime checks like try-catch blocks or type validation, especially for performance-critical code like cache event setup/cleanup functions.

Applied to files:

  • packages/rspeedy/core/src/plugins/dev.plugin.ts
🧬 Code graph analysis (5)
packages/rspeedy/core/src/plugins/dev.plugin.ts (1)
packages/rspeedy/core/src/utils/is-lynx.ts (1)
  • isLynx (7-11)
packages/rspeedy/plugin-qrcode/test/preview.test.ts (1)
packages/rspeedy/plugin-qrcode/src/index.ts (1)
  • pluginQRCode (93-180)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (3)
packages/rspeedy/plugin-qrcode/src/index.ts (1)
  • CustomizedSchemaFn (22-24)
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (1)
  • generateDevUrls (10-69)
packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1)
  • showQRCode (8-17)
packages/rspeedy/core/test/plugins/dev.plugin.test.ts (1)
packages/rspeedy/core/test/createStubRspeedy.ts (1)
  • createStubRspeedy (20-64)
packages/rspeedy/plugin-qrcode/src/index.ts (2)
packages/web-platform/web-rsbuild-server-middleware/src/node/index.ts (1)
  • createWebVirtualFilesMiddleware (22-89)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (1)
  • registerConsoleShortcuts (30-67)
🪛 GitHub Check: code-style-check
packages/rspeedy/plugin-qrcode/src/index.ts

[failure] 13-13:
Cannot find module '@lynx-js/web-rsbuild-server-middleware' or its corresponding type declarations.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: test-rust / Test (Ubuntu)
🔇 Additional comments (11)
packages/rspeedy/core/src/plugins/dev.plugin.ts (1)

123-171: LGTM: Correctly gate HMR wiring to Lynx env only

Aliasing and ProvidePlugin are now applied only when isLynx(environment). This prevents accidental HMR client injection for web. Looks good.

Please ensure default tests still run under a Lynx environment by default (they appear to).

packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2)

38-47: Nice fallback for malformed assetPrefix

Graceful fallback to http://localhost:<port>/ keeps preview resilient if dev.assetPrefix is invalid.


55-63: Encode query parameter to avoid broken URLs

outputPathname can contain slashes/special chars; it should be URL-encoded when used in a query param.

-  const web = new URL(
-    `/web?casename=${outputPathname}`,
-    base,
-  ).toString()
+  const web = new URL(
+    `/web?casename=${encodeURIComponent(outputPathname)}`,
+    base,
+  ).toString()
packages/rspeedy/plugin-qrcode/src/index.ts (3)

106-110: LGTM: Web middleware registration is properly scoped

Middleware is mounted only when a web environment exists and before dev server starts. Good boundary.


147-171: LGTM: Multi-environment entry handling

Collecting lynx and web entries and early-exiting when none exist aligns with the new dual-URL flow.


13-14: Expose ./node entry and types in web-rsbuild-server-middleware

  • In packages/web-rsbuild-server-middleware/package.json add an exports["./node"] entry pointing to the Node output and publish its .d.ts.
  • Then update the import in packages/rspeedy/plugin-qrcode/src/index.ts:
-import { createWebVirtualFilesMiddleware } from '@lynx-js/web-rsbuild-server-middleware'
+import { createWebVirtualFilesMiddleware } from '@lynx-js/web-rsbuild-server-middleware/node'
packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1)

8-16: LGTM: Dual output without changing QR semantics

Keeps QR rendering for Lynx only and logs the Web URL separately, matching test expectations.

packages/rspeedy/plugin-qrcode/test/preview.test.ts (2)

180-213: LGTM: “no entry” preview path covered

Test ensures no QR is rendered when entries are empty. Matches plugin skip logic.


215-248: LGTM: No Lynx environment should not render QR or exit

Confirms no QR printed and process not exited when environments.lynx is absent.

packages/rspeedy/plugin-qrcode/src/shortcuts.ts (2)

170-181: Gate URLs by environment presence when switching entry/schema

Avoid showing a Lynx URL for a web-only entry (and vice versa).

-  function getCurrentUrl(): {
-    lynx: string | undefined
-    web: string | undefined
-  } {
-    const { lynx, web } = generateDevUrls(
+  function getCurrentUrl(): { lynx: string | undefined; web: string | undefined } {
+    const { lynx, web } = generateDevUrls(
       options.api,
       currentEntry,
       options.schema,
       options.port,
     )
-    return { lynx: lynx[currentSchema], web }
+    const lynxEnabled = options.entries.lynx.includes(currentEntry)
+    const webEnabled = options.entries.web.includes(currentEntry)
+    return {
+      lynx: lynxEnabled ? lynx[currentSchema] : undefined,
+      web: webEnabled ? web : undefined,
+    }
   }

48-56: Initial print correctly gated per environment

Nice touch to avoid emitting Lynx QR for web-only entries and vice versa.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

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 (7)
.changeset/tricky-lamps-battle.md (1)

2-3: Use a minor bump for a feature addition

This is a new feature; recommend "minor" instead of "patch" per semver.

----
-"@lynx-js/qrcode-rsbuild-plugin": patch
+"@lynx-js/qrcode-rsbuild-plugin": minor
----
packages/web-platform/web-rsbuild-server-middleware/package.json (1)

15-15: Also set the "types" field for TS tooling compatibility

TypeScript recognizes both, but "types" is the common field; keep "typings" if you prefer, but add "types" for consistency across the repo.

   "main": "dist/index.js",
-  "typings": "dist/index.d.ts",
+  "typings": "dist/index.d.ts",
+  "types": "dist/index.d.ts",
packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1)

8-16: Optionally render a QR for the web URL

If scanning to open the web preview on a phone is useful, also render a QR when webUrl is provided.

 export default function showQRCode(lynxUrl?: string, webUrl?: string): void {
   if (lynxUrl) {
     log.info(color.green('Scan with Lynx'))
     log.success(renderUnicodeCompact(lynxUrl))
     log.success('Lynx Explorer: ' + lynxUrl)
   }
   if (webUrl) {
-    log.success('Lynx Web Platform: ' + webUrl)
+    log.info(color.cyan('Open in browser'))
+    log.success(renderUnicodeCompact(webUrl))
+    log.success('Lynx Web Platform: ' + webUrl)
   }
 }
packages/rspeedy/plugin-qrcode/src/index.ts (1)

112-112: Also serve middleware in preview mode (if needed)

If the web preview requires the same assets in rsbuild preview, add the middleware for prod server too.

-      api.onAfterStartProdServer(async ({ environments, port }) => {
-        await main(environments, port)
-      })
+      api.onAfterStartProdServer(async ({ environments, server, port }) => {
+        if (environments['web']) {
+          server.middlewares.use(createWebVirtualFilesMiddleware('/web'))
+        }
+        await main(environments, port)
+      })
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (3)

39-41: Avoid non-null assertion; handle empty entries gracefully

Guard when both entries.lynx and entries.web are empty to prevent runtime crash and provide a no-op unregistration.

-  // keep the default entry to be lynx explorer entry if exists
-  const currentEntry = (options.entries.lynx[0] ?? options.entries.web[0])!
+  // keep the default entry to be lynx explorer entry if exists
+  const currentEntry = options.entries.lynx[0] ?? options.entries.web[0]
+  if (!currentEntry) {
+    await options.onPrint?.()
+    showQRCode()
+    return () => {}
+  }

111-126: Gate entry hints by environment membership

When listing entries, avoid showing a Lynx URL for web-only entries (and vice versa). Compute hint with per-entry gating.

-        options: options.entries.all.map(entry => {
-          const newDevUrls = generateDevUrls(
+        options: options.entries.all.map(entry => {
+          const newDevUrls = generateDevUrls(
             options.api,
             entry,
             options.schema,
             options.port,
-          )
-          return {
-            value: entry,
-            label: entry,
-            hint: (newDevUrls.lynx[currentSchema] ?? newDevUrls.web),
-          }
+          )
+          const hasLynx = options.entries.lynx.includes(entry)
+          const hasWeb = options.entries.web.includes(entry)
+          const hint = hasLynx
+            ? newDevUrls.lynx[currentSchema]
+            : hasWeb
+              ? newDevUrls.web
+              : undefined
+          return { value: entry, label: entry, hint }
         }),

140-146: Avoid shadowing outer devUrls; rename for clarity

The local variable shadows the parameter, increasing cognitive load.

-      const devUrls = generateDevUrls(
+      const newDevUrls = generateDevUrls(
         options.api,
         currentEntry,
         options.schema,
         options.port,
       )
-      const selection = await selectFn(Object.keys(devUrls.lynx).length)({
+      const selection = await selectFn(Object.keys(newDevUrls.lynx).length)({
         message: 'Select schema',
-        options: Object.entries(devUrls.lynx).map(([name, url]) => ({
+        options: Object.entries(newDevUrls.lynx).map(([name, url]) => ({
           value: name,
           label: name,
           hint: url,
         })),
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 709e3c0 and ede6c13.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (17)
  • .changeset/crazy-jeans-hunt.md (1 hunks)
  • .changeset/tricky-lamps-battle.md (1 hunks)
  • examples/react/lynx.config.js (1 hunks)
  • packages/rspeedy/core/src/plugins/dev.plugin.ts (3 hunks)
  • packages/rspeedy/core/test/plugins/dev.plugin.test.ts (1 hunks)
  • packages/rspeedy/plugin-qrcode/package.json (1 hunks)
  • packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2 hunks)
  • packages/rspeedy/plugin-qrcode/src/index.ts (4 hunks)
  • packages/rspeedy/plugin-qrcode/src/shortcuts.ts (8 hunks)
  • packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1 hunks)
  • packages/rspeedy/plugin-qrcode/test/preview.test.ts (5 hunks)
  • packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts (2 hunks)
  • packages/rspeedy/plugin-qrcode/tsconfig.build.json (1 hunks)
  • packages/rspeedy/plugin-qrcode/tsconfig.json (1 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/package.json (2 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/rslib.config.ts (0 hunks)
  • packages/web-platform/web-rsbuild-server-middleware/tsconfig.json (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/web-platform/web-rsbuild-server-middleware/rslib.config.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/rspeedy/plugin-qrcode/test/preview.test.ts
  • packages/rspeedy/core/src/plugins/dev.plugin.ts
  • packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts
  • .changeset/crazy-jeans-hunt.md
  • examples/react/lynx.config.js
  • packages/rspeedy/core/test/plugins/dev.plugin.test.ts
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

For contributions, always generate a changeset and commit the resulting markdown file(s)

Files:

  • .changeset/tricky-lamps-battle.md
🧠 Learnings (3)
📓 Common learnings
Learnt from: gaoachao
PR: lynx-family/lynx-stack#1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.
Learnt from: gaoachao
PR: lynx-family/lynx-stack#1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.
📚 Learning: 2025-08-27T08:10:09.932Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1612
File: packages/rspeedy/create-rspeedy/template-react-vitest-rltl-ts/src/tsconfig.json:3-13
Timestamp: 2025-08-27T08:10:09.932Z
Learning: In the lynx-family/lynx-stack repository, Rspeedy templates use `lynx-js/rspeedy/client` types via `rspeedy-env.d.ts` instead of `vite/client` types. Rspeedy provides its own client-side environment type definitions and doesn't require direct Vite type references.

Applied to files:

  • packages/rspeedy/plugin-qrcode/package.json
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
PR: lynx-family/lynx-stack#1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • packages/rspeedy/plugin-qrcode/src/index.ts
🧬 Code graph analysis (2)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (3)
packages/rspeedy/plugin-qrcode/src/index.ts (1)
  • CustomizedSchemaFn (22-24)
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (1)
  • generateDevUrls (10-69)
packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1)
  • showQRCode (8-17)
packages/rspeedy/plugin-qrcode/src/index.ts (2)
packages/web-platform/web-rsbuild-server-middleware/src/node/index.ts (1)
  • createWebVirtualFilesMiddleware (22-89)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (1)
  • registerConsoleShortcuts (30-67)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: test-rust / Test (Ubuntu)
🔇 Additional comments (12)
packages/rspeedy/plugin-qrcode/package.json (1)

50-52: Dependency wiring for web middleware looks correct

Runtime dep added; aligns with new middleware usage in the plugin.

If you intend to import from the package root, confirm that @lynx-js/web-rsbuild-server-middleware’s root index exports createWebVirtualFilesMiddleware (see comment on index.ts for a verification script).

packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (1)

55-63: Encode query parameter to avoid broken URLs

-  const web = new URL(
-    `/web?casename=${outputPathname}`,
-    base,
-  ).toString()
+  const web = new URL(
+    `/web?casename=${encodeURIComponent(outputPathname)}`,
+    base,
+  ).toString()
packages/rspeedy/plugin-qrcode/src/index.ts (4)

106-110: Good: middleware gated to web environment

Registering the virtual files middleware only when environments.web exists is sound.


132-132: LGTM: single print on first successful build

Avoids duplicate QR output on rebuilds.


148-177: Entry computation and shortcut registration look correct

Merges lynx/web entries, handles empty case, and wires cleanup on dev-server close.

If rsbuild exposes a separate close hook for preview/prod servers, consider mirroring cleanup there to avoid leaks when running preview.


13-14: Confirm root export of createWebVirtualFilesMiddleware

This import assumes the package root re-exports the Node entry. If not, either add an exports map in the middleware package or import from a subpath you expose (e.g. './node').

Verification script to check the middleware package source exports:

If missing, consider adding an exports map:

+  "exports": {
+    ".": {
+      "types": "./dist/index.d.ts",
+      "default": "./dist/index.js"
+    },
+    "./node": {
+      "types": "./dist/node/index.d.ts",
+      "default": "./dist/node/index.js"
+    }
+  },
packages/rspeedy/plugin-qrcode/tsconfig.build.json (1)

10-10: Ensure referenced project is composite

TypeScript project references require the target tsconfig to have "composite": true; please verify the middleware tsconfig is set accordingly.

packages/web-platform/web-rsbuild-server-middleware/package.json (1)

26-26: Verify build emits .d.ts to dist/

With rslib.config.ts removed and a consolidated "rsbuild build", ensure declaration files still land in dist to satisfy "typings"/"types".

packages/rspeedy/plugin-qrcode/src/shortcuts.ts (2)

48-56: LGTM: initial per-environment gating before print

Correctly gates Lynx/Web URLs against current entry before printing/logging.


170-181: Gate URLs by environment when switching entry/schema (regression of prior fix)

Reintroduces the issue of exposing a Lynx URL for web-only entries (and vice versa). Gate per entries.lynx/web.

   function getCurrentUrl(): {
     lynx: string | undefined
     web: string | undefined
   } {
     const { lynx, web } = generateDevUrls(
       options.api,
       currentEntry,
       options.schema,
       options.port,
     )
-    return { lynx: lynx[currentSchema], web }
+    const lynxEnabled = options.entries.lynx.includes(currentEntry)
+    const webEnabled = options.entries.web.includes(currentEntry)
+    return {
+      lynx: lynxEnabled ? lynx[currentSchema] : undefined,
+      web: webEnabled ? web : undefined,
+    }
   }
packages/web-platform/web-rsbuild-server-middleware/tsconfig.json (1)

5-5: LGTM: composite build config now emits; node-only include is clear

Removing noEmit and scoping to src/node aligns with being a referenced project.

Please confirm declarations are emitted (either implicit via composite or explicit) for downstream type consumption. If not, add:

   "compilerOptions": {
     "composite": true,
     "rootDir": "./src/node",
     "outDir": "./dist",
     "lib": ["ESNext"],
+    "declaration": true,
+    "declarationMap": true,
   },

Also applies to: 9-9

packages/rspeedy/plugin-qrcode/tsconfig.json (1)

10-10: Validate project reference target and declaration emit

Referencing the middleware’s tsconfig is fine; ensure it’s a composite project that emits declarations so TS project references work end-to-end.

  • If middleware tsconfig isn’t emitting .d.ts, add "declaration": true (and optionally "declarationMap": true) there.
  • Alternatively, point to its build tsconfig if that’s the convention across the repo.

Run to verify:

@codspeed-hq
Copy link

codspeed-hq bot commented Sep 24, 2025

CodSpeed Performance Report

Merging #1816 will degrade performances by 11.47%

Comparing PupilTong:p/hw/web-qrcode-url (4ed1eae) with main (8983d4c)

🎉 Hooray! codspeed-node just leveled up to 4.0.1!

A heads-up, this is a breaking change and it might affect your current performance baseline a bit. But here's the exciting part - it's packed with new, cool features and promises improved result stability 🥳!
Curious about what's new? Visit our releases page to delve into all the awesome details about this new version.

Summary

⚡ 2 improvements
❌ 1 regression
✅ 50 untouched
⏩ 3 skipped1

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark BASE HEAD Change
transform 1000 view elements 45 ms 41.4 ms +8.81%
basic-performance-div-100 6.2 ms 5.9 ms +5.09%
basic-performance-small-css 6.9 ms 7.8 ms -11.47%

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@relativeci
Copy link

relativeci bot commented Sep 24, 2025

Web Explorer

#5813 Bundle Size — 365.13KiB (0%).

4ed1eae(current) vs 8983d4c main#5779(baseline)

Bundle metrics  Change 2 changes
                 Current
#5813
     Baseline
#5779
No change  Initial JS 145.05KiB 145.05KiB
No change  Initial CSS 32KiB 32KiB
No change  Cache Invalidation 0% 0%
No change  Chunks 8 8
No change  Assets 8 8
Change  Modules 217(-0.91%) 219
No change  Duplicate Modules 16 16
Change  Duplicate Code 3.37%(+0.3%) 3.36%
No change  Packages 4 4
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#5813
     Baseline
#5779
No change  JS 239.33KiB 239.33KiB
No change  Other 93.8KiB 93.8KiB
No change  CSS 32KiB 32KiB

Bundle analysis reportBranch PupilTong:p/hw/web-qrcode-urlProject dashboard


Generated by RelativeCIDocumentationReport issue

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/rspeedy/plugin-qrcode/src/index.ts (1)

147-177: Sort entry keys and ensure cleanup on production exit

  • Sort lynxEntries, webEntries, and allEntries for deterministic ordering.
  • No onCloseProdServer hook exists; invoke unregister in the onAfterStartProdServer teardown (or attach it to the production server’s close event) to avoid leaking console shortcuts.
-        const lynxEntries = Object.keys(environments['lynx']?.entry ?? {})
-        const webEntries = Object.keys(environments['web']?.entry ?? {})
-        const allEntries = [
-          ...new Set([
-            ...lynxEntries,
-            ...webEntries,
-          ]),
-        ]
+        const lynxEntries = Object.keys(environments['lynx']?.entry ?? {}).sort()
+        const webEntries = Object.keys(environments['web']?.entry ?? {}).sort()
+        const allEntries = Array.from(new Set([...lynxEntries, ...webEntries])).sort()
🧹 Nitpick comments (6)
packages/rspeedy/plugin-qrcode/tsconfig.json (1)

10-10: Project reference consistency (build vs. base tsconfig)

Consider referencing the middleware’s build tsconfig for consistency with the existing core reference, unless there’s a reason to target its base tsconfig.

If appropriate, apply:

-    { "path": "../../web-platform/web-rsbuild-server-middleware/tsconfig.json" },
+    { "path": "../../web-platform/web-rsbuild-server-middleware/tsconfig.build.json" },

Also verify the referenced tsconfig has "composite": true; otherwise tsc -b will fail.

packages/rspeedy/plugin-qrcode/src/shortcuts.ts (1)

111-125: Entry selection hint should respect per‑environment availability

Show the Lynx schema URL only for Lynx entries; otherwise show Web URL (if available).

Apply:

-        return {
-          value: entry,
-          label: entry,
-          hint: (newDevUrls.lynx[currentSchema] ?? newDevUrls.web),
-        }
+        const lynxEnabled = options.entries.lynx.includes(entry)
+        const webEnabled = options.entries.web.includes(entry)
+        return {
+          value: entry,
+          label: entry,
+          hint: lynxEnabled
+            ? newDevUrls.lynx[currentSchema]
+            : webEnabled
+              ? newDevUrls.web
+              : undefined,
+        }
.changeset/tricky-lamps-battle.md (1)

2-2: Semver bump likely should be minor, not patch

This adds a feature (web platform preview). Recommend bumping @lynx-js/qrcode-rsbuild-plugin to minor.

-"@lynx-js/qrcode-rsbuild-plugin": patch
+"@lynx-js/qrcode-rsbuild-plugin": minor

Please confirm your repo’s semver policy for features.

packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts (1)

54-57: Strengthen assertion: check the first call explicitly

Optional: assert the first invocation’s args explicitly to avoid ambiguity when multiple calls occur.

Apply:

-    expect(onPrint).toBeCalledWith(
+    expect(onPrint).toHaveBeenNthCalledWith(1,
       'https://example.com/foo.lynx.bundle',
       undefined,
     )
packages/rspeedy/plugin-qrcode/src/index.ts (2)

106-110: Confirm middleware mount path '/web' is correct and non-conflicting

Mounting at '/web' is reasonable; ensure this doesn’t clash with app routes or base/publicPath. Consider making the subpath configurable if needed.


112-113: Production: confirm that printing QR and console loop are desired

main() is invoked for prod server too. Verify that interactive console shortcuts (prompts) are intended in prod; otherwise, guard to dev-only.

Apply:

-      api.onAfterStartProdServer(async ({ environments, port }) => {
-        await main(environments, port)
-      })
+      api.onAfterStartProdServer(async ({ environments, port }) => {
+        if (process.env.NODE_ENV !== 'production') return
+        await main(environments, port)
+      })

Or, skip registering prompts entirely for prod.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ede6c13 and d791681.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • .changeset/tricky-lamps-battle.md (1 hunks)
  • examples/react/lynx.config.js (1 hunks)
  • packages/rspeedy/plugin-qrcode/package.json (1 hunks)
  • packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2 hunks)
  • packages/rspeedy/plugin-qrcode/src/index.ts (4 hunks)
  • packages/rspeedy/plugin-qrcode/src/shortcuts.ts (8 hunks)
  • packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1 hunks)
  • packages/rspeedy/plugin-qrcode/test/preview.test.ts (5 hunks)
  • packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts (2 hunks)
  • packages/rspeedy/plugin-qrcode/tsconfig.build.json (1 hunks)
  • packages/rspeedy/plugin-qrcode/tsconfig.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/rspeedy/plugin-qrcode/src/showQRCode.ts
  • packages/rspeedy/plugin-qrcode/package.json
  • packages/rspeedy/plugin-qrcode/test/preview.test.ts
  • packages/rspeedy/plugin-qrcode/tsconfig.build.json
🧰 Additional context used
📓 Path-based instructions (1)
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

For contributions, always generate a changeset and commit the resulting markdown file(s)

Files:

  • .changeset/tricky-lamps-battle.md
🧠 Learnings (5)
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
PR: lynx-family/lynx-stack#1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, private packages (marked with "private": true in package.json) like lynx-js/react-transform don't require meaningful changeset entries even when their public APIs change, since they are not published externally and only affect internal development.

Applied to files:

  • examples/react/lynx.config.js
📚 Learning: 2025-09-12T09:43:04.847Z
Learnt from: gaoachao
PR: lynx-family/lynx-stack#1736
File: .changeset/spotty-experts-smoke.md:1-3
Timestamp: 2025-09-12T09:43:04.847Z
Learning: In the lynx-family/lynx-stack repository, empty changeset files (containing only `---\n\n---`) are used for internal changes that modify src/** files but don't require meaningful release notes, such as private package changes or testing-only modifications. This satisfies CI requirements without generating user-facing release notes.

Applied to files:

  • .changeset/tricky-lamps-battle.md
📚 Learning: 2025-07-22T09:23:07.797Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:23:07.797Z
Learning: In the lynx-family/lynx-stack repository, changesets are only required for meaningful changes to end-users such as bugfixes and features. Internal/development changes like chores, refactoring, or removing debug info do not need changeset entries.

Applied to files:

  • .changeset/tricky-lamps-battle.md
📚 Learning: 2025-07-22T09:26:16.722Z
Learnt from: colinaaa
PR: lynx-family/lynx-stack#1330
File: .changeset/olive-animals-attend.md:1-3
Timestamp: 2025-07-22T09:26:16.722Z
Learning: In the lynx-family/lynx-stack repository, CI checks require changesets when files matching the pattern "src/**" are modified (as configured in .changeset/config.json). For internal changes that don't need meaningful changesets, an empty changeset file is used to satisfy the CI requirement while not generating any release notes.

Applied to files:

  • .changeset/tricky-lamps-battle.md
📚 Learning: 2025-08-27T12:42:01.095Z
Learnt from: upupming
PR: lynx-family/lynx-stack#1616
File: packages/webpack/cache-events-webpack-plugin/test/cases/not-cache-events/lazy-bundle/index.js:3-3
Timestamp: 2025-08-27T12:42:01.095Z
Learning: In webpack, properties like __webpack_require__.lynx_ce are injected during compilation/build time when webpack processes modules and generates bundles, not at runtime when dynamic imports execute. Tests for such properties don't need to wait for dynamic imports to complete.

Applied to files:

  • packages/rspeedy/plugin-qrcode/src/index.ts
🧬 Code graph analysis (2)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (3)
packages/rspeedy/plugin-qrcode/src/index.ts (1)
  • CustomizedSchemaFn (22-24)
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (1)
  • generateDevUrls (10-69)
packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1)
  • showQRCode (8-17)
packages/rspeedy/plugin-qrcode/src/index.ts (2)
packages/web-platform/web-rsbuild-server-middleware/src/node/index.ts (1)
  • createWebVirtualFilesMiddleware (22-89)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (1)
  • registerConsoleShortcuts (30-67)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: test-rust / rustfmt
  • GitHub Check: test-rust / Test (Ubuntu)
  • GitHub Check: code-style-check
🔇 Additional comments (9)
examples/react/lynx.config.js (1)

20-23: LGTM: environments map added

The environments map (web/lynx) aligns with the dual‑URL flow and web middleware wiring.

Please confirm the example runs with both Lynx and Web previews enabled in your local dev flow.

packages/rspeedy/plugin-qrcode/src/shortcuts.ts (3)

71-90: Remove dead cancel checks and unsafe casts; fix types

value.lynx/web are URLs, not cancel tokens; the loop condition is ineffective and types are overly permissive. Clean up types and loop condition; drop the casts.

Apply:

-async function loop(
-  options: Options,
-  value: { lynx: string | symbol | undefined, web: string | undefined },
-  devUrls: { lynx: Record<string, string | symbol>, web: string },
-  currentEntry: string,
-) {
+async function loop(
+  options: Options,
+  value: { lynx?: string; web?: string },
+  devUrls: { lynx: Record<string, string>; web: string },
+  currentEntry: string,
+) {
@@
-  while (
-    !(value.lynx && isCancel(value.lynx) || value.web && isCancel(value.web))
-  ) {
+  while (true) {
@@
-    await options.onPrint?.(value.lynx as string | undefined, value.web)
-    showQRCode(value.lynx as string, value.web)
+    await options.onPrint?.(value.lynx, value.web)
+    showQRCode(value.lynx, value.web)

Also applies to: 157-159


39-56: Initial defaulting and gating look good

Defaulting to a Lynx entry when present and gating initial lynx/web URLs by entry availability is correct.


170-181: Gate URLs by environment when switching entry/schema

Avoid returning a Lynx QR for a web‑only entry (and vice versa).

Apply:

-  function getCurrentUrl(): {
-    lynx: string | undefined
-    web: string | undefined
-  } {
+  function getCurrentUrl(): { lynx?: string; web?: string } {
     const { lynx, web } = generateDevUrls(
       options.api,
       currentEntry,
       options.schema,
       options.port,
     )
-    return { lynx: lynx[currentSchema], web }
+    const lynxEnabled = options.entries.lynx.includes(currentEntry)
+    const webEnabled = options.entries.web.includes(currentEntry)
+    return {
+      lynx: lynxEnabled ? lynx[currentSchema] : undefined,
+      web: webEnabled ? web : undefined,
+    }
   }
.changeset/tricky-lamps-battle.md (1)

5-15: LGTM: changeset content and example config

Good, concise release note with a minimal config example that mirrors the code changes.

packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2)

55-63: Encode query parameter to prevent malformed URLs

outputPathname may contain slashes and special characters; encode it before embedding in the query string.

Apply:

-  const web = new URL(
-    `/web?casename=${outputPathname}`,
-    base,
-  ).toString()
+  const web = new URL(
+    `/web?casename=${encodeURIComponent(outputPathname)}`,
+    base,
+  ).toString()

15-15: Return type change verified
All generateDevUrls call sites handle the { lynx, web } object correctly.

packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts (1)

41-45: LGTM: per-platform entries shape is correct

The test now passes the { all, lynx, web } structure expected by registerConsoleShortcuts. Looks good.

packages/rspeedy/plugin-qrcode/src/index.ts (1)

13-14: Fix middleware import path or ensure package exports/types

The root import may fail type-resolution unless the package exposes a root export. Import the explicit Node entry, or add proper exports/types to the middleware package.

Apply:

-import { createWebVirtualFilesMiddleware } from '@lynx-js/web-rsbuild-server-middleware'
+import { createWebVirtualFilesMiddleware } from '@lynx-js/web-rsbuild-server-middleware/node'

If you intend to keep the root path, ensure the middleware package provides an exports map and types.

Run to verify wiring:

#!/bin/bash
set -euo pipefail
fd -a package.json | rg -n 'packages/(rspeedy/plugin-qrcode|web-platform/web-rsbuild-server-middleware)/package.json' -N | cut -d: -f1 | while read -r p; do echo "==> $p"; cat "$p"; echo; done
echo "Searching for exports['./node'] mapping..."
rg -n '"exports"\s*:\s*{' -n -C3 packages/web-platform/web-rsbuild-server-middleware/package.json || true

Comment on lines 38 to 47
// <port> is supported in `dev.assetPrefix`, we should replace it with the real port
let base: string
try {
base = new URL(
'',
assetPrefix.replaceAll('<port>', String(port)),
).toString()
} catch {
base = `http://localhost:${port}/`
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Relative assetPrefix loses its path in fallback

If dev.assetPrefix is relative (e.g. "/assets"), the catch branch discards its path and falls back to just http://localhost:/. Resolve the (possibly relative) prefix against localhost to preserve the path.

Apply:

   let base: string
   try {
     base = new URL(
       '',
       assetPrefix.replaceAll('<port>', String(port)),
     ).toString()
   } catch {
-    base = `http://localhost:${port}/`
+    // Preserve relative or path-only assetPrefix by resolving against localhost
+    base = new URL(
+      assetPrefix.replaceAll('<port>', String(port)),
+      `http://localhost:${port}/`,
+    ).toString()
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// <port> is supported in `dev.assetPrefix`, we should replace it with the real port
let base: string
try {
base = new URL(
'',
assetPrefix.replaceAll('<port>', String(port)),
).toString()
} catch {
base = `http://localhost:${port}/`
}
// <port> is supported in `dev.assetPrefix`, we should replace it with the real port
let base: string
try {
base = new URL(
'',
assetPrefix.replaceAll('<port>', String(port)),
).toString()
} catch {
// Preserve relative or path-only assetPrefix by resolving against localhost
base = new URL(
assetPrefix.replaceAll('<port>', String(port)),
`http://localhost:${port}/`,
).toString()
}
🤖 Prompt for AI Agents
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts around lines 38-47: the
catch branch currently falls back to "http://localhost:<port>/" and drops any
path from a relative dev.assetPrefix (e.g. "/assets"); replace the catch logic
to first substitute <port> in assetPrefix and then resolve that value against a
localhost base (e.g. use new URL(prefixWithPort, `http://localhost:${port}`)) so
both relative and absolute prefixes preserve their path when the initial
URL(...) call fails.

@relativeci
Copy link

relativeci bot commented Sep 25, 2025

React Example

#5817 Bundle Size — 237.56KiB (0%).

4ed1eae(current) vs 8983d4c main#5785(baseline)

Bundle metrics  no changes
                 Current
#5817
     Baseline
#5785
No change  Initial JS 0B 0B
No change  Initial CSS 0B 0B
No change  Cache Invalidation 0% 0%
No change  Chunks 0 0
No change  Assets 4 4
No change  Modules 166 166
No change  Duplicate Modules 68 68
No change  Duplicate Code 46.82% 46.82%
No change  Packages 2 2
No change  Duplicate Packages 0 0
Bundle size by type  no changes
                 Current
#5817
     Baseline
#5785
No change  IMG 145.76KiB 145.76KiB
No change  Other 91.8KiB 91.8KiB

Bundle analysis reportBranch PupilTong:p/hw/web-qrcode-urlProject dashboard


Generated by RelativeCIDocumentationReport issue

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (2)

71-73: Type inconsistency in function signature.

The devUrls parameter has type Record<string, string | symbol> but based on the generateDevUrls return type and usage, it should be Record<string, string>. The symbol type appears to be legacy from cancel token handling that's no longer needed.

Apply this diff to align types:

async function loop(
  options: Options,
  value: { lynx: string | symbol | undefined, web: string | undefined },
-  devUrls: { lynx: Record<string, string | symbol>, web: string },
+  devUrls: { lynx: Record<string, string>, web: string },
  currentEntry: string,
) {

157-158: Type casting can be eliminated.

The as string cast on Line 158 is unnecessary since value.lynx is already typed correctly in the function signature, and the cast could hide potential undefined values.

Apply this diff to remove unnecessary casting:

-    await options.onPrint?.(value.lynx as string | undefined, value.web)
-    showQRCode(value.lynx as string, value.web)
+    await options.onPrint?.(value.lynx, value.web)
+    showQRCode(value.lynx, value.web)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d791681 and 44d8fa7.

📒 Files selected for processing (2)
  • packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2 hunks)
  • packages/rspeedy/plugin-qrcode/src/shortcuts.ts (8 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (3)
packages/rspeedy/plugin-qrcode/src/index.ts (1)
  • CustomizedSchemaFn (22-24)
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (1)
  • generateDevUrls (10-70)
packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1)
  • showQRCode (8-17)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: build / Build (Windows)
  • GitHub Check: build / Build (Ubuntu)
  • GitHub Check: test-rust / Test (Ubuntu)
🔇 Additional comments (9)
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (4)

56-63: Fix URL query parameter encoding.

The outputPathname is directly inserted into the query string without URL encoding, which can create malformed URLs when the pathname contains special characters like slashes, spaces, or query delimiters.

When encoding a string to put in a URL component (a querystring parameter), you should call encodeURIComponent.

Apply this diff to encode the query parameter:

  const web = new URL(
-    `/web?casename=${outputPathname}`,
+    `/web?casename=${encodeURIComponent(outputPathname)}`,
    base,
  ).toString()

38-48: Fix relative assetPrefix fallback handling.

When dev.assetPrefix is a relative path (e.g., "/assets"), the catch block's fallback to http://localhost:${port}/ discards the path information. This can break the generated URLs when the application expects assets to be served from a specific path.

Apply this diff to preserve path information:

  let base: string
  try {
    base = new URL(
      '',
      assetPrefix.replaceAll('<port>', String(port)),
    ).toString()
  } catch {
-    base = `http://localhost:${port}/`
+    // Preserve relative or path-only assetPrefix by resolving against localhost
+    base = new URL(
+      assetPrefix.replaceAll('<port>', String(port)),
+      `http://localhost:${port}/`,
+    ).toString()
  }

15-15: LGTM! Return type correctly reflects dual-environment support.

The updated return type { lynx: Record<string, string>, web: string } properly represents the dual-environment structure needed for web platform support.


56-69: Web URL generation logic is sound.

The logic correctly:

  • Computes the web pathname using the same base URL as lynx
  • Constructs a proper web preview URL with the casename parameter
  • Returns the structured object with both lynx and web URLs
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (5)

16-20: Well-structured entries interface for multi-platform support.

The updated entries interface with all, lynx, and web arrays provides clear separation of concerns for different environments while maintaining backward compatibility through the all array.


27-27: Improved onPrint callback signature.

The updated signature (lynx?: string, web?: string) => Promise<void> correctly handles dual URLs and optional parameters, matching the multi-platform architecture.


39-56: Robust entry selection and URL handling.

The logic correctly:

  • Prioritizes lynx entries as the default when available
  • Properly gates URLs based on entry environment support
  • Calls onPrint and showQRCode with appropriate parameters

113-125: Efficient hint generation for entry selection.

The implementation correctly generates hints by computing URLs for each entry option, with proper fallback logic (lynx[currentSchema] ?? web) for display purposes.


170-186: Proper environment gating in getCurrentUrl.

The function correctly:

  • Checks if the current entry is supported in each environment
  • Returns undefined URLs for unsupported environments
  • Prevents displaying inappropriate QR codes (e.g., lynx QR for web-only entries)

Copy link
Collaborator

@colinaaa colinaaa left a comment

Choose a reason for hiding this comment

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

Like I said in https://github.com/lynx-family/lynx-stack/pull/1816/files#r2384891713. This change would make the QRCode too complex. And also would make it REQUIRED for Lynx development.

The QRCode plugin is only made for quickly display the URLs of .lynx.bundle that can be scanned with LynxExplorer. Since we already have a web-dev-middleware, I think we could use it for Web Platform development (and even Lynx development).

Here are some common use cases:

1. Use Rspeedy without qrcode-plugin

On the terminal:

We use server.printUrls to print the URL to the development page (without the ?casename query)

  ➜  Local:    http://localhost:3000/lynx
  ➜  Local:    http://localhost:3000/web
  ➜  Network:  http://<host>:3000/lynx
  ➜  Network:  http://<host>:3000/web

On the web page (http://<host>:<port>/web):

We display URLs for all the entries.
Or we could even create a <lynx-view> for each entry.

On the lynx page (http://<host>:<port>/lynx):

We display QRCode and URLs for all the entires.

2. Use Rspeedy with qrcode-plugin

there is nothing special, only the QRCode for the .lynx.bundle are displayed on the terminal:

●  Scan with Lynx
│
◆ <qrcode>
│
◆  http://10.67.172.118:3000/main2.lynx.bundle?fullscreen=true

  ➜  Local:    http://localhost:3000/lynx
  ➜  Local:    http://localhost:3000/web
  ➜  Network:  http://<host>:3000/lynx
  ➜  Network:  http://<host>:3000/web

◆  Usage
│   r  Switch entries 
│   a  Switch schema 
│   h  Help 
│   q  Quit

What do you think

)

return typeof customSchema === 'string'
const outputPathname = new URL(
Copy link
Collaborator

Choose a reason for hiding this comment

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

We should respect the schemaFn option, even for Web.

]),
]
if (allEntries.length === 0) {
// Not lynx or web environment, skip print
Copy link
Collaborator

Choose a reason for hiding this comment

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

nitpick: the comment does not match the condition.

const value: string | symbol = Object.values(devUrls)[0]!
await options.onPrint?.(value)
showQRCode(value)
const hasLynxEntry = options.entries.lynx.includes(currentEntry)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually, I don't think it's a good idea to have environments mixed-up with entries. It's too complex.

Can we only display the QRCode of Lynx in the terminal, with the http://<host>:<port>/web printed as the entrypoint of the whole Web Platform, on which page display links to each entry.

@PupilTong PupilTong force-pushed the p/hw/web-qrcode-url branch 2 times, most recently from 3eba98d to 81dcb1e Compare October 9, 2025 07:29
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2)

75-75: URL-encode the pathname in the query parameter.

pathname can contain slashes (e.g., /dist/entry.web.bundle), which will break the query string structure. Use encodeURIComponent to properly encode it.

Apply this diff:

-      const url = new URL(`/web?casename=${pathname}`, base).toString()
+      const url = new URL(`/web?casename=${encodeURIComponent(pathname)}`, base).toString()

Based on past review comments.


68-70: Preserve relative assetPrefix path in fallback.

When assetPublicPath is relative (e.g., "/assets"), URL.parse() returns null and the fallback discards the path component, resulting in http://localhost:<port>/ instead of http://localhost:<port>/assets/.

Apply this diff:

-      const base = URL.parse(assetPublicPath)
-        ? assetPublicPath
-        : `http://localhost:${port}/`
+      const base = new URL(
+        assetPublicPath,
+        `http://localhost:${port}/`,
+      ).toString()

Based on past review comments.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 44d8fa7 and 81dcb1e.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (11)
  • .changeset/tricky-lamps-battle.md (1 hunks)
  • examples/react/lynx.config.js (1 hunks)
  • packages/rspeedy/plugin-qrcode/package.json (1 hunks)
  • packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2 hunks)
  • packages/rspeedy/plugin-qrcode/src/index.ts (4 hunks)
  • packages/rspeedy/plugin-qrcode/src/shortcuts.ts (9 hunks)
  • packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1 hunks)
  • packages/rspeedy/plugin-qrcode/test/preview.test.ts (5 hunks)
  • packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts (2 hunks)
  • packages/rspeedy/plugin-qrcode/tsconfig.build.json (1 hunks)
  • packages/rspeedy/plugin-qrcode/tsconfig.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/rspeedy/plugin-qrcode/test/shortcuts.test.ts
  • examples/react/lynx.config.js
  • .changeset/tricky-lamps-battle.md
  • packages/rspeedy/plugin-qrcode/package.json
  • packages/rspeedy/plugin-qrcode/tsconfig.json
  • packages/rspeedy/plugin-qrcode/tsconfig.build.json
🧰 Additional context used
🧬 Code graph analysis (4)
packages/rspeedy/plugin-qrcode/src/index.ts (2)
packages/web-platform/web-rsbuild-server-middleware/src/node/index.ts (1)
  • createWebVirtualFilesMiddleware (22-89)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (1)
  • registerConsoleShortcuts (32-75)
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2)
packages/rspeedy/core/src/index.ts (1)
  • RsbuildPluginAPI (67-67)
packages/rspeedy/plugin-qrcode/src/index.ts (1)
  • CustomizedSchemaFn (22-24)
packages/rspeedy/plugin-qrcode/src/shortcuts.ts (3)
packages/rspeedy/plugin-qrcode/src/index.ts (1)
  • CustomizedSchemaFn (22-24)
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (2)
  • generateExplorerDevUrls (40-58)
  • generateWebDevUrls (60-82)
packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1)
  • showQRCode (8-22)
packages/rspeedy/plugin-qrcode/test/preview.test.ts (1)
packages/rspeedy/plugin-qrcode/src/index.ts (1)
  • pluginQRCode (93-171)
🔇 Additional comments (10)
packages/rspeedy/plugin-qrcode/src/generateDevUrls.ts (1)

60-82: Consider respecting schemaFn for web URLs.

Currently, generateWebDevUrls generates plain URLs without applying schemaFn. This creates an asymmetry with generateExplorerDevUrls which respects custom schemas. Consider whether web URLs should also support custom schema transformation for consistency.

Based on past review comments.

packages/rspeedy/plugin-qrcode/src/showQRCode.ts (1)

8-22: LGTM!

The refactored signature cleanly separates Lynx and web preview concerns, and the conditional rendering logic correctly handles both environments.

packages/rspeedy/plugin-qrcode/src/index.ts (3)

106-110: LGTM!

The middleware registration correctly gates on the presence of the web environment and applies the middleware at the expected path.


147-156: LGTM!

The refactored main function correctly handles both Lynx and web environments, and the early return condition accurately reflects the comment.


13-14: Note: Type resolution issue tracked in past comments.

Past review comments flagged that the import of createWebVirtualFilesMiddleware fails type-checking due to missing exports/types in the source package. This appears to be a package configuration issue outside the scope of this file.

If the type-check failure persists, verify that packages/web-platform/web-rsbuild-server-middleware/package.json properly exports the module and declares types.

Based on past review comments.

packages/rspeedy/plugin-qrcode/test/preview.test.ts (2)

180-213: LGTM!

Test correctly validates behavior when entry is empty with lynx environment present.


215-248: LGTM!

Test correctly validates behavior when lynx environment is absent, ensuring QR code is not rendered.

packages/rspeedy/plugin-qrcode/src/shortcuts.ts (3)

32-74: LGTM!

The initialization logic correctly generates both Lynx explorer URLs and web URLs, and properly invokes onPrint and showQRCode with both parameters.


117-136: LGTM!

Entry-switching logic correctly regenerates explorer URLs for hint display and updates the current value.


137-157: LGTM!

Schema-switching logic correctly regenerates the URL map and updates the current schema/value.

@PupilTong PupilTong force-pushed the p/hw/web-qrcode-url branch from 81dcb1e to 4ed1eae Compare October 9, 2025 07:52
@PupilTong PupilTong requested a review from colinaaa October 9, 2025 08:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: In Progress
Status: Todo

Development

Successfully merging this pull request may close these issues.

2 participants