mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 08:13:50 +00:00
Every plugin iframe loaded /plugin-sandbox, a force-dynamic Next page. Each frame then fetched, parsed and hydrated Next's client router on top of React and the runtime, and the server rendered the page once per frame, one after another when a dozen plugins started together. Sandboxed frames have opaque origins, so the browser's code cache never helps, and they run on the host page's main thread: with 12 plugins the frames took 2.5-3 s to come up after the app had loaded. The sandbox routes now return a small HTML page with the UI kit's stylesheet and the runtime as an ES module, both built ahead of time: - `scripts/build-plugin-sandbox.mjs` bundles the runtime with esbuild and compiles `plugin-kit.css` with the app's Tailwind setup into `public/plugin-sandbox-assets/`, with a manifest. Named Tabler imports are pointed at the icons' own files, so the full icon set stays in a chunk that only loads for an icon name the kit doesn't ship. - `npm run build`, `npm run dev`, the Dockerfile and the perf-guard workflow run it before `next build`. - `lib/plugin-sandbox/sandbox-document.ts` writes the page; proxy.ts still sets the sandbox CSP and the script carries its nonce. - The assets are served from public/ with CORS and immutable caching. A frame on an idle page is ready in 255 ms instead of 362 ms, eleven at once in 1.0 s instead of 2.1 s.
62 lines
2.7 KiB
Docker
62 lines
2.7 KiB
Docker
FROM node:24-alpine AS builder
|
|
WORKDIR /app
|
|
COPY package.json package-lock.json ./
|
|
RUN npm ci
|
|
COPY . .
|
|
ENV NEXT_TELEMETRY_DISABLED=1
|
|
# Optional: serve under a subpath like /webmail. Baked into emitted asset URLs
|
|
# at build time, so it cannot be changed without rebuilding.
|
|
ARG NEXT_PUBLIC_BASE_PATH=
|
|
ENV NEXT_PUBLIC_BASE_PATH=$NEXT_PUBLIC_BASE_PATH
|
|
# Optional: avoid next-intl rewrite loops when served under a subpath.
|
|
# Baked in at build time.
|
|
ARG NEXT_PUBLIC_LOCALE_PREFIX=
|
|
ENV NEXT_PUBLIC_LOCALE_PREFIX=$NEXT_PUBLIC_LOCALE_PREFIX
|
|
# Optional: fallback UI locale (e.g. tr, de, fr) used when the visitor's
|
|
# Accept-Language header does not match any supported locale. Baked in at
|
|
# build time because next-intl wires it into client-side routing too.
|
|
ARG NEXT_PUBLIC_DEFAULT_LOCALE=
|
|
ENV NEXT_PUBLIC_DEFAULT_LOCALE=$NEXT_PUBLIC_DEFAULT_LOCALE
|
|
# Commit SHA shown in the About screen. .dockerignore excludes .git, so
|
|
# `git rev-parse` inside the build can't find it - CI must pass it in.
|
|
ARG GIT_COMMIT=unknown
|
|
ENV GIT_COMMIT=$GIT_COMMIT
|
|
# The mock JMAP server (DEV_MOCK_JMAP) accepts any password and is for
|
|
# `npm run dev` only; images ship without it.
|
|
# `next build` type-checks every .ts file, and some unit tests import the
|
|
# deleted route, so the tests go too. .dockerignore already drops them from a
|
|
# local context, but a remote Git context never applies .dockerignore (#1118).
|
|
RUN rm -rf "app/api/dev-jmap" && \
|
|
find . -path ./node_modules -prune -o \
|
|
\( -name __tests__ -o -name "*.test.ts" -o -name "*.test.tsx" \) \
|
|
-prune -exec rm -rf {} \; && \
|
|
node scripts/build-plugin-sandbox.mjs && \
|
|
npx next build --webpack
|
|
|
|
FROM node:24-alpine AS runner
|
|
|
|
LABEL org.opencontainers.image.title="Bulwark Webmail"
|
|
LABEL org.opencontainers.image.description="Modern webmail client built with Next.js and the JMAP protocol"
|
|
LABEL org.opencontainers.image.source="https://github.com/bulwarkmail/webmail"
|
|
LABEL org.opencontainers.image.url="https://github.com/bulwarkmail/webmail"
|
|
LABEL org.opencontainers.image.licenses="AGPL-3.0-only"
|
|
LABEL org.opencontainers.image.vendor="rbm.systems"
|
|
|
|
WORKDIR /app
|
|
ENV NODE_ENV=production
|
|
ENV NEXT_TELEMETRY_DISABLED=1
|
|
RUN apk upgrade --no-cache && \
|
|
npm uninstall -g npm && \
|
|
rm -rf /usr/local/lib/node_modules/npm /usr/local/bin/npx && \
|
|
addgroup --system --gid 1001 nodejs && \
|
|
adduser --system --uid 1001 nextjs
|
|
COPY --from=builder /app/public ./public
|
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
|
RUN mkdir -p /app/data/settings /app/data/admin /app/data/admin-state /app/data/telemetry && chown -R nextjs:nodejs /app/data
|
|
USER nextjs
|
|
EXPOSE 3000
|
|
ENV PORT=3000
|
|
ENV HOSTNAME="0.0.0.0"
|
|
CMD ["node", "server.js"]
|