7. Shipping it
The app works. In this last step you'll build it for production and run it the way a server would, first directly and then in Docker.
Build and run
Stop the dev server, then:
bun run build
NODE_ENV=production bun run start -- --no-buildsigil build compiles every route for the browser, once for hydrating server-rendered pages and once for rendering pages from scratch after client-side navigation, and writes the bundles to public/__grimoire__/. sigil start runs the production server on the configured port. It builds first unless you pass --no-build, which is what you want when the build already happened, as it will in Docker.
The production server is a small coordinator that hands requests to worker processes. By default there's one worker, on the port after yours (3001 when you serve on 3000), and a crashed worker is restarted automatically. Deploying covers running more workers.
Open http://localhost:3000: it's the same app, minus the dev server's live reload.
Listen on every interface
The config listens on localhost by default, which is right on your machine and wrong in a container. Let the environment decide, in sigil.config.ts:
import type { GrimoireConfig } from "@sigil-dev/grimoire";
export default {
port: Number(process.env.PORT ?? 3000),
host: process.env.HOST ?? "localhost",
routes: "src/routes",
} satisfies GrimoireConfig;While you're there, let the database path come from the environment too, so a container can keep it on a volume. In src/lib/server/db.ts:
const db = new Database(process.env.DB_PATH ?? "books.sqlite", { create: true });Docker
Add a Dockerfile:
FROM oven/bun:1-alpine
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
COPY . .
RUN bun run build
ENV NODE_ENV=production HOST=0.0.0.0 DB_PATH=/data/books.sqlite
EXPOSE 3000
CMD ["bun", "run", "start", "--", "--no-build"]And a .dockerignore, so local build output and the database stay out of the image:
node_modules
.grimoire
public/__grimoire__
books.sqliteBuild and run it:
docker build -t reading-list .
docker run -p 3000:3000 -v reading-list-data:/data reading-listThe named volume keeps the database across container restarts. Put the container behind a reverse proxy that terminates TLS, and it's deployed.
Where to go next
You've now used most of Sigil. From here: