Skip to content

feat(utoopack): support multiple server entries - #72

Open
fireairforce wants to merge 4 commits into
mainfrom
zoomdong/utoopack-multi-server-entry
Open

feat(utoopack): support multiple server entries#72
fireairforce wants to merge 4 commits into
mainfrom
zoomdong/utoopack-multi-server-entry

Conversation

@fireairforce

@fireairforce fireairforce commented Aug 3, 2026

Copy link
Copy Markdown
Member

Summary

  • upgrade @utoo/pack to 1.5.0
  • forward EVJS server-runtime and page-server BuildPlan entries as named Utoopack server entries
  • map each named entry back to its serverEntryAssets while retaining shared server chunks
  • keep the legacy scalar server runtime entry compatible
  • enable regular server builds; RSC and PPR remain unsupported

Related

Summary by CodeRabbit

  • New Features

    • Added support for production server builds.
    • Added support for multiple server entries, including page-server renderers.
    • Improved handling of shared JavaScript assets across server entries.
  • Bug Fixes

    • Improved server asset selection and validation.
    • Added clearer errors for ambiguous, missing, or unsupported server entries.
    • Preserved page-server renderers after server statistics rebuilds.

@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Utoopack now supports named server-runtime and page-server entries. It resolves their configuration, selects their JavaScript assets, permits shared chunks, advertises production server builds, and validates the behavior with unit and integration tests.

Changes

Utoopack server-entry support

Layer / File(s) Summary
Server entry resolution and validation
packages/bundler-utoopack/package.json, packages/bundler-utoopack/src/adapter/create-config.ts, packages/bundler-utoopack/src/adapter/index.ts, packages/bundler-utoopack/tests/create-config.test.ts
The adapter resolves server-runtime and page-server entries as scalar or ordered named entries. It rejects multiple server-runtime entries and unsupported RSC/PPR entries. Production server build support is enabled.
Server asset selection and inventory
packages/bundler-utoopack/src/manifest-generator.ts, packages/bundler-utoopack/tests/manifest-generator.test.ts
The manifest generator selects one JavaScript asset per server entry, preserves shared assets, and validates owned entry assets.
Adapter rebuild validation
packages/bundler-utoopack/tests/adapter.test.ts
Test mocks generate artifacts for all configured server entries. Rebuild coverage verifies refreshed page-server assets and renderer metadata.
Multi-server integration coverage
packages/bundler-utoopack/tests/multi-server-entry.test.ts
An integration test builds runtime and page-server entries, checks shared chunks and manifest entrypoints, and loads both emitted server outputs.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BuildPlan
  participant UtoopackAdapter
  participant ManifestGenerator
  participant EmittedServerEntries
  BuildPlan->>UtoopackAdapter: provide server-runtime and page-server entries
  UtoopackAdapter->>UtoopackAdapter: resolve ordered named server entries
  UtoopackAdapter->>ManifestGenerator: provide server entry configuration and stats
  ManifestGenerator->>ManifestGenerator: select one JavaScript asset per entry
  ManifestGenerator->>EmittedServerEntries: emit mapped entries and shared assets
Loading

Possibly related PRs

  • afx-team/evjs#32: Extends the manifest and build-output contract changes used by the Utoopack adapter.
  • afx-team/evjs#41: Introduces framework-generated server and page-server entries consumed by this adapter.
  • afx-team/evjs#64: Overlaps with the Utoopack server-entry and manifest-generation changes.

Suggested reviewers: xusd320

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ 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%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: support for multiple Utoopack server entries.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch zoomdong/utoopack-multi-server-entry

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.

@fireairforce
fireairforce marked this pull request as ready for review August 3, 2026 07:57
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 478581979e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/bundler-utoopack/src/adapter/create-config.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
packages/bundler-utoopack/src/manifest-generator.ts (1)

326-338: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

The single-asset short-circuit accepts an asset that does not belong to the entry.

If an entrypoint lists exactly one JavaScript asset, selectServerJavaScriptAsset returns it without any name check. If Utoopack emits only a shared chunk for that entrypoint, the generator maps the planned entry to the shared chunk and the manifest points renderers at the wrong file. Every other path in this function requires a name match.

Check the name first, then fall back to the sole asset. The behavior stays the same for the common case and rejects an obvious mismatch.

♻️ Proposed refactor: prefer the named candidate
 function selectServerJavaScriptAsset(
   entryName: string,
   assets: AssetGroup,
 ): string {
-  if (assets.js.length === 1) return assets.js[0] as string;
   const candidates = assets.js.filter((asset) =>
     isNamedEntryAsset(entryName, asset),
   );
   if (candidates.length === 1) return candidates[0] as string;
+  if (candidates.length === 0 && assets.js.length === 1) {
+    return assets.js[0] as string;
+  }
   throw new Error(
     `[evjs] Utoopack server stats entrypoint "${entryName}" must identify exactly one JavaScript entry asset; found ${assets.js.length} JavaScript assets and ${candidates.length} named candidates.`,
   );
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/bundler-utoopack/src/manifest-generator.ts` around lines 326 - 338,
Update selectServerJavaScriptAsset to validate the asset name before accepting a
single JavaScript asset: prefer the uniquely named candidate, and only fall back
to the sole asset when it matches the entry name. Preserve the existing error
behavior when neither condition is satisfied.
packages/bundler-utoopack/tests/multi-server-entry.test.ts (1)

85-99: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

require runs the built modules and each fixture calls console.log at import time.

Every emitted entry logs during the test. Remove the console.log calls from the fixtures, or export a value and assert on it. The load check then stays meaningful without extra test output.

♻️ Proposed refactor: export instead of log
     fs.promises.writeFile(
       path.join(sourceDir, "server.ts"),
-      'import { sharedPrimary } from "./shared-primary";\nconsole.log("server", sharedPrimary);\n',
+      'import { sharedPrimary } from "./shared-primary";\nexport const serverEntry = sharedPrimary;\n',
     ),

Apply the same change to dashboard.server.ts and detail.server.ts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/bundler-utoopack/tests/multi-server-entry.test.ts` around lines 85 -
99, Remove the import-time console.log calls from the dashboard.server.ts and
detail.server.ts fixtures, replacing them with exported values if needed. Keep
the require-based checks in the multi-server entry test unchanged so they verify
each emitted entry loads without producing test output.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/bundler-utoopack/src/adapter/create-config.ts`:
- Around line 259-289: Snapshot the framework-owned server entry defensively
before configureBundler hooks run, preserving array contents rather than sharing
the same reference. Update createUtoopackConfig to pass this expectedServerEntry
snapshot to every assertUtoopackServerEntryMatchesPlan call, so in-place
push/splice mutations are detected while existing scalar and array comparisons
remain unchanged.

In `@packages/bundler-utoopack/tests/adapter.test.ts`:
- Around line 1042-1045: Update the vi.waitFor assertion around onBuildOutput
and onServerBundleReady to use an explicit timeout longer than the 500 ms stats
polling delay, ensuring the expectation remains reliable on slower environments.

In `@packages/bundler-utoopack/tests/multi-server-entry.test.ts`:
- Around line 76-84: Update the sharedAssets assertion in the multi-server entry
test to avoid matching the unstable or incorrect “server-shared” filename
pattern. Assert a stable invariant instead, preferably identifying an emitted
asset referenced by more than one server entrypoint, or use a documented
entry-independent asset name if one exists.

---

Nitpick comments:
In `@packages/bundler-utoopack/src/manifest-generator.ts`:
- Around line 326-338: Update selectServerJavaScriptAsset to validate the asset
name before accepting a single JavaScript asset: prefer the uniquely named
candidate, and only fall back to the sole asset when it matches the entry name.
Preserve the existing error behavior when neither condition is satisfied.

In `@packages/bundler-utoopack/tests/multi-server-entry.test.ts`:
- Around line 85-99: Remove the import-time console.log calls from the
dashboard.server.ts and detail.server.ts fixtures, replacing them with exported
values if needed. Keep the require-based checks in the multi-server entry test
unchanged so they verify each emitted entry loads without producing test output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: b4052420-c62f-4f3a-8254-31c13ecd0ae1

📥 Commits

Reviewing files that changed from the base of the PR and between 80ca26d and 4785819.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (8)
  • packages/bundler-utoopack/package.json
  • packages/bundler-utoopack/src/adapter/create-config.ts
  • packages/bundler-utoopack/src/adapter/index.ts
  • packages/bundler-utoopack/src/manifest-generator.ts
  • packages/bundler-utoopack/tests/adapter.test.ts
  • packages/bundler-utoopack/tests/create-config.test.ts
  • packages/bundler-utoopack/tests/manifest-generator.test.ts
  • packages/bundler-utoopack/tests/multi-server-entry.test.ts

Comment thread packages/bundler-utoopack/src/adapter/create-config.ts
Comment thread packages/bundler-utoopack/tests/adapter.test.ts Outdated
Comment thread packages/bundler-utoopack/tests/multi-server-entry.test.ts Outdated
@fireairforce
fireairforce force-pushed the zoomdong/utoopack-multi-server-entry branch from a0575ba to c8f1ee6 Compare August 3, 2026 09:48

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/bundler-utoopack/tests/multi-server-entry.test.ts (1)

70-106: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert selected entry assets and shared inventory in the integration test.

The test checks fact keys, shared files in stats, and module loadability. A regression that maps a page-server entry to server.js, or removes a shared chunk from facts.emittedFiles.server, can still pass. Assert that each selected asset belongs only to its named stats entrypoint and that emitted server files contain sharedAssets.

Verify the entry-asset uniqueness invariant against the actual @utoo/pack 1.5.0 stats for this fixture.

Proposed test update
-    expect(Object.keys(facts.serverEntryAssets ?? {}).sort()).toEqual([
+    const serverEntryAssets = facts.serverEntryAssets ?? {};
+    expect(Object.keys(serverEntryAssets).sort()).toEqual([
       "page-server-dashboard",
       "page-server-detail",
       "server",
     ]);
@@
     const sharedAssets = [...assetReferenceCounts]
       .filter(([, references]) => references > 1)
       .map(([asset]) => asset);
     expect(sharedAssets.length).toBeGreaterThan(0);
+    for (const [name, entry] of Object.entries(serverEntryAssets)) {
+      const [entryAsset] = entry.js;
+      if (!entryAsset) throw new Error(`Expected JavaScript asset for ${name}.`);
+      const statsEntrypoint = stats.entrypoints[name];
+      if (!statsEntrypoint) throw new Error(`Expected stats entrypoint for ${name}.`);
+      expect(
+        statsEntrypoint.assets.map((asset) =>
+          asset.name.replace(/^\.\//, ""),
+        ),
+      ).toContain(entryAsset);
+      expect(assetReferenceCounts.get(entryAsset)).toBe(1);
+    }
+    expect(facts.emittedFiles?.server).toEqual(
+      expect.arrayContaining(sharedAssets),
+    );
     await expect(
       Promise.all(
         sharedAssets.map((asset) =>
@@
-    for (const entry of Object.values(facts.serverEntryAssets ?? {})) {
+    for (const entry of Object.values(serverEntryAssets)) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/bundler-utoopack/tests/multi-server-entry.test.ts` around lines 70 -
106, Strengthen the integration assertions around facts.serverEntryAssets and
stats.entrypoints: for each named server entry, assert its selected asset
belongs to that entrypoint and is not associated with any other entrypoint,
preserving the actual `@utoo/pack` 1.5.0 fixture behavior. Also assert every asset
in sharedAssets is present in facts.emittedFiles.server, in addition to the
existing filesystem and loadability checks.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/bundler-utoopack/tests/multi-server-entry.test.ts`:
- Around line 70-106: Strengthen the integration assertions around
facts.serverEntryAssets and stats.entrypoints: for each named server entry,
assert its selected asset belongs to that entrypoint and is not associated with
any other entrypoint, preserving the actual `@utoo/pack` 1.5.0 fixture behavior.
Also assert every asset in sharedAssets is present in facts.emittedFiles.server,
in addition to the existing filesystem and loadability checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c4e05ac0-4e36-4559-8626-22e5a2b69351

📥 Commits

Reviewing files that changed from the base of the PR and between 4785819 and f47b2d8.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (8)
  • packages/bundler-utoopack/package.json
  • packages/bundler-utoopack/src/adapter/create-config.ts
  • packages/bundler-utoopack/src/adapter/index.ts
  • packages/bundler-utoopack/src/manifest-generator.ts
  • packages/bundler-utoopack/tests/adapter.test.ts
  • packages/bundler-utoopack/tests/create-config.test.ts
  • packages/bundler-utoopack/tests/manifest-generator.test.ts
  • packages/bundler-utoopack/tests/multi-server-entry.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/bundler-utoopack/src/adapter/index.ts
  • packages/bundler-utoopack/src/manifest-generator.ts
  • packages/bundler-utoopack/package.json

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant