request inject Dev Cookbook
This page does not repeat basic inject syntax. It focuses directly on the most common request inject patterns used in the current lzc-cli workflow.
Target scenarios:
- Frontend development: proxy the app entry to a dev machine frontend server.
- Backend development: return a static guide page when the service is not ready, and proxy to the real backend once ready.
- Keep all of this active only in dev mode so release stays clean.
Related docs:
1. Enable only in dev mode
The recommended pattern is to gate dev-only behavior in manifest build preprocessing, instead of checking many variables inside the script itself.
Example:
application:
routes:
- /=file:///lzcapp/pkg/content/dist
#@build if env.DEV_MODE=1
injects:
- id: frontend-dev-proxy
on: request
auth_required: false
when:
- "/*"
do:
- src: |
// dev only request inject here
#@build endThis way the release render result does not contain the inject at all.
2. Frontend development: proxy to dev machine
Use this pattern for:
vitewebpack dev server- Any frontend server running on a local port of the dev machine
Note: lzc-cli project deploy syncs the current development machine's dev.id into the app instance. The inject script then uses ctx.dev.id together with ctx.net.via.client(...) to route traffic to that development machine.
Example:
application:
routes:
- /=file:///lzcapp/pkg/content/dist
#@build if env.DEV_MODE=1
injects:
- id: frontend-dev-proxy
on: request
auth_required: false
when:
- "/*"
do:
- src: |
const devPort = 3000;
const contentType = "text/html; charset=utf-8";
function renderDevPage(title, subtitle, steps) {
const items = steps.map(function (step) {
return "<li>" + step + "</li>";
}).join("");
return [
"<!doctype html>",
"<html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><title>Frontend Dev</title></head>",
"<body><h1>", title, "</h1><p>", subtitle, "</p><div>Expected local port: ", String(devPort), "</div><ol>", items, "</ol></body></html>",
].join("");
}
if (!ctx.dev.id) {
ctx.response.send(200, renderDevPage(
"Dev machine is not linked yet",
"This app is waiting for a frontend dev server from the machine that runs lzc-cli project deploy.",
[
"Run <code>lzc-cli project deploy</code> on your dev machine.",
"Start your local dev server with <code>npm run dev</code>.",
"Refresh this page after port <code>" + String(devPort) + "</code> is ready.",
]
), { content_type: contentType });
return;
}
const via = ctx.net.via.client(ctx.dev.id);
if (!ctx.dev.online()) {
ctx.response.send(200, renderDevPage(
"Dev machine is offline",
"The linked dev machine is not reachable right now.",
[
"Bring the dev machine online.",
"Start your local dev server with <code>npm run dev</code>.",
"Refresh this page after port <code>" + String(devPort) + "</code> is ready.",
]
), { content_type: contentType });
return;
}
if (!ctx.net.reachable("tcp", "127.0.0.1", devPort, via)) {
ctx.response.send(200, renderDevPage(
"Frontend dev server is not ready",
"This app is running in dev mode and will proxy requests to your linked dev machine.",
[
"Start your local dev server with <code>npm run dev</code>.",
"Make sure the dev server listens on port <code>" + String(devPort) + "</code>.",
"Refresh this page after the server is ready.",
]
), { content_type: contentType });
return;
}
ctx.proxy.to("http://127.0.0.1:" + String(devPort), {
via: via,
use_target_host: true,
});
#@build endKey points:
- Check
ctx.dev.idfirst so the app can explain what is missing. - Then check
ctx.dev.online()to avoid meaningless live probe against a known offline machine. - Use
ctx.net.reachable(...)for the final port readiness probe. - Use
ctx.proxy.to(..., { via })to route traffic to the dev machine.
3. Backend development: return a guide page until ready
Use this pattern for:
- Go / Java services that are better started manually in dev mode
- Any backend that must run inside the real LPK runtime environment
Example:
application:
#@build if env.DEV_MODE!=1
routes:
- /=exec://3000,/app/run.sh
#@build end
#@build if env.DEV_MODE=1
injects:
- id: backend-dev-proxy
on: request
auth_required: false
when:
- "/*"
do:
- src: |
const backendPort = 3000;
const backendURL = "http://127.0.0.1:" + String(backendPort);
const contentType = "text/html; charset=utf-8";
function renderDevPage(steps) {
const items = steps.map(function (step) {
return "<li>" + step + "</li>";
}).join("");
return [
"<!doctype html>",
"<html lang=\"en\"><head><meta charset=\"UTF-8\"><title>Backend Dev</title></head>",
"<body><h1>Backend dev service is not ready</h1><ol>", items, "</ol></body></html>",
].join("");
}
if (!ctx.net.reachable("tcp", "127.0.0.1", backendPort)) {
ctx.response.send(200, renderDevPage([
"Sync your latest code into the container with <code>lzc-cli project sync --watch</code> or copy it with <code>lzc-cli project cp</code>.",
"Open a shell with <code>lzc-cli project exec /bin/sh</code> and start or restart the backend process with <code>/app/run.sh</code>.",
"Refresh this page after port <code>" + String(backendPort) + "</code> is ready.",
]), { content_type: contentType });
return;
}
ctx.proxy.to(backendURL, {
use_target_host: true,
});
#@build endKey points:
- In dev mode, remove the auto-start route so the strategy is not bypassed.
- When the service is not ready, return a static guide page directly.
- Proxy to the real backend only after the port is actually ready.
4. Access lzcos host network or a specific client node
Both ctx.proxy.to(...) and ctx.net.reachable(...) support via.
Access lzcos host network:
ctx.proxy.to("http://127.0.0.1:8080", {
via: ctx.net.via.host(),
use_target_host: true,
});Access a specific client node:
if (ctx.dev.id) {
ctx.proxy.to("http://127.0.0.1:3000", {
via: ctx.net.via.client(ctx.dev.id),
use_target_host: true,
});
}5. When to send a static page directly
Recommended cases for ctx.response.send(...):
- Dev machine is not linked yet
- Dev machine is offline
- Frontend or backend service is not started yet
- You want to provide an explicit next step instead of a vague 502
Do not use fallback to release routes by default. That tends to hide the real dev state and makes developers think the dev path is already active.
6. Recommended debug order
Debug in this order:
- Whether the inject really matches the current path
- Whether
ctx.dev.idis empty - Whether
ctx.dev.online()istrue - Whether
ctx.net.reachable(...)istrue - Whether
ctx.proxy.to(...)uses the correctvia
Temporary debug headers are often useful:
ctx.headers.set("X-Debug-Dev-ID", ctx.dev.id || "");
ctx.headers.set("X-Debug-Dev-Online", String(ctx.dev.online()));7. Recommended combinations
These helpers work best together:
#@build if env.DEV_MODE=1- Trim dev-only inject at package build time
ctx.dev- Check whether the app is linked to a dev machine and whether it is online
ctx.net.reachable- Check whether the target service is actually ready
ctx.net.via.*- Route traffic to networks outside the container
ctx.response.send- Return a clear guide page when the service is not ready
ctx.proxy.to- Switch to the real target once ready
Next
- For API reference: continue with inject.ctx spec
- For the full workflow: continue with Dev Workflow Overview
- For inject matching and built-in scripts: continue with Script Injection (injects)