feat(pnpm): standardize store path and configuration (#569)

* test(node): add better-sqlite3 dependency and workspace config

Generated-by: aiautocommit

* docs: add readme for pnpm-corepack-runtime-usage example

Generated-by: aiautocommit

* feat(pnpm): standardize pnpm store path and configuration

* Move pnpm home to /opt/pnpm to follow standard Linux filesystem conventions.
* Explicitly configure PNPM_STORE_DIR to ensure cache consistency.
* Set PNPM environment variables during dependency installation to improve reliability.

Generated-by: aiautocommit

* chore: add node_modules cleanup to clean task

Generated-by: aiautocommit

* test: update build plan snapshots for pnpm path changes

Update snapshots to reflect the migration of the pnpm store and home directory to /opt/pnpm, ensuring consistent paths across build plans and environment variables.

Generated-by: aiautocommit
This commit is contained in:
Michael Bianco
2026-06-01 15:35:56 +02:00
committed by GitHub
parent 4caf8432c6
commit 7befea5ac8
17 changed files with 68 additions and 41 deletions
@@ -13,7 +13,7 @@
"type": "shared"
},
"pnpm-install": {
"directory": "/root/.local/share/pnpm/store/v3",
"directory": "/opt/pnpm/store",
"type": "shared"
}
},
@@ -112,7 +112,7 @@
"src": "pnpm-lock.yaml"
},
{
"path": "/pnpm"
"path": "/opt/pnpm"
},
{
"cmd": "pnpm add -g node-gyp"
@@ -133,7 +133,8 @@
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_PRODUCTION": "false",
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"PNPM_HOME": "/pnpm"
"PNPM_HOME": "/opt/pnpm",
"PNPM_STORE_DIR": "/opt/pnpm/store"
}
},
{
@@ -17,7 +17,7 @@
"type": "shared"
},
"pnpm-install": {
"directory": "/root/.local/share/pnpm/store/v3",
"directory": "/opt/pnpm/store",
"type": "shared"
}
},
@@ -117,7 +117,7 @@
"src": "pnpm-lock.yaml"
},
{
"path": "/pnpm"
"path": "/opt/pnpm"
},
{
"cmd": "pnpm add -g node-gyp"
@@ -139,7 +139,8 @@
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_PRODUCTION": "false",
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"PNPM_HOME": "/pnpm"
"PNPM_HOME": "/opt/pnpm",
"PNPM_STORE_DIR": "/opt/pnpm/store"
}
},
{
@@ -13,7 +13,7 @@
"type": "shared"
},
"pnpm-install": {
"directory": "/root/.local/share/pnpm/store/v3",
"directory": "/opt/pnpm/store",
"type": "shared"
}
},
@@ -138,7 +138,9 @@
"NODE_ENV": "production",
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_PRODUCTION": "false",
"NPM_CONFIG_UPDATE_NOTIFIER": "false"
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"PNPM_HOME": "/opt/pnpm",
"PNPM_STORE_DIR": "/opt/pnpm/store"
}
},
{
@@ -13,7 +13,7 @@
"type": "shared"
},
"pnpm-install": {
"directory": "/root/.local/share/pnpm/store/v3",
"directory": "/opt/pnpm/store",
"type": "shared"
}
},
@@ -120,7 +120,7 @@
"src": "pnpm-workspace.yaml"
},
{
"path": "/pnpm/bin"
"path": "/opt/pnpm/bin"
},
{
"cmd": "pnpm add -g node-gyp"
@@ -141,7 +141,8 @@
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_PRODUCTION": "false",
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"PNPM_HOME": "/pnpm"
"PNPM_HOME": "/opt/pnpm",
"PNPM_STORE_DIR": "/opt/pnpm/store"
}
},
{
@@ -13,7 +13,7 @@
"type": "shared"
},
"pnpm-install": {
"directory": "/root/.local/share/pnpm/store/v3",
"directory": "/opt/pnpm/store",
"type": "shared"
}
},
@@ -108,7 +108,7 @@
"src": "package.json"
},
{
"path": "/pnpm"
"path": "/opt/pnpm"
},
{
"cmd": "pnpm add -g node-gyp"
@@ -129,7 +129,8 @@
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_PRODUCTION": "false",
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"PNPM_HOME": "/pnpm"
"PNPM_HOME": "/opt/pnpm",
"PNPM_STORE_DIR": "/opt/pnpm/store"
}
},
{
@@ -13,7 +13,7 @@
"type": "shared"
},
"pnpm-install": {
"directory": "/root/.local/share/pnpm/store/v3",
"directory": "/opt/pnpm/store",
"type": "shared"
}
},
@@ -112,7 +112,7 @@
"src": "pnpm-lock.yaml"
},
{
"path": "/pnpm"
"path": "/opt/pnpm"
},
{
"cmd": "pnpm add -g node-gyp"
@@ -133,7 +133,8 @@
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_PRODUCTION": "false",
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"PNPM_HOME": "/pnpm"
"PNPM_HOME": "/opt/pnpm",
"PNPM_STORE_DIR": "/opt/pnpm/store"
}
},
{
@@ -13,7 +13,7 @@
"type": "shared"
},
"pnpm-install": {
"directory": "/root/.local/share/pnpm/store/v3",
"directory": "/opt/pnpm/store",
"type": "shared"
}
},
@@ -132,7 +132,7 @@
"src": "pnpm-workspace.yaml"
},
{
"path": "/pnpm"
"path": "/opt/pnpm"
},
{
"cmd": "pnpm add -g node-gyp"
@@ -153,7 +153,8 @@
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_PRODUCTION": "false",
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"PNPM_HOME": "/pnpm"
"PNPM_HOME": "/opt/pnpm",
"PNPM_STORE_DIR": "/opt/pnpm/store"
}
},
{
@@ -13,7 +13,7 @@
"type": "shared"
},
"pnpm-install": {
"directory": "/root/.local/share/pnpm/store/v3",
"directory": "/opt/pnpm/store",
"type": "shared"
}
},
@@ -103,7 +103,7 @@
"cmd": "mkdir -p /app/node_modules/.cache"
},
{
"path": "/pnpm"
"path": "/opt/pnpm"
},
{
"cmd": "pnpm add -g node-gyp"
@@ -130,7 +130,8 @@
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_PRODUCTION": "false",
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"PNPM_HOME": "/pnpm"
"PNPM_HOME": "/opt/pnpm",
"PNPM_STORE_DIR": "/opt/pnpm/store"
}
},
{
@@ -13,7 +13,7 @@
"type": "shared"
},
"pnpm-install": {
"directory": "/root/.local/share/pnpm/store/v3",
"directory": "/opt/pnpm/store",
"type": "shared"
},
"react-router": {
@@ -111,7 +111,7 @@
"src": "pnpm-lock.yaml"
},
{
"path": "/pnpm"
"path": "/opt/pnpm"
},
{
"cmd": "pnpm add -g node-gyp"
@@ -132,7 +132,8 @@
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_PRODUCTION": "false",
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"PNPM_HOME": "/pnpm"
"PNPM_HOME": "/opt/pnpm",
"PNPM_STORE_DIR": "/opt/pnpm/store"
}
},
{
@@ -13,7 +13,7 @@
"type": "shared"
},
"pnpm-install": {
"directory": "/root/.local/share/pnpm/store/v3",
"directory": "/opt/pnpm/store",
"type": "shared"
},
"react-router": {
@@ -120,7 +120,7 @@
"src": "pnpm-lock.yaml"
},
{
"path": "/pnpm"
"path": "/opt/pnpm"
},
{
"cmd": "pnpm add -g node-gyp"
@@ -141,7 +141,8 @@
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_PRODUCTION": "false",
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"PNPM_HOME": "/pnpm"
"PNPM_HOME": "/opt/pnpm",
"PNPM_STORE_DIR": "/opt/pnpm/store"
}
},
{
@@ -13,7 +13,7 @@
"type": "shared"
},
"pnpm-install": {
"directory": "/root/.local/share/pnpm/store/v3",
"directory": "/opt/pnpm/store",
"type": "shared"
},
"vite": {
@@ -107,7 +107,7 @@
"src": "pnpm-lock.yaml"
},
{
"path": "/pnpm"
"path": "/opt/pnpm"
},
{
"cmd": "pnpm add -g node-gyp"
@@ -128,7 +128,8 @@
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_PRODUCTION": "false",
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"PNPM_HOME": "/pnpm"
"PNPM_HOME": "/opt/pnpm",
"PNPM_STORE_DIR": "/opt/pnpm/store"
}
},
{
@@ -13,7 +13,7 @@
"type": "shared"
},
"pnpm-install": {
"directory": "/root/.local/share/pnpm/store/v3",
"directory": "/opt/pnpm/store",
"type": "shared"
}
},
@@ -118,6 +118,10 @@
"dest": "package.json",
"src": "package.json"
},
{
"dest": "pnpm-workspace.yaml",
"src": "pnpm-workspace.yaml"
},
{
"cmd": "pnpm install"
}
@@ -134,7 +138,9 @@
"NODE_ENV": "production",
"NPM_CONFIG_FUND": "false",
"NPM_CONFIG_PRODUCTION": "false",
"NPM_CONFIG_UPDATE_NOTIFIER": "false"
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
"PNPM_HOME": "/opt/pnpm",
"PNPM_STORE_DIR": "/opt/pnpm/store"
}
},
{
+8 -6
View File
@@ -20,7 +20,8 @@ const (
PackageManagerYarnBerry PackageManager = "yarnberry"
DEFAULT_PNPM_VERSION = "9"
PNPM_HOME = "/pnpm"
PNPM_HOME = "/opt/pnpm"
PNPM_STORE_DIR = PNPM_HOME + "/store"
)
func (p PackageManager) Name() string {
@@ -110,7 +111,7 @@ func (p PackageManager) GetInstallCache(ctx *generate.GenerateContext) string {
case PackageManagerNpm:
return ctx.Caches.AddCache("npm-install", "/root/.npm")
case PackageManagerPnpm:
return ctx.Caches.AddCache("pnpm-install", "/root/.local/share/pnpm/store/v3")
return ctx.Caches.AddCache("pnpm-install", PNPM_STORE_DIR)
case PackageManagerBun:
return ctx.Caches.AddCache("bun-install", "/root/.bun/install/cache")
case PackageManagerYarn1:
@@ -134,6 +135,11 @@ func (p PackageManager) installDeps(ctx *generate.GenerateContext, install *gene
install.AddCommand(plan.NewExecCommand("npm install"))
}
case PackageManagerPnpm:
install.AddEnvVars(map[string]string{
"PNPM_HOME": PNPM_HOME,
"PNPM_STORE_DIR": PNPM_STORE_DIR,
})
// pnpm (standalone) does not bundle node-gyp like npm does, so we must install it globally
// to support packages with native dependencies (e.g., better-sqlite3, bcrypt, etc.)
// Only needed when using mise to install pnpm (not corepack, which includes node-gyp)
@@ -145,10 +151,6 @@ func (p PackageManager) installDeps(ctx *generate.GenerateContext, install *gene
pnpmBinPath = PNPM_HOME + "/bin"
}
// Set PNPM_HOME so pnpm can create a global bin directory for node-gyp
install.AddEnvVars(map[string]string{
"PNPM_HOME": PNPM_HOME,
})
// binaries are installed in the /bin subpath. If this is not added to PATH `pnpm add -g` will fail
install.AddPaths([]string{pnpmBinPath})
install.AddCommand(plan.NewExecCommand("pnpm add -g node-gyp"))
@@ -0,0 +1 @@
lockfile is intentionally omitted to test the pnpm detection without lockfile + mise config
@@ -7,6 +7,9 @@
"start": "node main.js"
},
"packageManager": "[email protected]",
"dependencies": {
"better-sqlite3": ">=12"
},
"engines": {
"node": "^26.0.0"
}
@@ -0,0 +1,2 @@
allowBuilds:
better-sqlite3: true
+2 -1
View File
@@ -40,6 +40,7 @@ run = "go build -o bin/railpack cmd/cli/main.go"
[tasks.clean]
run = [
"rm -rf bin dist docs/dist",
"find . -type d -name node_modules -prune -exec rm -rf {} +",
# clean up buildkit cache, avoids cached layers from being used
"docker exec buildkit buildctl prune",
"rm -f *.test",
@@ -147,4 +148,4 @@ description = "Shell into the published railpack-builder image"
run = "docker run -it --rm ghcr.io/railwayapp/railpack-builder:mise-$RAILPACK_MISE_VERSION bash"
[tasks.image-runtime-build]
run = "docker build -f images/debian/runtime/Dockerfile -t railpack-runtime:local ."
run = "docker build -f images/debian/runtime/Dockerfile -t railpack-runtime:local ."