Skip to content

Bootstrap CodePress Live Dev Server recipe + dev Dockerfile - #55

Open
codepress-dev[bot] wants to merge 1 commit into
masterfrom
codepress/dev@codepress.dev/you-are-bootstrapping-the-live-dev-bed74342
Open

Bootstrap CodePress Live Dev Server recipe + dev Dockerfile#55
codepress-dev[bot] wants to merge 1 commit into
masterfrom
codepress/dev@codepress.dev/you-are-bootstrapping-the-live-dev-bed74342

Conversation

@codepress-dev

@codepress-dev codepress-dev Bot commented Jul 28, 2026

Copy link
Copy Markdown

Summary

This sets up live previews for this repo. Until now, CodePress had to guess how to start your frontend; this PR adds two small config files that tell it exactly how, so a preview of the React app in web/ boots reliably and updates as you edit.

The only runnable frontend here is the create-react-app in web/. It's a 2017-era toolchain (react-scripts 1.0.10 on webpack 2), which is exactly the kind of setup a generic heuristic gets wrong — so rather than guessing, I actually installed and ran it to confirm the image will work: it boots, serves the app under a preview address, and its hot-reload connection comes up.

Nothing about how your app runs changes. These files are only read by CodePress previews; your existing yarn start and production build are untouched.

One thing I deliberately did not do: I left your Django backend alone. Previews sometimes need a CORS tweak so the previewed frontend can call the API, but that doesn't apply here — web/ makes no API calls, and in production Django serves the React build itself, so it's same-origin. There's also no staging environment to scope such a change to. Details in the open items below.

Technical details

Adds .codepress/dev-server/recipe.json (the contract the Live Dev Server reads) and .codepress/dev-server/Dockerfile.web (a thin, dev-mode, toolchain-only image). No application code is touched.

Discovery. One runnable frontend: web/framework: cra, package_manager: yarn (yarn lockfile v1, no packageManager field), dev_port: 3000, dependency_manifests: ["web/yarn.lock"], install_command: yarn install --frozen-lockfile, size: small. No prebuild step (postbuild is a production-only hook that copies the build into server/static/build/, so it stays out of dev_command). samples/auth-web/ is loose reference snippets — no package.json/index.html, not imported by web/src — so it is not a frontend.

Why node:18-bookworm. This was the main judgement call. -bookworm tags start at Node 18, which is also the closest available match to a react-scripts 1.0.10 / webpack 2.6.1 dependency tree. Rather than assume it works, I ran it: installed web/'s deps under Node 18.20.8 (OpenSSL 3.0.16 — identical to the image) with yarn install --frozen-lockfile, started the dev server, and verified HTTP 200 on /, HTTP 200 on a non-loopback interface (proving the 0.0.0.0 bind), and /sockjs-node/info returning {"websocket":true}.

Three findings from that testing changed the output, and are each worth a look:

  • No NODE_OPTIONS=--openssl-legacy-provider. The reflex for webpack-on-OpenSSL-3 is the legacy-provider flag, but that's a webpack 4+ problem (md4). webpack 2.6.1 hashes with md5, which OpenSSL 3 still provides. I confirmed the dev server compiles cleanly without the flag, so it isn't set — one less bit of unexplained config.
  • Corepack is deliberately not enabled, contrary to the usual template. The repo declares no packageManager, so corepack enable would replace the yarn 1.22 already baked into the node image with a shim that resolves a yarn release over the network on first run — a cold-start failure mode for no benefit.
  • No HMR client-port wiring. react-dev-utils 3.0.2's webpackHotDevClient builds its SockJS URL from window.location (verified in the package source), so it follows the preview origin to wss/443 on its own. WDS_SOCKET_PORT is still mapped from CODEPRESS_HMR_CLIENT_PORT in the CMD; it is inert on this pinned version and only takes effect if react-scripts is upgraded to >= 3.4. The Dockerfile comment says so explicitly so it doesn't read as working config.

DANGEROUSLY_DISABLE_HOST_CHECK=true is set defensively: webpack-dev-server 2.5.0 does have checkHost, and react-scripts only auto-disables it while no proxy key exists in web/package.json. That's true today (hence the verified 200 under a preview Host header), but adding a proxy later would otherwise silently break previews with "Invalid Host header".

The image satisfies the thin-image contract: full -bookworm base (not -slim, so runtime node-gyp installs have a toolchain), no baked node_modules, no source COPY, procps installed, WORKDIR /app/app/web, and bind/HMR driven entirely by CODEPRESS_BIND_HOST/PORT/CODEPRESS_HMR_* with no localhost literals.

staging_backend_url is omitted — no .env*, no CI workflows, no vercel.json, no verify-staging recipe, so there was no candidate. Per the never-persist-a-guess rule the key is absent rather than empty, and no Live Dev Server env var was prefilled (web/ reads no API-base env var).

No backend CORS edit. Django is in server/, but the gate fails on two independent counts: it has no cross-origin surface (no django-cors-headers anywhere, and web/src issues zero API calls — redux/example.js is a boilerplate reducer, not an auth flow), and there is no staging-only config path to scope an allowance to (a single server/server/settings.py, no settings package, no env gating). Adding CORS would have meant introducing a dependency and inventing a staging environment, which is well outside an append-only allowance — so this is correctly report-only.

No social-auth work. No runnable frontend has social or enterprise sign-in (web/ has a single / route and no sign-in UI), so the preview social-auth audit was not applicable.

Changes

  • Add .codepress/dev-server/recipe.json — schema_version 1, one frontend entry for web/ (cra, yarn, port 3000)
  • Add .codepress/dev-server/Dockerfile.web — thin dev-mode image on node:18-bookworm with env-driven bind and HMR
  • Pin node:18-bookworm and omit the OpenSSL legacy-provider flag, both verified by running the dev server
  • Skip corepack in favour of the image's preinstalled yarn 1, since the repo declares no packageManager
  • Set DANGEROUSLY_DISABLE_HOST_CHECK so previews keep working if a proxy key is ever added to web/package.json

Test plan

  • Build the image from the repo root: docker build -f .codepress/dev-server/Dockerfile.web -t ddi-web . — it should succeed and bake no node_modules.
  • Install deps the way the runtime does: from web/, run yarn install --frozen-lockfile on Node 18. It should complete without node-gyp errors (fsevents is darwin-only and is skipped on linux).
  • Run the container with the checkout mounted at /app and confirm the dev server starts: docker run --rm -p 3000:3000 -v "$PWD":/app ddi-web. Expect create-react-app's "Compiled successfully!".
  • Confirm it binds all interfaces, not loopback: curl -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3000/ returns 200.
  • Confirm the preview Host header is accepted (the "Invalid Host header" regression): curl -o /dev/null -w '%{http_code}\n' -H 'Host: 0123456789abcdef0123456789abcdef-de116f94b7ab06ad.preview.codepress.dev' http://127.0.0.1:3000/ returns 200.
  • Confirm the hot-reload endpoint is live: curl http://127.0.0.1:3000/sockjs-node/info returns JSON containing "websocket":true.
  • Open a CodePress preview, edit web/src/containers/home/Home.js, and verify the browser hot-reloads without a manual refresh.
  • Confirm nothing else changed: git diff --stat origin/master...HEAD should list only the two files under .codepress/dev-server/.

Open items

  • Backend CORS was intentionally not changed. The Django API in server/ is same-origin (web/ makes no API calls, and its production build is served by Django's catch-all index view), and the repo has no staging-only config path to scope an allowance to. If you later add cross-origin API calls from the previewed frontend, preview requests will need an anchored allowance for ^https://[0-9a-f]{32}-de116f94b7ab06ad.preview.codepress.dev$ added to a staging-only Django settings path (via django-cors-headers' CORS_ALLOWED_ORIGIN_REGEXES) — never to base or production config. Any such change only affects the live API after staging is deployed with it.
  • No staging backend URL was detected, so staging_backend_url is omitted from the recipe and no backend URL was prefilled into the Live Dev Server env settings. Previews still run; the UI just won't pre-fill a backend.
  • The dev image was validated by running this app's dev server on a matching Node 18.20 / OpenSSL 3 toolchain, but the Docker image itself was not built (no Docker daemon in the bootstrap environment). The build step in the test plan is the one unexercised path.
  • react-scripts 1.0.10 is pinned exactly and is ~8 years old. The recipe is built around that pin (Node 18 base, no corepack, window.location-based HMR). If you upgrade react-scripts, re-run /codepress-bootstrap-dev-server so the base image and HMR wiring are re-derived — the generated files carry managed-file headers and are safe to regenerate.

Authors

Generated with CodePress · View the chat session

Co-authored-by: dev@codepress.dev dev@codepress.dev

Author the committed Live Dev Server artifacts so previews boot from
repo-owned files instead of a runtime heuristic.

Discovered one runnable frontend: the create-react-app app in web/
(react-scripts 1.0.10 / webpack 2.6.1, yarn classic lockfile).

Dockerfile.web pins node:18-bookworm -- the oldest Debian-bookworm Node
image and the closest match to this 2017-era toolchain. Verified on Node
18.20 / OpenSSL 3 that the app installs with `yarn install
--frozen-lockfile`, boots, binds 0.0.0.0, serves HTTP 200 under a
preview Host header, and exposes a live /sockjs-node HMR endpoint.

Notes on deliberate choices:
- No --openssl-legacy-provider: webpack 2 hashes with md5, not md4, so
  OpenSSL 3 does not break it (confirmed by running the dev server).
- Corepack is not enabled: the repo declares no `packageManager`, so a
  corepack shim would try to fetch yarn from the network on cold start.
- No HMR client-port wiring needed: react-dev-utils 3.0.2 builds its
  SockJS URL from window.location, so it follows the preview origin.

No backend CORS change: the Django API in server/ is same-origin only
(web/ makes no API calls and its build is served by Django), and the
repo has no staging config path to scope an allowance to.

Co-authored-by: dev@codepress.dev <dev@codepress.dev>
@codepress-dev codepress-dev Bot added the cp:in-progress CodePress: still being worked on label Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cp:in-progress CodePress: still being worked on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants