Add Serinus deployment guidance and Inertia frontend skill#3
Add Serinus deployment guidance and Inertia frontend skill#3kingwill101 wants to merge 3 commits into
Conversation
📝 WalkthroughWalkthroughThis PR adds production-ready deployment infrastructure for a Serinus Inertia example project. It introduces Docker containerization (multi-stage Dockerfiles for client and SSR builds), Docker Compose orchestration with health checks, comprehensive deployment documentation, static asset serving with caching, and extensive skill documentation for building Inertia Dart frontends with multiple server integrations. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (5)
packages/serinus_inertia/example/client/vite.config.js (1)
15-17: Consider aligning with theInertiaAssetsOptions.entry.
rollupOptions.input: 'src/main.jsx'duplicates the entry declared inapp_module.dart(InertiaAssetsOptions(entry: 'src/main.jsx', ...)). If one side changes (e.g., tosrc/ssr.jsxor a different entry) the other can silently get out of sync and break manifest lookups. Not a blocker, but worth a brief comment linking the two, or parameterizing via an env var in a follow-up.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/serinus_inertia/example/client/vite.config.js` around lines 15 - 17, The rollupOptions.input in vite.config.js duplicates the entry declared in InertiaAssetsOptions(entry: 'src/main.jsx') and can drift out of sync; update vite.config.js to derive input from a single source (e.g., read an env var like VITE_ENTRY or import a shared constant) or at minimum add a clear comment linking it to InertiaAssetsOptions(entry: ...) so maintainers know they must change both; reference rollupOptions.input and InertiaAssetsOptions(entry: ...) when making the change.packages/serinus_inertia/example/Dockerfile.client (1)
3-19: Both build stagesCOPY . .the entire repo — consider scoping.Each build stage copies the full monorepo before narrowing to
packages/serinus_inertia/example. This invalidates the Docker layer cache on any unrelated file change and inflates build context. Sinceserinus_inertiadepends on the siblinginertiapackage viapath:override, the copy can't be trivially reduced to one directory, but you can at least split the copies sonpm ci/dart pub getlayers cache on manifest files first.♻️ Suggested cache-friendlier ordering (client stage)
FROM node:24-bookworm-slim AS client-build WORKDIR /workspace -COPY . . - -WORKDIR /workspace/packages/serinus_inertia/example/client -RUN npm ci -RUN npm run build +COPY packages/serinus_inertia/example/client/package.json packages/serinus_inertia/example/client/package-lock.json ./packages/serinus_inertia/example/client/ +WORKDIR /workspace/packages/serinus_inertia/example/client +RUN npm ci +WORKDIR /workspace +COPY . . +WORKDIR /workspace/packages/serinus_inertia/example/client +RUN npm run buildFeel free to defer; purely a build-time optimization.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/serinus_inertia/example/Dockerfile.client` around lines 3 - 19, The Dockerfile uses COPY . . in both client-build and server-build stages which copies the whole monorepo and busts caches; change each stage to first copy only manifest files needed for dependency installation (e.g., package.json, package-lock.json for the client stage used before RUN npm ci and pubspec.* files for the server stage used before RUN dart pub get) then run the install steps (npm ci / dart pub get) and finally COPY the rest of the workspace before RUN npm run build and dart compile in the client-build and server-build stages respectively; update the client-build and server-build stages to reference these staged copies so npm ci and dart pub get layers cache properly while still including the sibling package source before the final build commands.packages/serinus_inertia/example/lib/app_module.dart (1)
22-38: Minor: env-driven SSR resolver ignoresSERINUS_INERTIA_SSR_RUNTIME/SERINUS_INERTIA_SSR_BUNDLEwhen an endpoint is also set.If a user sets both
SERINUS_INERTIA_SSR_ENDPOINTand the managed-process vars, the endpoint silently wins and the managed-process vars are discarded with no warning. That's a defensible precedence rule, but consider documenting it in the deploy guide (or logging a hint) so misconfigured environments aren't confusing to debug.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/serinus_inertia/example/lib/app_module.dart` around lines 22 - 38, The env-driven SSR resolver currently returns the endpoint silently when SERINUS_INERTIA_SSR_ENDPOINT is set, discarding SERINUS_INERTIA_SSR_RUNTIME and SERINUS_INERTIA_SSR_BUNDLE; update _resolveSsrOptions to detect when endpoint != null and either SERINUS_INERTIA_SSR_RUNTIME or SERINUS_INERTIA_SSR_BUNDLE are also set and emit a clear warning that the endpoint takes precedence (use the existing logging facility, e.g., processLogger.warn or a print fallback), so users see the precedence; also add a short note to the deploy docs explaining this precedence rule.skills/inertia-dart-frontend/references/client-patterns.md (1)
53-58: Make component-path examples adapter-agnostic.These examples currently imply React-only extensions in a shared multi-adapter guide. Consider using
.*or showing one example per adapter to avoid confusion.🧩 Suggested example tweak
-- `component: 'Home'` -> `client/src/Pages/Home.jsx` -- `component: 'Users/Index'` -> `client/src/Pages/Users/Index.jsx` +- `component: 'Home'` -> `client/src/Pages/Home.*` (e.g., `.jsx`, `.vue`, `.svelte`) +- `component: 'Users/Index'` -> `client/src/Pages/Users/Index.*`🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/inertia-dart-frontend/references/client-patterns.md` around lines 53 - 58, The examples for the Dart-side `component` path currently hardcode a React extension (`.jsx`) and should be adapter-agnostic: update the two sample lines that map `component` to `client/src/Pages/...` (the examples referencing `component: 'Home'` and `component: 'Users/Index'`) to either use a generic extension wildcard (e.g., `.*`) or show one example per adapter (e.g., `.jsx` for React, `.dart` for Dart, etc.), so the documentation for `component` clearly indicates the file path without implying a single frontend adapter.skills/inertia-dart-frontend/SKILL.md (1)
45-48: Reduce repeated imperative openings in list items.The repeated “Use …” / “Read …” pattern in adjacent bullets is a small readability drag; varying phrasing would improve scan speed without changing meaning.
Also applies to: 61-66
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@skills/inertia-dart-frontend/SKILL.md` around lines 45 - 48, The adjacent bullet list repeatedly starts lines with "Use …" which reduces readability; revise the bullets mentioning LazyProp, OptionalProp, DeferredProp, MergeProp, ScrollProp, and OnceProp to vary phrasing (e.g., "Prefer LazyProp/OptionalProp…", "Reserve DeferredProp…", "Apply MergeProp/ScrollProp…", "Choose OnceProp…") and make the same phrasing adjustments for the similar block at 61-66 to remove repetitive openings while preserving meanings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/serinus_inertia/example/client/package.json`:
- Around line 8-10: The SSR preload manifest is being generated in the SSR
build; update the npm scripts so the SSR manifest is produced during the client
build instead: remove the --manifest ssr-manifest.json flag from the "build:ssr"
script and add the --ssrManifest ssr-manifest.json flag to the "build:client"
script (or alternatively set build.ssrManifest in Vite config); adjust the
"build" script unchanged to run "build:client" then "build:ssr". This targets
the scripts named build:client and build:ssr.
In `@packages/serinus_inertia/example/DEPLOY.md`:
- Around line 398-402: The bullets in DEPLOY.md repeat the same lead phrasing
making them hard to scan; update the five checks to vary the sentence starters
while keeping the same verification items (references: client/public/hot,
client/dist/assets, nginx/Caddy proxy root -> client/dist,
client/dist/.vite/manifest.json, client/dist/ssr.js and /render). For example,
change each bullet to start differently (e.g., "Remove...", "Verify...", "Ensure
your proxy root...", "Confirm the manifest...", "When SSR is enabled, check...")
so each line is concise, action-oriented, and still instructs the same checks
without altering the file paths or intent.
In `@packages/serinus_inertia/example/Dockerfile.client`:
- Around line 21-33: The runtime Dockerfile app stage currently runs as root;
add a non-root user and switch to it before CMD to satisfy Trivy DS-0002. In the
final stage (labels: FROM debian:bookworm-slim AS app, WORKDIR
/opt/serinus-inertia, EXPOSE 4000, CMD ["./server"]) create a dedicated
user/group (e.g., uid/gid 1000), chown the application directories
(/opt/serinus-inertia, ./server, ./client/dist) to that user, use USER to switch
to the non-root user, and ensure the server binary has execute permission so CMD
["./server"] runs as the non-root user.
In `@packages/serinus_inertia/example/Dockerfile.ssr`:
- Around line 21-48: The final image stages (app and ssr) run as root; update
both stages (the "app" stage and the "ssr" stage) to create a non-root
user/group (e.g., uid/gid 1000), chown the application directories and copied
artifacts (the server binary at ./server and the client dist at ./client/dist or
./dist), and add USER to switch to that non-root account before EXPOSE/CMD so
the app listens on ports 4000 and 13714 unprivileged; ensure files are
executable and owned by the new user after the COPY steps and before switching
USER.
In `@packages/serinus_inertia/example/lib/asset_controller.dart`:
- Around line 20-28: The code currently uses synchronous filesystem calls
(assetFile.existsSync(), assetFile.statSync(), assetFile.lengthSync()) in the
request path; replace them with a single asynchronous stat call: call await
assetFile.stat(), check the returned FileStat.type equals
FileSystemEntityType.file (throw NotFoundException('Asset not found') if not),
then reuse FileStat.size to set context.res.contentLength and keep setting
context.res.contentType as before (using lookupMimeType on assetFile.path).
Update any surrounding function to be async if needed so you can await
assetFile.stat().
- Around line 14-19: The _containsUnsafeSegments check currently only splits
relativePath on '/' so backslashes can hide traversal; update
_containsUnsafeSegments to split the incoming relativePath on both '/' and '\'
(treat both as separators), reject any empty segments, and then check each
segment for '.' or '..' (or any other unsafe token) to return true; ensure the
code that reads context.params['**'] (relativePath) still uses this updated
helper before constructing File('client/dist/assets/$relativePath') so
Windows-style separators cannot bypass the validation.
In `@skills/inertia-dart-frontend/references/dart-io.md`:
- Around line 21-28: Add the Inertia asset-version conflict check before
building a normal page response: when handling an Inertia request
(inertiaRequest.isInertia), compare the request version (inertiaRequest.version)
to the current app asset version (the same check logic used in
RoutedInertiaMiddleware), and if they differ return an HTTP 409 with an
X-Inertia-Location header pointing to the current location instead of calling
InertiaResponseFactory().buildPageDataAsync(...) or
renderInertiaBootstrap(page); ensure this early-return happens immediately after
inertiaRequestFromHttp(request) / inertiaRequest.createContext() and before any
page construction or JSON/html rendering.
---
Nitpick comments:
In `@packages/serinus_inertia/example/client/vite.config.js`:
- Around line 15-17: The rollupOptions.input in vite.config.js duplicates the
entry declared in InertiaAssetsOptions(entry: 'src/main.jsx') and can drift out
of sync; update vite.config.js to derive input from a single source (e.g., read
an env var like VITE_ENTRY or import a shared constant) or at minimum add a
clear comment linking it to InertiaAssetsOptions(entry: ...) so maintainers know
they must change both; reference rollupOptions.input and
InertiaAssetsOptions(entry: ...) when making the change.
In `@packages/serinus_inertia/example/Dockerfile.client`:
- Around line 3-19: The Dockerfile uses COPY . . in both client-build and
server-build stages which copies the whole monorepo and busts caches; change
each stage to first copy only manifest files needed for dependency installation
(e.g., package.json, package-lock.json for the client stage used before RUN npm
ci and pubspec.* files for the server stage used before RUN dart pub get) then
run the install steps (npm ci / dart pub get) and finally COPY the rest of the
workspace before RUN npm run build and dart compile in the client-build and
server-build stages respectively; update the client-build and server-build
stages to reference these staged copies so npm ci and dart pub get layers cache
properly while still including the sibling package source before the final build
commands.
In `@packages/serinus_inertia/example/lib/app_module.dart`:
- Around line 22-38: The env-driven SSR resolver currently returns the endpoint
silently when SERINUS_INERTIA_SSR_ENDPOINT is set, discarding
SERINUS_INERTIA_SSR_RUNTIME and SERINUS_INERTIA_SSR_BUNDLE; update
_resolveSsrOptions to detect when endpoint != null and either
SERINUS_INERTIA_SSR_RUNTIME or SERINUS_INERTIA_SSR_BUNDLE are also set and emit
a clear warning that the endpoint takes precedence (use the existing logging
facility, e.g., processLogger.warn or a print fallback), so users see the
precedence; also add a short note to the deploy docs explaining this precedence
rule.
In `@skills/inertia-dart-frontend/references/client-patterns.md`:
- Around line 53-58: The examples for the Dart-side `component` path currently
hardcode a React extension (`.jsx`) and should be adapter-agnostic: update the
two sample lines that map `component` to `client/src/Pages/...` (the examples
referencing `component: 'Home'` and `component: 'Users/Index'`) to either use a
generic extension wildcard (e.g., `.*`) or show one example per adapter (e.g.,
`.jsx` for React, `.dart` for Dart, etc.), so the documentation for `component`
clearly indicates the file path without implying a single frontend adapter.
In `@skills/inertia-dart-frontend/SKILL.md`:
- Around line 45-48: The adjacent bullet list repeatedly starts lines with "Use
…" which reduces readability; revise the bullets mentioning LazyProp,
OptionalProp, DeferredProp, MergeProp, ScrollProp, and OnceProp to vary phrasing
(e.g., "Prefer LazyProp/OptionalProp…", "Reserve DeferredProp…", "Apply
MergeProp/ScrollProp…", "Choose OnceProp…") and make the same phrasing
adjustments for the similar block at 61-66 to remove repetitive openings while
preserving meanings.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 3fe1a07d-6995-4c02-a838-208319f9bebd
📒 Files selected for processing (19)
.dockerignorepackages/serinus_inertia/example/DEPLOY.mdpackages/serinus_inertia/example/Dockerfile.clientpackages/serinus_inertia/example/Dockerfile.ssrpackages/serinus_inertia/example/README.mdpackages/serinus_inertia/example/client/package.jsonpackages/serinus_inertia/example/client/vite.config.jspackages/serinus_inertia/example/compose.yamlpackages/serinus_inertia/example/lib/app_module.dartpackages/serinus_inertia/example/lib/asset_controller.dartpackages/serinus_inertia/example/pubspec.yamlskills/inertia-dart-frontend/SKILL.mdskills/inertia-dart-frontend/agents/openai.yamlskills/inertia-dart-frontend/references/client-patterns.mdskills/inertia-dart-frontend/references/dart-io.mdskills/inertia-dart-frontend/references/deployment.mdskills/inertia-dart-frontend/references/docker.mdskills/inertia-dart-frontend/references/routed.mdskills/inertia-dart-frontend/references/serinus.md
| "build:client": "node -e \"const fs=require('node:fs'); try { fs.unlinkSync('public/hot') } catch {}\" && vite build", | ||
| "build": "npm run build:client && npm run build:ssr", | ||
| "build:ssr": "vite build --ssr src/ssr.jsx --emptyOutDir false --manifest ssr-manifest.json", |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Vite 7 official docs vite build --ssrManifest build.ssrManifest SSR manifest client build
💡 Result:
In Vite (including version 7), the vite build --ssrManifest build.ssrManifest command generates an SSR manifest file during the client build for use in server-side rendering (SSR) setups. This maps module IDs (collected during SSR rendering) to their corresponding client-side chunks and assets, enabling preload directives (), style links, and 103 Early Hints in production SSR servers. ## Usage Run on the client build (not SSR build): "build:client": "vite build --outDir dist/client --ssrManifest build.ssrManifest" - Generates dist/client/build.ssrManifest (custom filename via argument; default: .vite/ssr-manifest.json). - The SSR manifest is created from the client build because it maps SSR-used module IDs to client files. ## Config Alternative In vite.config.js: js export default defineConfig({ build: { ssrManifest: 'build.ssrManifest' // Path relative to build.outDir } }) - Type: boolean | string (default: false). - When true: .vite/ssr-manifest.json. ## In SSR Server 1. Read the manifest: const ssrManifest = JSON.parse(await fs.readFile('dist/client/build.ssrManifest', 'utf-8')). 2. During SSR render, collect used module IDs (framework-specific, e.g., @vitejs/plugin-vue populates ctx.modules). 3. Use manifest to generate preloads: js // Pseudo-code for (const id of ctx.modules) { const files = ssrManifest[id]; if (files) { for (const file of files) { if (file.endsWith('.js')) { html += ; } else if (file.endsWith('.css')) { html += ; } } } } ## Vite 7 Status - Fully supported (released June 2025); no breaking changes to SSR manifest in Vite 7 changelogs. - Vite 8 (beta as of 2026-02) uses Rolldown; minor manifest adjustments (e.g., CSS assets) but core SSR manifest unchanged. ## Example package.json Scripts { "scripts": { "build:client": "vite build --outDir dist/client --ssrManifest build.ssrManifest", "build:ssr": "vite build --outDir dist/server --ssr src/entry-server.js" } } See official docs: SSR Guide, Build Options.
Citations:
- 1: https://v7.vite.dev/guide/ssr
- 2: https://vite.dev/guide/ssr
- 3: https://vite.dev/config/build-options
- 4: https://github.com/vitejs/vite/blob/v7.0.1/packages/vite/CHANGELOG.md
- 5: https://github.com/vitejs/vite/blob/v7.1.0/packages/vite/CHANGELOG.md
- 6: https://github.com/vitejs/vite/blob/v7.0.0/packages/vite/CHANGELOG.md
🏁 Script executed:
# Check the actual package.json file
cat -n packages/serinus_inertia/example/client/package.jsonRepository: avesbox/inertia_dart
Length of output: 1185
🏁 Script executed:
# Look for Vite configuration files
fd -e js -e ts -e json --basename 'vite.config.*' packages/serinus_inertia/example/Repository: avesbox/inertia_dart
Length of output: 326
🏁 Script executed:
# Check if there's a root vite.config
fd -e js -e ts -e json --basename 'vite.config.*' packages/serinus_inertia/Repository: avesbox/inertia_dart
Length of output: 326
🏁 Script executed:
# Find vite config files using proper fd syntax
fd -e js -e ts 'vite\.config' packages/serinus_inertia/example/Repository: avesbox/inertia_dart
Length of output: 118
🏁 Script executed:
# Also check parent directories
fd -e js -e ts 'vite\.config' packages/serinus_inertia/Repository: avesbox/inertia_dart
Length of output: 118
🏁 Script executed:
# Check the vite.config.js contents
cat -n packages/serinus_inertia/example/client/vite.config.jsRepository: avesbox/inertia_dart
Length of output: 595
🏁 Script executed:
# Also check if there's an SSR entry file
cat -n packages/serinus_inertia/example/client/src/ssr.jsxRepository: avesbox/inertia_dart
Length of output: 622
Move SSR manifest generation to the client build.
The --manifest ssr-manifest.json flag on the SSR build creates a regular build manifest, not Vite's SSR preload manifest. Per Vite 7 documentation, --ssrManifest (or build.ssrManifest in config) must run on the client build, since it maps SSR-used module IDs to client-side chunks for preload directives. Reference: https://vite.dev/guide/ssr#generating-preload-directives and https://vite.dev/config/build-options.html#build-ssrmanifest
Proposed fix
- "build:client": "node -e \"const fs=require('node:fs'); try { fs.unlinkSync('public/hot') } catch {}\" && vite build",
+ "build:client": "node -e \"const fs=require('node:fs'); try { fs.unlinkSync('public/hot') } catch {}\" && vite build --ssrManifest ssr-manifest.json",
"build": "npm run build:client && npm run build:ssr",
- "build:ssr": "vite build --ssr src/ssr.jsx --emptyOutDir false --manifest ssr-manifest.json",
+ "build:ssr": "vite build --ssr src/ssr.jsx --emptyOutDir false",📝 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.
| "build:client": "node -e \"const fs=require('node:fs'); try { fs.unlinkSync('public/hot') } catch {}\" && vite build", | |
| "build": "npm run build:client && npm run build:ssr", | |
| "build:ssr": "vite build --ssr src/ssr.jsx --emptyOutDir false --manifest ssr-manifest.json", | |
| "build:client": "node -e \"const fs=require('node:fs'); try { fs.unlinkSync('public/hot') } catch {}\" && vite build --ssrManifest ssr-manifest.json", | |
| "build": "npm run build:client && npm run build:ssr", | |
| "build:ssr": "vite build --ssr src/ssr.jsx --emptyOutDir false", |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/serinus_inertia/example/client/package.json` around lines 8 - 10,
The SSR preload manifest is being generated in the SSR build; update the npm
scripts so the SSR manifest is produced during the client build instead: remove
the --manifest ssr-manifest.json flag from the "build:ssr" script and add the
--ssrManifest ssr-manifest.json flag to the "build:client" script (or
alternatively set build.ssrManifest in Vite config); adjust the "build" script
unchanged to run "build:client" then "build:ssr". This targets the scripts named
build:client and build:ssr.
| - If the app tries to load assets from a Vite dev server, remove `client/public/hot`. | ||
| - If assets 404, confirm the working directory contains `client/dist/assets`. | ||
| - If assets 404 behind nginx or Caddy, confirm the proxy root points to `client/dist`, not the deployment root. | ||
| - If first visits fail, confirm `client/dist/.vite/manifest.json` exists. | ||
| - If SSR is enabled, confirm `client/dist/ssr.js` exists and the renderer is reachable on `/render`. |
There was a problem hiding this comment.
Tighten troubleshooting bullet phrasing for scanability.
These consecutive bullets repeat the same sentence opener, which makes the section harder to scan quickly during incidents. Consider varying the lead phrasing while keeping the checks intact.
✏️ Suggested wording cleanup
-- If the app tries to load assets from a Vite dev server, remove `client/public/hot`.
-- If assets 404, confirm the working directory contains `client/dist/assets`.
-- If assets 404 behind nginx or Caddy, confirm the proxy root points to `client/dist`, not the deployment root.
-- If first visits fail, confirm `client/dist/.vite/manifest.json` exists.
-- If SSR is enabled, confirm `client/dist/ssr.js` exists and the renderer is reachable on `/render`.
+- App loading from a Vite dev server in production usually means `client/public/hot` still exists; remove it.
+- For direct-serving 404s, verify the process working directory contains `client/dist/assets`.
+- For proxy-only 404s, verify nginx/Caddy points at `client/dist` (not the deployment root).
+- First-visit failures often indicate a missing `client/dist/.vite/manifest.json`.
+- With SSR enabled, verify `client/dist/ssr.js` exists and `/render` is reachable.🧰 Tools
🪛 LanguageTool
[style] ~400-~400: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ectory contains client/dist/assets. - If assets 404 behind nginx or Caddy, confi...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~401-~401: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...lient/dist, not the deployment root. - If first visits fail, confirm client/dist...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~402-~402: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ent/dist/.vite/manifest.jsonexists. - If SSR is enabled, confirmclient/dist/ss...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/serinus_inertia/example/DEPLOY.md` around lines 398 - 402, The
bullets in DEPLOY.md repeat the same lead phrasing making them hard to scan;
update the five checks to vary the sentence starters while keeping the same
verification items (references: client/public/hot, client/dist/assets,
nginx/Caddy proxy root -> client/dist, client/dist/.vite/manifest.json,
client/dist/ssr.js and /render). For example, change each bullet to start
differently (e.g., "Remove...", "Verify...", "Ensure your proxy root...",
"Confirm the manifest...", "When SSR is enabled, check...") so each line is
concise, action-oriented, and still instructs the same checks without altering
the file paths or intent.
| FROM debian:bookworm-slim AS app | ||
| WORKDIR /opt/serinus-inertia | ||
|
|
||
| RUN apt-get update \ | ||
| && apt-get install -y --no-install-recommends ca-certificates \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| COPY --from=server-build /workspace/packages/serinus_inertia/example/build/server ./server | ||
| COPY --from=client-build /workspace/packages/serinus_inertia/example/client/dist ./client/dist | ||
|
|
||
| EXPOSE 4000 | ||
|
|
||
| CMD ["./server"] |
There was a problem hiding this comment.
Run the runtime container as a non-root user.
The final app stage runs as root by default, which Trivy flags (DS-0002) and is not needed for serving assets and listening on port 4000. Add a dedicated non-root user in the runtime stage.
🛡️ Proposed hardening
FROM debian:bookworm-slim AS app
WORKDIR /opt/serinus-inertia
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates \
- && rm -rf /var/lib/apt/lists/*
+ && rm -rf /var/lib/apt/lists/* \
+ && groupadd --system --gid 1001 app \
+ && useradd --system --uid 1001 --gid app --home /opt/serinus-inertia app
-COPY --from=server-build /workspace/packages/serinus_inertia/example/build/server ./server
-COPY --from=client-build /workspace/packages/serinus_inertia/example/client/dist ./client/dist
+COPY --from=server-build --chown=app:app /workspace/packages/serinus_inertia/example/build/server ./server
+COPY --from=client-build --chown=app:app /workspace/packages/serinus_inertia/example/client/dist ./client/dist
+USER app
EXPOSE 4000
CMD ["./server"]📝 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.
| FROM debian:bookworm-slim AS app | |
| WORKDIR /opt/serinus-inertia | |
| RUN apt-get update \ | |
| && apt-get install -y --no-install-recommends ca-certificates \ | |
| && rm -rf /var/lib/apt/lists/* | |
| COPY --from=server-build /workspace/packages/serinus_inertia/example/build/server ./server | |
| COPY --from=client-build /workspace/packages/serinus_inertia/example/client/dist ./client/dist | |
| EXPOSE 4000 | |
| CMD ["./server"] | |
| FROM debian:bookworm-slim AS app | |
| WORKDIR /opt/serinus-inertia | |
| RUN apt-get update \ | |
| && apt-get install -y --no-install-recommends ca-certificates \ | |
| && rm -rf /var/lib/apt/lists/* \ | |
| && groupadd --system --gid 1001 app \ | |
| && useradd --system --uid 1001 --gid app --home /opt/serinus-inertia app | |
| COPY --from=server-build --chown=app:app /workspace/packages/serinus_inertia/example/build/server ./server | |
| COPY --from=client-build --chown=app:app /workspace/packages/serinus_inertia/example/client/dist ./client/dist | |
| USER app | |
| EXPOSE 4000 | |
| CMD ["./server"] |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/serinus_inertia/example/Dockerfile.client` around lines 21 - 33, The
runtime Dockerfile app stage currently runs as root; add a non-root user and
switch to it before CMD to satisfy Trivy DS-0002. In the final stage (labels:
FROM debian:bookworm-slim AS app, WORKDIR /opt/serinus-inertia, EXPOSE 4000, CMD
["./server"]) create a dedicated user/group (e.g., uid/gid 1000), chown the
application directories (/opt/serinus-inertia, ./server, ./client/dist) to that
user, use USER to switch to the non-root user, and ensure the server binary has
execute permission so CMD ["./server"] runs as the non-root user.
| FROM debian:bookworm-slim AS app | ||
| WORKDIR /opt/serinus-inertia | ||
|
|
||
| RUN apt-get update \ | ||
| && apt-get install -y --no-install-recommends ca-certificates \ | ||
| && rm -rf /var/lib/apt/lists/* | ||
|
|
||
| COPY --from=server-build /workspace/packages/serinus_inertia/example/build/server ./server | ||
| COPY --from=client-build /workspace/packages/serinus_inertia/example/client/dist ./client/dist | ||
|
|
||
| EXPOSE 4000 | ||
|
|
||
| CMD ["./server"] | ||
|
|
||
| FROM node:24-bookworm-slim AS ssr | ||
| WORKDIR /opt/serinus-inertia/client | ||
|
|
||
| COPY packages/serinus_inertia/example/client/package.json ./package.json | ||
| COPY packages/serinus_inertia/example/client/package-lock.json ./package-lock.json | ||
| RUN npm ci --omit=dev | ||
|
|
||
| COPY --from=client-build /workspace/packages/serinus_inertia/example/client/dist ./dist | ||
|
|
||
| WORKDIR /opt/serinus-inertia | ||
|
|
||
| EXPOSE 13714 | ||
|
|
||
| CMD ["node", "./client/dist/ssr.js"] |
There was a problem hiding this comment.
Run the runtime stages as non-root users.
Both final images currently default to root. The app listens on 4000 and the SSR renderer on 13714, so they can run unprivileged after artifacts are copied.
🛡️ Proposed hardening
FROM debian:bookworm-slim AS app
WORKDIR /opt/serinus-inertia
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates \
- && rm -rf /var/lib/apt/lists/*
+ && rm -rf /var/lib/apt/lists/* \
+ && groupadd --system serinus \
+ && useradd --system --gid serinus --home-dir /opt/serinus-inertia --shell /usr/sbin/nologin serinus
-COPY --from=server-build /workspace/packages/serinus_inertia/example/build/server ./server
-COPY --from=client-build /workspace/packages/serinus_inertia/example/client/dist ./client/dist
+COPY --from=server-build --chown=serinus:serinus /workspace/packages/serinus_inertia/example/build/server ./server
+COPY --from=client-build --chown=serinus:serinus /workspace/packages/serinus_inertia/example/client/dist ./client/dist
EXPOSE 4000
+USER serinus
+
CMD ["./server"]
FROM node:24-bookworm-slim AS ssr
WORKDIR /opt/serinus-inertia/client
COPY packages/serinus_inertia/example/client/package.json ./package.json
COPY packages/serinus_inertia/example/client/package-lock.json ./package-lock.json
RUN npm ci --omit=dev
COPY --from=client-build /workspace/packages/serinus_inertia/example/client/dist ./dist
WORKDIR /opt/serinus-inertia
EXPOSE 13714
+RUN chown -R node:node /opt/serinus-inertia
+USER node
+
CMD ["node", "./client/dist/ssr.js"]📝 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.
| FROM debian:bookworm-slim AS app | |
| WORKDIR /opt/serinus-inertia | |
| RUN apt-get update \ | |
| && apt-get install -y --no-install-recommends ca-certificates \ | |
| && rm -rf /var/lib/apt/lists/* | |
| COPY --from=server-build /workspace/packages/serinus_inertia/example/build/server ./server | |
| COPY --from=client-build /workspace/packages/serinus_inertia/example/client/dist ./client/dist | |
| EXPOSE 4000 | |
| CMD ["./server"] | |
| FROM node:24-bookworm-slim AS ssr | |
| WORKDIR /opt/serinus-inertia/client | |
| COPY packages/serinus_inertia/example/client/package.json ./package.json | |
| COPY packages/serinus_inertia/example/client/package-lock.json ./package-lock.json | |
| RUN npm ci --omit=dev | |
| COPY --from=client-build /workspace/packages/serinus_inertia/example/client/dist ./dist | |
| WORKDIR /opt/serinus-inertia | |
| EXPOSE 13714 | |
| CMD ["node", "./client/dist/ssr.js"] | |
| FROM debian:bookworm-slim AS app | |
| WORKDIR /opt/serinus-inertia | |
| RUN apt-get update \ | |
| && apt-get install -y --no-install-recommends ca-certificates \ | |
| && rm -rf /var/lib/apt/lists/* \ | |
| && groupadd --system serinus \ | |
| && useradd --system --gid serinus --home-dir /opt/serinus-inertia --shell /usr/sbin/nologin serinus | |
| COPY --from=server-build --chown=serinus:serinus /workspace/packages/serinus_inertia/example/build/server ./server | |
| COPY --from=client-build --chown=serinus:serinus /workspace/packages/serinus_inertia/example/client/dist ./client/dist | |
| EXPOSE 4000 | |
| USER serinus | |
| CMD ["./server"] | |
| FROM node:24-bookworm-slim AS ssr | |
| WORKDIR /opt/serinus-inertia/client | |
| COPY packages/serinus_inertia/example/client/package.json ./package.json | |
| COPY packages/serinus_inertia/example/client/package-lock.json ./package-lock.json | |
| RUN npm ci --omit=dev | |
| COPY --from=client-build /workspace/packages/serinus_inertia/example/client/dist ./dist | |
| WORKDIR /opt/serinus-inertia | |
| EXPOSE 13714 | |
| RUN chown -R node:node /opt/serinus-inertia | |
| USER node | |
| CMD ["node", "./client/dist/ssr.js"] |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/serinus_inertia/example/Dockerfile.ssr` around lines 21 - 48, The
final image stages (app and ssr) run as root; update both stages (the "app"
stage and the "ssr" stage) to create a non-root user/group (e.g., uid/gid 1000),
chown the application directories and copied artifacts (the server binary at
./server and the client dist at ./client/dist or ./dist), and add USER to switch
to that non-root account before EXPOSE/CMD so the app listens on ports 4000 and
13714 unprivileged; ensure files are executable and owned by the new user after
the COPY steps and before switching USER.
| final relativePath = context.params['**']?.toString() ?? ''; | ||
| if (relativePath.isEmpty || _containsUnsafeSegments(relativePath)) { | ||
| throw NotFoundException('Asset not found'); | ||
| } | ||
|
|
||
| final assetFile = File('client/dist/assets/$relativePath'); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Verify that AssetController rejects both POSIX and Windows-style traversal segments.
rg -n -C3 "split\\(RegExp\\(r'\\[\\\\\\\\/\\\\\\\\\\]\\+'\\)|split\\('/'\\)|_containsUnsafeSegments" --glob 'asset_controller.dart'Repository: avesbox/inertia_dart
Length of output: 1367
🏁 Script executed:
cat -n packages/serinus_inertia/example/lib/asset_controller.dartRepository: avesbox/inertia_dart
Length of output: 1696
🏁 Script executed:
# Search for other path validation patterns or similar issues in the codebase
rg -n "split\('|split\(RegExp|File\(" packages/serinus_inertia/example/lib/ -A2 -B2Repository: avesbox/inertia_dart
Length of output: 991
🏁 Script executed:
# Check if there are any other implementations or usage patterns of path handling
fd "controller" packages/serinus_inertia/example/lib/ -type f | head -20Repository: avesbox/inertia_dart
Length of output: 234
🏁 Script executed:
# Check if serinus is a dependency and find its implementation
rg -n "class RequestContext|context.params\|" packages/serinus_inertia/ -A5 -B2 | head -50Repository: avesbox/inertia_dart
Length of output: 46
🏁 Script executed:
# Search for how URL parameters are decoded in the framework
fd "serinus" packages/ -type dRepository: avesbox/inertia_dart
Length of output: 234
🏁 Script executed:
# Check if there's any URL decoding happening in the codebase
rg -n "Uri.decodeComponent|Uri.parse|decodeURI|decodeURIComponent" packages/serinus_inertia/Repository: avesbox/inertia_dart
Length of output: 1847
🏁 Script executed:
# Look for documentation or pubspec files to understand serinus dependency
cat packages/serinus_inertia/pubspec.yaml | head -40Repository: avesbox/inertia_dart
Length of output: 577
🏁 Script executed:
# Search for tests of the AssetController or route parameter handling
rg -n "asset|/**|params\[" packages/serinus_inertia/example/ -A3 -B3 | head -60Repository: avesbox/inertia_dart
Length of output: 4172
🏁 Script executed:
# Check if there are any other controllers with similar patterns
rg -n "split\('/'|existsSync|statSync" packages/serinus_inertia/example/ -B2 -A2Repository: avesbox/inertia_dart
Length of output: 1549
🏁 Script executed:
# Look for any route or parameter examples in tests
fd ".*test.*" packages/serinus_inertia/example/ -type fRepository: avesbox/inertia_dart
Length of output: 234
Validate both POSIX and Windows path separators in _containsUnsafeSegments.
The validation at line 40 only splits on /, so backslash separators can hide .. segments. On Windows-compatible Dart deployments, if URL parameters are decoded (standard HTTP behavior), a request like /assets/..%5C..%5Cfile could bypass validation. Split on both separator forms and reject empty segments.
🛡️ Recommended fix
bool _containsUnsafeSegments(String path) {
- return path.split('/').any((segment) => segment == '..' || segment == '.');
+ return path
+ .split(RegExp(r'[\\/]+'))
+ .any((segment) => segment.isEmpty || segment == '..' || segment == '.');
}Also applies to: 39-40
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/serinus_inertia/example/lib/asset_controller.dart` around lines 14 -
19, The _containsUnsafeSegments check currently only splits relativePath on '/'
so backslashes can hide traversal; update _containsUnsafeSegments to split the
incoming relativePath on both '/' and '\' (treat both as separators), reject any
empty segments, and then check each segment for '.' or '..' (or any other unsafe
token) to return true; ensure the code that reads context.params['**']
(relativePath) still uses this updated helper before constructing
File('client/dist/assets/$relativePath') so Windows-style separators cannot
bypass the validation.
| if (!assetFile.existsSync() || | ||
| assetFile.statSync().type != FileSystemEntityType.file) { | ||
| throw NotFoundException('Asset not found'); | ||
| } | ||
|
|
||
| context.res.contentType = ContentType.parse( | ||
| lookupMimeType(assetFile.path) ?? 'application/octet-stream', | ||
| ); | ||
| context.res.contentLength = assetFile.lengthSync(); |
There was a problem hiding this comment.
Avoid synchronous filesystem calls in the request path.
existsSync, statSync, and lengthSync block the Dart isolate while serving static assets. Use one async stat() call and reuse its size.
⚡ Proposed async filesystem check
- if (!assetFile.existsSync() ||
- assetFile.statSync().type != FileSystemEntityType.file) {
+ final assetStat = await assetFile.stat();
+ if (assetStat.type != FileSystemEntityType.file) {
throw NotFoundException('Asset not found');
}
context.res.contentType = ContentType.parse(
lookupMimeType(assetFile.path) ?? 'application/octet-stream',
);
- context.res.contentLength = assetFile.lengthSync();
+ context.res.contentLength = assetStat.size;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/serinus_inertia/example/lib/asset_controller.dart` around lines 20 -
28, The code currently uses synchronous filesystem calls
(assetFile.existsSync(), assetFile.statSync(), assetFile.lengthSync()) in the
request path; replace them with a single asynchronous stat call: call await
assetFile.stat(), check the returned FileStat.type equals
FileSystemEntityType.file (throw NotFoundException('Asset not found') if not),
then reuse FileStat.size to set context.res.contentLength and keep setting
context.res.contentType as before (using lookupMimeType on assetFile.path).
Update any surrounding function to be async if needed so you can await
assetFile.stat().
| For each request: | ||
|
|
||
| 1. Parse the request with `inertiaRequestFromHttp(request)`. | ||
| 2. Build `PropertyContext` from `inertiaRequest.createContext()`. | ||
| 3. Build page data with `InertiaResponseFactory().buildPageDataAsync(...)`. | ||
| 4. Return JSON when `inertiaRequest.isInertia` is true. | ||
| 5. Otherwise render HTML with `renderInertiaBootstrap(page)` and resolved asset tags. | ||
|
|
There was a problem hiding this comment.
Include the Inertia asset-version conflict step.
The raw flow should call out the same version check shown in RoutedInertiaMiddleware: for Inertia requests, compare the request version to the current asset version and return 409 with X-Inertia-Location before building a normal page response. Otherwise stale clients can keep using old chunks after a deploy.
📝 Suggested doc addition
For each request:
1. Parse the request with `inertiaRequestFromHttp(request)`.
2. Build `PropertyContext` from `inertiaRequest.createContext()`.
-3. Build page data with `InertiaResponseFactory().buildPageDataAsync(...)`.
-4. Return JSON when `inertiaRequest.isInertia` is true.
-5. Otherwise render HTML with `renderInertiaBootstrap(page)` and resolved asset tags.
+3. If `inertiaRequest.isInertia` and the requested asset version is stale,
+ return `409` with the `X-Inertia-Location` header set to the current URL.
+4. Build page data with `InertiaResponseFactory().buildPageDataAsync(...)`.
+5. Return JSON when `inertiaRequest.isInertia` is true.
+6. Otherwise render HTML with `renderInertiaBootstrap(page)` and resolved asset tags.📝 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.
| For each request: | |
| 1. Parse the request with `inertiaRequestFromHttp(request)`. | |
| 2. Build `PropertyContext` from `inertiaRequest.createContext()`. | |
| 3. Build page data with `InertiaResponseFactory().buildPageDataAsync(...)`. | |
| 4. Return JSON when `inertiaRequest.isInertia` is true. | |
| 5. Otherwise render HTML with `renderInertiaBootstrap(page)` and resolved asset tags. | |
| For each request: | |
| 1. Parse the request with `inertiaRequestFromHttp(request)`. | |
| 2. Build `PropertyContext` from `inertiaRequest.createContext()`. | |
| 3. If `inertiaRequest.isInertia` and the requested asset version is stale, | |
| return `409` with the `X-Inertia-Location` header set to the current URL. | |
| 4. Build page data with `InertiaResponseFactory().buildPageDataAsync(...)`. | |
| 5. Return JSON when `inertiaRequest.isInertia` is true. | |
| 6. Otherwise render HTML with `renderInertiaBootstrap(page)` and resolved asset tags. |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@skills/inertia-dart-frontend/references/dart-io.md` around lines 21 - 28, Add
the Inertia asset-version conflict check before building a normal page response:
when handling an Inertia request (inertiaRequest.isInertia), compare the request
version (inertiaRequest.version) to the current app asset version (the same
check logic used in RoutedInertiaMiddleware), and if they differ return an HTTP
409 with an X-Inertia-Location header pointing to the current location instead
of calling InertiaResponseFactory().buildPageDataAsync(...) or
renderInertiaBootstrap(page); ensure this early-return happens immediately after
inertiaRequestFromHttp(request) / inertiaRequest.createContext() and before any
page construction or JSON/html rendering.
There was a problem hiding this comment.
Pull request overview
This PR enhances the serinus_inertia example’s production story (direct Vite asset serving + SSR env wiring) and adds a portable “inertia-dart-frontend” skill with reference docs for Serinus/Routed/raw dart:io, plus deployment/Docker guidance.
Changes:
- Add a Serinus controller to serve built Vite assets at
/assets/*with immutable caching, and wire SSR options from environment variables. - Add production deployment documentation and container artifacts (Dockerfiles + Compose) for client-only and SSR topologies.
- Introduce a portable
inertia-dart-frontendskill with integration-specific reference guides and shared client patterns.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| skills/inertia-dart-frontend/references/serinus.md | Serinus-specific integration guidance (assets, SSR, static serving options). |
| skills/inertia-dart-frontend/references/routed.md | Routed-specific integration guidance and configuration expectations. |
| skills/inertia-dart-frontend/references/docker.md | Reference guidance for Docker/Compose patterns and SSR topology. |
| skills/inertia-dart-frontend/references/deployment.md | Reference guidance for production build outputs, asset serving, and SSR deployment rules. |
| skills/inertia-dart-frontend/references/dart-io.md | Reference guidance for raw dart:io Inertia request flow, assets, and SSR. |
| skills/inertia-dart-frontend/references/client-patterns.md | Shared frontend conventions (scaffolding, resolver, SSR hydration, asset paths). |
| skills/inertia-dart-frontend/agents/openai.yaml | Declares the skill’s OpenAI agent metadata. |
| skills/inertia-dart-frontend/SKILL.md | Defines the skill workflow/rules and when to load each reference. |
| packages/serinus_inertia/example/pubspec.yaml | Adds mime dependency for correct asset content types. |
| packages/serinus_inertia/example/lib/asset_controller.dart | Implements /assets/** serving from client/dist/assets/** with caching + HEAD support. |
| packages/serinus_inertia/example/lib/app_module.dart | Adds SSR env-based configuration and registers the new asset controller. |
| packages/serinus_inertia/example/compose.yaml | Adds Compose profiles for client-only and SSR stacks with renderer healthcheck gating. |
| packages/serinus_inertia/example/client/vite.config.js | Sets Rollup input to align manifest keys with src/main.jsx entry usage. |
| packages/serinus_inertia/example/client/package.json | Splits client vs SSR build scripts; ensures hot file is removed for production builds. |
| packages/serinus_inertia/example/README.md | Updates docs to point to DEPLOY guide and adds Compose usage instructions. |
| packages/serinus_inertia/example/Dockerfile.ssr | Adds multi-stage build for app + SSR renderer runtime image. |
| packages/serinus_inertia/example/Dockerfile.client | Adds multi-stage build for the client-only runtime image. |
| packages/serinus_inertia/example/DEPLOY.md | Adds full deployment walkthrough incl. systemd + optional nginx/Caddy patterns. |
| .dockerignore | Excludes VCS and build artifacts from Docker build context. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| final endpoint = _envString('SERINUS_INERTIA_SSR_ENDPOINT'); | ||
| if (endpoint != null) { | ||
| return InertiaSsrOptions(enabled: true, endpoint: Uri.parse(endpoint)); |
There was a problem hiding this comment.
SERINUS_INERTIA_SSR_ENDPOINT is parsed with Uri.parse(endpoint) without handling FormatException. If the env var is malformed, the example will crash at startup with a fairly opaque stack trace. Consider catching the parse error and either (a) disabling SSR with a clear log message, or (b) throwing a StateError/configuration exception that includes the env var name and expected format.
| return InertiaSsrOptions(enabled: true, endpoint: Uri.parse(endpoint)); | |
| try { | |
| return InertiaSsrOptions(enabled: true, endpoint: Uri.parse(endpoint)); | |
| } on FormatException catch (error) { | |
| throw StateError( | |
| 'Invalid SERINUS_INERTIA_SSR_ENDPOINT value "$endpoint". ' | |
| 'Expected an absolute URI such as ' | |
| '"http://127.0.0.1:13714/render". ${error.message}', | |
| ); | |
| } |
|
|
||
| WORKDIR /workspace/packages/serinus_inertia/example/client | ||
| RUN npm ci | ||
| RUN npm run build |
There was a problem hiding this comment.
This image runs npm run build, but build now includes build:ssr (SSR bundle + SSR manifest). For the client-only container profile, that extra SSR build work and output is unnecessary and increases build time/image size. Consider switching this Dockerfile to npm run build:client (and keep the SSR build only in Dockerfile.ssr).
| RUN npm run build | |
| RUN npm run build:client |
Summary
serinus_inertiaexample, including Vite build updates and SSR env wiringinertia-dart-frontendskill that works acrossinertia_dart,routed_inertia, andserinus_inertiawithout assuming this repo's local examples existCommit breakdown
feat(serinus_inertia): serve production assets directlydocs(serinus_inertia): add deployment guide and containersfeat(skills): add portable inertia frontend skillVerification
dart analyzeinpackages/serinus_inertia/examplepython3 /home/kingwill101/.codex/skills/skill-creator/scripts/quick_validate.py skills/inertia-dart-frontenddocker compose --profile client up --build -ddocker compose --profile ssr up --build -dSummary by CodeRabbit
Release Notes
New Features
Documentation
Chores
.dockerignoreto exclude build artifacts from Docker context