build: speed up task runner deployment

This commit is contained in:
Declan Carroll 2026-09-04 14:12:54 +01:00
parent fcabdcae3c
commit 57ffd26d2c
5 changed files with 10 additions and 49 deletions

View File

@ -10,34 +10,23 @@ COPY ./dist/task-runner-javascript /app/task-runner-javascript
WORKDIR /app/task-runner-javascript
# Pin pnpm to the repo's packageManager version. `pnpm deploy` drops the
# packageManager field from the deployed package.json, so nothing else here pins it.
ARG PNPM_VERSION
RUN npm i -g "pnpm@${PNPM_VERSION}"
# Remove `catalog` and `workspace` references from package.json to allow `pnpm add` in extended images
# Remove workspace-only references from package.json to allow `pnpm add` in extended images.
RUN node -e "const pkg = require('./package.json'); \
Object.keys(pkg.dependencies || {}).forEach(k => { \
const val = pkg.dependencies[k]; \
if (val === 'catalog:' || val.startsWith('catalog:') || val.startsWith('workspace:')) \
if (val === 'catalog:' || val.startsWith('catalog:') || val.startsWith('workspace:') || val.startsWith('file:') || val.includes('@file:')) \
delete pkg.dependencies[k]; \
}); \
Object.keys(pkg.devDependencies || {}).forEach(k => { \
const val = pkg.devDependencies[k]; \
if (val === 'catalog:' || val.startsWith('catalog:') || val.startsWith('workspace:')) \
if (val === 'catalog:' || val.startsWith('catalog:') || val.startsWith('workspace:') || val.startsWith('file:') || val.includes('@file:')) \
delete pkg.devDependencies[k]; \
}); \
delete pkg.devDependencies; \
require('fs').writeFileSync('./package.json', JSON.stringify(pkg, null, 2));"
# `--config.minimum-release-age=0`: pnpm 11 defaults it to 1440 (24h), which would make
# this reject any dependency published less than a day ago — e.g. a first-party
# @n8n_io/ai-assistant-sdk bump landed within hours of its npm publish. This step only
# re-resolves an already-vetted, already-pinned dependency set; the real supply-chain age
# policy is enforced by the host install (pnpm-workspace.yaml + SafeChain).
# Install moment (special case for backwards compatibility)
RUN rm -f node_modules/.modules.yaml && \
pnpm add moment@2.30.1 --prod --no-lockfile --config.minimum-release-age=0
# Remove deploy metadata that points to workspace-only settings and patch files.
RUN rm -f pnpm-lock.yaml node_modules/.modules.yaml node_modules/.pnpm/lock.yaml node_modules/.pnpm-workspace-state-v1.json
# ==============================================================================
# STAGE 2: Python runner build (@n8n/task-runner-python) with uv

View File

@ -13,7 +13,6 @@
# ==============================================================================
ARG NODE_VERSION=26.7.0
ARG PNPM_VERSION=11.25.0
ARG PYTHON_VERSION=3.13
@ -23,37 +22,6 @@ ARG PYTHON_VERSION=3.13
FROM node:${NODE_VERSION}-bookworm-slim AS javascript-runner-builder
COPY ./dist/task-runner-javascript /app/task-runner-javascript
WORKDIR /app/task-runner-javascript
# Pin pnpm to the repo's packageManager version. `pnpm deploy` drops the
# packageManager field from the deployed package.json, so nothing else here pins it.
ARG PNPM_VERSION
RUN npm i -g "pnpm@${PNPM_VERSION}"
# Remove `catalog` and `workspace` references from package.json to allow `pnpm add`
RUN node -e "const pkg = require('./package.json'); \
Object.keys(pkg.dependencies || {}).forEach(k => { \
const val = pkg.dependencies[k]; \
if (val === 'catalog:' || val.startsWith('catalog:') || val.startsWith('workspace:')) \
delete pkg.dependencies[k]; \
}); \
Object.keys(pkg.devDependencies || {}).forEach(k => { \
const val = pkg.devDependencies[k]; \
if (val === 'catalog:' || val.startsWith('catalog:') || val.startsWith('workspace:')) \
delete pkg.devDependencies[k]; \
}); \
delete pkg.devDependencies; \
require('fs').writeFileSync('./package.json', JSON.stringify(pkg, null, 2));"
# `--config.minimum-release-age=0`: pnpm 11 defaults it to 1440 (24h), which would make
# this reject any dependency published less than a day ago — e.g. a first-party
# @n8n_io/ai-assistant-sdk bump landed within hours of its npm publish. This step only
# re-resolves an already-vetted, already-pinned dependency set; the real supply-chain age
# policy is enforced by the host install (pnpm-workspace.yaml + SafeChain).
# Install moment by default (special case for n8n cloud)
RUN rm -f node_modules/.modules.yaml && \
pnpm add moment@2.30.1 --prod --no-lockfile --config.minimum-release-age=0
# Rebuild isolated-vm for the container platform. Install build tools as
# fallback in case prebuild-install cannot find a prebuilt binary.
RUN apt-get update && apt-get install -y --no-install-recommends python3 make g++ && \

View File

@ -47,6 +47,7 @@
"acorn-walk": "8.3.4",
"lodash": "catalog:",
"luxon": "catalog:",
"moment": "2.30.1",
"n8n-core": "workspace:*",
"n8n-workflow": "workspace:*",
"nanoid": "catalog:",

View File

@ -3784,6 +3784,9 @@ importers:
luxon:
specifier: 'catalog:'
version: 3.7.2
moment:
specifier: 2.30.1
version: 2.30.1
n8n-core:
specifier: workspace:*
version: link:../../core

View File

@ -423,7 +423,7 @@ try {
// orders of magnitude smaller than the n8n one, so the strips above are not
// worth duplicating here — the closure figure they report covers the n8n image
// only, not the shipped total.
await $`cd ${config.rootDir} && NODE_ENV=production DOCKER_BUILD=true pnpm --filter=@n8n/task-runner --prod --legacy deploy --no-optional ${config.compiledTaskRunnerDir}`;
await $`cd ${config.rootDir} && NODE_ENV=production DOCKER_BUILD=true pnpm --filter=@n8n/task-runner --prod --config.inject-workspace-packages=true deploy --no-optional ${config.compiledTaskRunnerDir}`;
// Check the production closure for single-instance dependency duplication. A curated
// library resolving to more than one physical copy silently breaks instanceof /