What happens
The plugin runs icp once, in the config hook, and returns the ic_env cookie as a static server.headers["Set-Cookie"] and the /api target as a static server.proxy entry. Nothing re-runs detection while the server lives. So:
-
A canister deployed after vite dev started never gets its id. Starting the dev server before (or while) deploying is the usual order. The plugin even warns about it, in words that promise the opposite:
The local replica is running, but no canister ID could be resolved for "backend". Deploy it (icp deploy) — until then the injected ic_env carries no PUBLIC_CANISTER_ID for it and the app will see an undefined canister id.
After icp deploy, every reload still gets a cookie without PUBLIC_CANISTER_ID:backend, and the reactor throws "canisterId is required ... could not be resolved from the ic_env cookie" until the dev server is restarted.
-
A network that was down at startup is never picked up. The plugin falls back to proxying /api to http://127.0.0.1:4943 and injects no cookie. icp network start then brings the network up on icp-cli's port (8000 by default), but /api keeps going to 4943 and the page keeps getting no cookie. (The env-only fallback cookie in the same branch already assumes port 8000 for Internet Identity.)
-
Redeploying into a fresh network state (new canister ids) keeps serving the old ids.
Measured on Vite 4.2.0, 4.5.14, 5.4.21, 6.4.3, 7.3.6 and 8.3.0 with a fake icp whose answers change while the server runs:
vite dev started, backend not deployed: root key ends ...aaae PUBLIC_CANISTER_ID:backend=(none)
(icp now reports backend = bkyz2-fmaaa-aaaaa-qaaaq-cai)
after deploy, page reload: root key ends ...aaae PUBLIC_CANISTER_ID:backend=(none)
(network restarted: new root key ...aaaf, backend redeployed as be2us-64aaa-aaaaa-qaaba-cai)
after network restart + redeploy, reload: root key ends ...aaae PUBLIC_CANISTER_ID:backend=(none)
icp calls made: 3
#304 listed this as a low-severity note ("ic_env cookie computed once at server start; no re-detection"); it was never filed.
Why it is a design question
Fixing it changes when and how often the plugin runs icp, and how the /api proxy is built:
- The cookie can be set per response from a
configureServer middleware instead of server.headers.
- The proxy target is fixed in Vite's proxy config. Following a network that moves needs either a plugin-owned proxy or a
bypass/configure hook that updates the target.
- Each
icp call takes about 30 ms here (icp 1.5.0), once for the network and once per canister plus internet_identity.
Options
A. Re-detect for document requests, cached. A middleware sets ic_env on HTML responses from a detection result at most a few seconds old, refreshed with async execFile. The cookie follows deploys and network restarts on the next reload. It costs about (2 + N) × 30 ms at most once per cache window, and needs the proxy target to follow the same result.
B. Re-detect only while incomplete. Retry on document requests only while detection failed or a configured canister had no id, and stop once everything resolves. It is cheap and fixes cases 1 and 2. It does not follow a later redeploy (case 3).
C. Keep it static and say so. Change the warning to "deploy it, then restart the dev server", and document that the environment is read once. No behaviour change.
Recommendation
B now, since it fixes the reported workflow (dev server first, deploy second) with almost no cost. Also change the fallback proxy target to follow detection. Consider A only if restarts with fresh network state turn out to be common. Whatever is chosen, the warning text should stop promising something the plugin does not do.
Acceptance (for B)
What happens
The plugin runs
icponce, in theconfighook, and returns theic_envcookie as a staticserver.headers["Set-Cookie"]and the/apitarget as a staticserver.proxyentry. Nothing re-runs detection while the server lives. So:A canister deployed after
vite devstarted never gets its id. Starting the dev server before (or while) deploying is the usual order. The plugin even warns about it, in words that promise the opposite:After
icp deploy, every reload still gets a cookie withoutPUBLIC_CANISTER_ID:backend, and the reactor throws "canisterId is required ... could not be resolved from the ic_env cookie" until the dev server is restarted.A network that was down at startup is never picked up. The plugin falls back to proxying
/apitohttp://127.0.0.1:4943and injects no cookie.icp network startthen brings the network up on icp-cli's port (8000 by default), but/apikeeps going to 4943 and the page keeps getting no cookie. (The env-only fallback cookie in the same branch already assumes port 8000 for Internet Identity.)Redeploying into a fresh network state (new canister ids) keeps serving the old ids.
Measured on Vite 4.2.0, 4.5.14, 5.4.21, 6.4.3, 7.3.6 and 8.3.0 with a fake
icpwhose answers change while the server runs:#304 listed this as a low-severity note ("ic_env cookie computed once at server start; no re-detection"); it was never filed.
Why it is a design question
Fixing it changes when and how often the plugin runs
icp, and how the/apiproxy is built:configureServermiddleware instead ofserver.headers.bypass/configurehook that updates the target.icpcall takes about 30 ms here (icp 1.5.0), once for the network and once per canister plusinternet_identity.Options
A. Re-detect for document requests, cached. A middleware sets
ic_envon HTML responses from a detection result at most a few seconds old, refreshed with asyncexecFile. The cookie follows deploys and network restarts on the next reload. It costs about (2 + N) × 30 ms at most once per cache window, and needs the proxy target to follow the same result.B. Re-detect only while incomplete. Retry on document requests only while detection failed or a configured canister had no id, and stop once everything resolves. It is cheap and fixes cases 1 and 2. It does not follow a later redeploy (case 3).
C. Keep it static and say so. Change the warning to "deploy it, then restart the dev server", and document that the environment is read once. No behaviour change.
Recommendation
B now, since it fixes the reported workflow (dev server first, deploy second) with almost no cost. Also change the fallback proxy target to follow detection. Consider A only if restarts with fresh network state turn out to be common. Whatever is chosen, the warning text should stop promising something the plugin does not do.
Acceptance (for B)
icpreporting no id for a configured canister at startup, a page load after the canister is deployed receives a cookie carrying its id, without restarting Vite./apireaches the detected target.icpcommands.