Viewer guide

Build the image yourself

Only if you changed the source or must build images in-house. Two things about the Dockerfile will bite you if you skip them.

The published image on Deploy the Viewer is the shortest path.

Skip this page unless you have changed the source, or your organization requires images built in-house.

There is a Dockerfile at viewer/Dockerfile. Two things about it are unusual and will bite you if you skip them.

The bridge comes from your checkout#

The script the Viewer adds to every prototype it serves is dist/bridge-bundle.js at the repo root. The Dockerfile does not build it: it copies the file from your checkout as it is. The file is committed, and CI fails any commit where it differs from a fresh build of the bridge source, so a clean checkout already has the right one.

Rebuild it only if you changed the bridge source yourself. From the repo root:

npm install
npm run build:bridge

If the file is missing outright, the image builds cleanly and then exits on startup.

The build context is the repo root#

The Dockerfile copies from repo-root paths (viewer/package.json and the root package.json), because the Viewer's Next.js dashboard resolves next and react from the checkout root rather than vendoring its own copies. So you build from the repo root and point -f at the Dockerfile, not the other way around:

DOCKER_BUILDKIT=1 docker build -f viewer/Dockerfile -t desde-viewer .

Running docker build . from inside viewer/ fails: the root package.json is not in that context.

Why DOCKER_BUILDKIT=1 is in that command#

The ignore rules for this build live in viewer/Dockerfile.dockerignore. Naming an ignore file <Dockerfile>.dockerignore next to its Dockerfile is a BuildKit feature. The classic builder looks only for a .dockerignore at the context root, and this repo does not have one.

So if the build runs on the classic builder (an old Docker Engine, or DOCKER_BUILDKIT=0), nothing is excluded and COPY . . copies your entire working checkout into the image. That includes .git, every node_modules tree, and viewer/.env.local, which holds your GitHub App private key, the App client secret, the session secret, and your SMTP password.

BuildKit is the default in Docker Desktop, which bundles the buildx plugin BuildKit needs.

Note On a Linux host, DOCKER_BUILDKIT=1 can fail the build outright:

ERROR: BuildKit is enabled but the buildx component is missing or broken.

The variable does not turn on a builder that is already there. It selects one that ships as a separate plugin, and an engine without it stops rather than falling back. Install the plugin (apt install docker-buildx-plugin, or your distribution's equivalent), or drop the variable and read the paragraph below: the classic builder produces a correct image, it just copies more into the context on the way.

The build does not rely on you getting that right. After COPY . ., the Dockerfile asserts that no .env, .env.local, .env.*.local or .env.production reached the build context, and fails the build if one did. The ignore file is the optimization; the assertion is the control. (.env.example is exempt: it is a tracked template with no real values.) To confirm after a build anyway:

docker run --rm desde-viewer ls -a /app/viewer

There should be no .env.local in that listing.