A previous packaged .app under dist-electron-builds/ carries its own
data/ tree, and output tracing tried to copy pieces of the OLD app into
the NEW standalone output during dist:mac ("Failed to copy traced
files..." warnings). Zero bytes actually leaked (the copies ENOENT'd),
but the failure mode — yesterday's build inside today's artifact — is
bad enough to fence off explicitly, same as ./repos already was.
87 lines
3.6 KiB
TypeScript
87 lines
3.6 KiB
TypeScript
import type { NextConfig } from "next";
|
|
import createNextIntlPlugin from "next-intl/plugin";
|
|
import { execSync } from "child_process";
|
|
import { readFileSync } from "fs";
|
|
import { join } from "path";
|
|
|
|
// Prefer an explicit build arg (passed in by CI / Docker, where .git is
|
|
// excluded from the build context) and fall back to `git rev-parse` for
|
|
// local builds.
|
|
let gitCommitHash = process.env.GIT_COMMIT?.trim() || "";
|
|
if (!gitCommitHash) {
|
|
try {
|
|
gitCommitHash = execSync("git rev-parse --short HEAD").toString().trim();
|
|
} catch {
|
|
gitCommitHash = "unknown";
|
|
}
|
|
}
|
|
// Normalise full 40-char SHAs (e.g. ${{ github.sha }}) to the short form.
|
|
if (/^[0-9a-f]{40}$/i.test(gitCommitHash)) {
|
|
gitCommitHash = gitCommitHash.slice(0, 7);
|
|
}
|
|
|
|
let appVersion = "0.0.0";
|
|
try {
|
|
appVersion = readFileSync(join(import.meta.dirname, "VERSION"), "utf-8").trim();
|
|
} catch {
|
|
// VERSION file not found
|
|
}
|
|
|
|
// Subpath deployment, e.g. NEXT_PUBLIC_BASE_PATH=/webmail. Read at build time
|
|
// because Next.js bakes basePath into emitted asset URLs and route metadata.
|
|
// Trailing slash is stripped; an empty/missing value disables the feature.
|
|
const rawBasePath = process.env.NEXT_PUBLIC_BASE_PATH?.trim() ?? "";
|
|
const basePath = rawBasePath.replace(/\/+$/, "");
|
|
if (basePath && !basePath.startsWith("/")) {
|
|
throw new Error(
|
|
`NEXT_PUBLIC_BASE_PATH must start with "/" (got: ${JSON.stringify(rawBasePath)})`
|
|
);
|
|
}
|
|
|
|
const nextConfig: NextConfig = {
|
|
output: "standalone",
|
|
// 127.0.0.1 alongside the existing LAN entry: electron/main.ts always
|
|
// loads its window at 127.0.0.1 (see ELECTRON_LOAD_URL and
|
|
// startStandaloneServer()), so dev-mode Electron runs (only used by
|
|
// integration/tests/11-electron-notification.spec.ts today) need it in
|
|
// this allowlist the same way any other cross-origin dev client would.
|
|
allowedDevOrigins: ["192.168.1.51", "127.0.0.1"],
|
|
basePath: basePath || undefined,
|
|
// esbuild ships native binaries + a README the bundler can't parse; load
|
|
// it from node_modules at runtime instead of trying to bundle it. Used by
|
|
// PLUGIN_DEV_DIR's on-the-fly bundler.
|
|
//
|
|
// @signalapp/sqlcipher is a native N-API addon resolved at runtime by
|
|
// node-gyp-build (a directory scan of prebuilds/), which a bundler cannot
|
|
// follow. It is also an OPTIONAL dependency - absent on musl/Alpine, where
|
|
// both Dockerfiles build - so it must never be a hard build-time import.
|
|
// lib/mail-index/binding.ts guards the require; this keeps webpack from
|
|
// trying to resolve it at all.
|
|
serverExternalPackages: ["esbuild", "@signalapp/sqlcipher"],
|
|
// Sibling repos checked out under ./repos/ are unrelated source trees that
|
|
// Turbopack's NFT can otherwise rope into the trace when dynamic fs calls
|
|
// confuse it. Keeps the build from ballooning memory tracing dead code.
|
|
//
|
|
// dist-electron-builds/ is the OUTPUT of electron-builder — a previous
|
|
// packaged .app sitting there contains its own data/ tree, and tracing
|
|
// once tried to copy pieces of the old app into the new standalone output
|
|
// ("Failed to copy traced files ... dist-electron-builds/..." warnings,
|
|
// observed 2026-08-06). Same reasoning for ./data/, a dev-run server's
|
|
// local state dir.
|
|
outputFileTracingExcludes: {
|
|
"*": ["./repos/**/*", "./dist-electron-builds/**/*", "./data/**/*"],
|
|
},
|
|
turbopack: {
|
|
root: import.meta.dirname,
|
|
},
|
|
env: {
|
|
NEXT_PUBLIC_GIT_COMMIT: gitCommitHash,
|
|
NEXT_PUBLIC_APP_VERSION: appVersion,
|
|
NEXT_PUBLIC_BASE_PATH: basePath,
|
|
NEXT_PUBLIC_DEV_MOCK_JMAP: process.env.DEV_MOCK_JMAP ?? "",
|
|
},
|
|
};
|
|
|
|
const withNextIntl = createNextIntlPlugin();
|
|
export default withNextIntl(nextConfig);
|