Skip to content

Commit b438c07

Browse files
JohnMcLearclaude
andcommitted
build(deb): ship production deps only to keep the package under GitHub's 100 MB limit
The staging step copied the whole workspace node_modules into the .deb, so it shipped every devDependency plus the admin/ui/doc dependency trees. The 3.3.14 amd64 package hit 101 MiB and apt-publish was rejected by GitHub's 100 MiB file limit. Move staging into packaging/stage.sh and install a fresh `pnpm install --prod --frozen-lockfile` for root, src and bin. The build-only importers are dropped from the staged lockfile, since pnpm otherwise installs their deps too. Also drop src/tests and the playwright/vitest configs. amd64 goes from 101 MiB to 46 MiB. Add a CI step that fails the build if a .deb is over 95 MiB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TcYAoEw35xr1qP19ipr25W
1 parent 2f97851 commit b438c07

4 files changed

Lines changed: 77 additions & 36 deletions

File tree

‎.github/workflows/deb-package.yml‎

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -108,30 +108,8 @@ jobs:
108108
sudo dpkg -i "/tmp/${NFPM_DEB}"
109109
110110
- name: Stage tree for packaging
111-
run: |
112-
set -eux
113-
STAGE=staging/opt/etherpad
114-
mkdir -p "${STAGE}"
115-
116-
# Production footprint = src/ + bin/ + node_modules/ + metadata.
117-
cp -a src bin package.json pnpm-workspace.yaml README.md LICENSE \
118-
node_modules "${STAGE}/"
119-
120-
# Make pnpm-workspace.yaml production-only (same trick Dockerfile uses).
121-
printf 'packages:\n - src\n - bin\n' > "${STAGE}/pnpm-workspace.yaml"
122-
123-
mkdir -p packaging/etc
124-
cp settings.json.template packaging/etc/settings.json.dist
125-
126-
# Purge test fixtures and dev caches from node_modules to shrink size.
127-
find "${STAGE}/node_modules" -type d \
128-
\( -name test -o -name tests -o -name '__tests__' \
129-
-o -name example -o -name examples -o -name docs \) \
130-
-prune -exec rm -rf {} + 2>/dev/null || true
131-
find "${STAGE}/node_modules" -type f \
132-
\( -name '*.md' -o -name '*.ts.map' -o -name '*.map' \
133-
-o -name 'CHANGELOG*' -o -name 'HISTORY*' \) \
134-
-delete 2>/dev/null || true
111+
# Production deps only; see packaging/stage.sh.
112+
run: packaging/stage.sh
135113

136114
- name: Build .deb
137115
env:
@@ -141,6 +119,22 @@ jobs:
141119
mkdir -p dist
142120
nfpm package --packager deb -f packaging/nfpm.yaml --target dist/
143121
122+
- name: Check package size
123+
# apt-publish commits the .deb into ether/ether.github.com, and GitHub
124+
# rejects files over 100 MiB. Fail here, with some headroom, so a
125+
# size regression shows up on the PR instead of at release time.
126+
run: |
127+
set -euo pipefail
128+
LIMIT=$((95 * 1024 * 1024))
129+
for f in dist/*.deb; do
130+
size=$(stat -c %s "$f")
131+
echo "$f: $((size / 1024 / 1024)) MiB ($size bytes)"
132+
if [ "$size" -gt "$LIMIT" ]; then
133+
echo "::error file=$f::$f is over 95 MiB; GitHub rejects files over 100 MiB in the apt repo"
134+
exit 1
135+
fi
136+
done
137+
144138
- name: Smoke-test the package (amd64 only)
145139
if: matrix.arch == 'amd64'
146140
run: |

‎packaging/README.md‎

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,8 @@ Prereqs: Node 24 (current LTS; matches `engines.node` floor), pnpm 12+, nfpm.
2525
pnpm install --frozen-lockfile
2626
pnpm run build:etherpad
2727

28-
# Stage the tree the way CI does:
29-
STAGE=staging/opt/etherpad
30-
mkdir -p "$STAGE"
31-
cp -a src bin package.json pnpm-workspace.yaml README.md LICENSE \
32-
node_modules "$STAGE/"
33-
printf 'packages:\n - src\n - bin\n' > "$STAGE/pnpm-workspace.yaml"
34-
cp settings.json.template packaging/etc/settings.json.dist
28+
# Stage the tree the way CI does (production deps only):
29+
packaging/stage.sh
3530

3631
VERSION=$(node -p "require('./package.json').version") \
3732
ARCH=amd64 \

‎packaging/stage.sh‎

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env bash
2+
# Stage the production tree for nfpm under staging/opt/etherpad.
3+
# Run from the repo root after `pnpm install` and `pnpm run build:etherpad`.
4+
# Used by .github/workflows/deb-package.yml and packaging/test-local.sh.
5+
set -euxo pipefail
6+
7+
cd "$(dirname "$0")/.."
8+
9+
STAGE=staging/opt/etherpad
10+
rm -rf staging
11+
mkdir -p "${STAGE}"
12+
13+
# Production footprint = src/ + bin/ + metadata, plus a fresh
14+
# production-only node_modules installed below. src/ already holds the
15+
# admin + oidc builds from `build:etherpad`. Copying the workspace
16+
# node_modules used to ship every devDependency (typescript, playwright,
17+
# vitest, eslint, vite, ...) and the admin/ui/doc dependency trees, which
18+
# pushed the .deb past GitHub's 100 MiB per-file limit for the apt repo.
19+
cp -a src bin package.json pnpm-lock.yaml README.md LICENSE "${STAGE}/"
20+
rm -rf "${STAGE}/src/node_modules" "${STAGE}/bin/node_modules" \
21+
"${STAGE}/src/tests" "${STAGE}/src/playwright.config.ts" \
22+
"${STAGE}/src/vitest.config.ts"
23+
24+
# Install production deps for the runtime workspace (root, src, bin) from
25+
# the lockfile. pnpm installs the dependencies of every importer listed in
26+
# the lockfile, even if its directory is missing, so drop the build-only
27+
# importers from the staged lockfile and workspace file. Everything else
28+
# (overrides, build policy) stays as-is so --frozen-lockfile still matches.
29+
BUILD_ONLY='admin|doc|ui|admin/tools/openapi-codegen'
30+
awk -v re="^ (${BUILD_ONLY}):\$" '
31+
/^importers:/ { imp = 1; print; next }
32+
imp && /^[^ ]/ { imp = 0; skip = 0 }
33+
imp && /^ [^ ]/ { skip = ($0 ~ re) }
34+
!skip { print }
35+
' pnpm-lock.yaml > "${STAGE}/pnpm-lock.yaml"
36+
grep -Ev "^ - (${BUILD_ONLY})\$" pnpm-workspace.yaml > "${STAGE}/pnpm-workspace.yaml"
37+
( cd "${STAGE}" && CI=1 pnpm install --prod --frozen-lockfile )
38+
39+
# Ship the same minimal workspace file as before (same trick the
40+
# Dockerfile uses) and no lockfile.
41+
printf 'packages:\n - src\n - bin\n' > "${STAGE}/pnpm-workspace.yaml"
42+
rm -f "${STAGE}/pnpm-lock.yaml"
43+
44+
mkdir -p packaging/etc
45+
cp settings.json.template packaging/etc/settings.json.dist
46+
47+
# Purge test fixtures and docs from node_modules to shrink size.
48+
find "${STAGE}/node_modules" -type d \
49+
\( -name test -o -name tests -o -name '__tests__' \
50+
-o -name example -o -name examples -o -name docs \) \
51+
-prune -exec rm -rf {} + 2>/dev/null || true
52+
find "${STAGE}/node_modules" -type f \
53+
\( -name '*.md' -o -name '*.ts.map' -o -name '*.map' \
54+
-o -name 'CHANGELOG*' -o -name 'HISTORY*' \) \
55+
-delete 2>/dev/null || true

‎packaging/test-local.sh‎

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,8 @@ CI=1 pnpm install --frozen-lockfile
3636

3737
echo "==> Building staging tree"
3838
rm -rf staging dist packaging/etc
39-
mkdir -p staging/opt/etherpad packaging/etc dist
40-
cp -a src bin package.json pnpm-workspace.yaml README.md LICENSE node_modules \
41-
staging/opt/etherpad/
42-
printf 'packages:\n - src\n - bin\n' > staging/opt/etherpad/pnpm-workspace.yaml
43-
cp settings.json.template packaging/etc/settings.json.dist
39+
mkdir -p dist
40+
packaging/stage.sh
4441

4542
echo "==> Building .deb via nfpm ${NFPM_VERSION} (in container)"
4643
VERSION="$(node -p 'require("./package.json").version')"

0 commit comments

Comments
 (0)