pnpm-hoist-layer v1.2.0
šŖ pnpm-hoist-layer
use .pnpmfile.cjs
to hoist deps/devDeps to project like
Nuxt Layer
Purpose
pnpm public-hoist-pattern only affects to the top-project (virtual store), not the sub-projects, therefore,
- relative path issues may occur
- copy same deps/devDeps from here to there
- config too many hoist-pattern
how to auto add the dep's deps/devDeps to my project? i.e. give your deps/devDeps to me when i deps on you.
e.g. mobile->common
, common->@nuxt
, after hoist layer,
āāā common
ā āāā node_modules
ā ā āāā @nuxt -> ../.pnpm/...
āāā mobile
āāā node_modules
ā āāā @fessional
ā ā āāā razor-common -> ../.pnpm/...
+ ā āāā @nuxt -> ../.pnpm/... // ā
hoist as layer
Mechanism
When using catalog
in pnpm-workspace.yaml
, it is not easy to manage
the dependencies via pnpm add
, the recommended practice is to manually
edit the catalog
and the package.json
, and then run pnpm i
to
install the update, at this point, the following happens to pnpm-hoist-layer.
- make a temporary directory(tmpDir), and write the
.pnpmfile.cjs
hook. - start the sub-process,
pnpm -r i --resolution-only --lockfile-dir=tmpDir
- sub-process quickly resolves packages related to hoistLayer
- top-process parse stdout of sub-process as hoistLayer metadata
- top-process merges hoistLayer metadata via hooks
the hoistLayer metadata is š hoist-layer.json
in the console,
[
{
"name": "hoist1",
"dependencies": {
"date-fns": "catalog:h1",
"lodash-es": "catalog:h1"
},
"devDependencies": {}
},
{
"name": "hoist2",
"dependencies": {
"date-fns": "catalog:h2",
"hoist1": "workspace:*",
"lodash-es": "catalog:h1"
},
"devDependencies": {},
"hoistLayer": [
"hoist1"
]
}
]
Usage
(1) add layer
to the package.json
hoistLayer
- to define which is the layer*dependencies
- for package resolution
"devDependencies": {
+ "@fessional/razor-common": "file:../common",
},
+ "hoistLayer": [
+ "@fessional/razor-common",
+ ]
(2) write .pnpmfile.cjs
to hook
## š¾ opt-1: project install and require
pnpm add -D pnpm-hoist-layer
cat > .pnpmfile.cjs << 'EOF'
module.exports = require('pnpm-hoist-layer');
EOF
## š¦ opt-2: write content to .pnpmfile.cjs
curl -o .pnpmfile.cjs https://raw.githubusercontent.com/trydofor\
/pnpm-hoist-layer/main/index.js
## š opt-3: global install and require
pnpm add -g pnpm-hoist-layer
cat > .pnpmfile.cjs << 'EOF'
module.exports = (() => {
try {
return require('pnpm-hoist-layer');
}
catch {
const gr = require('child_process').execSync('pnpm root -g').toString().trim();
return require(require('path').join(gr, 'pnpm-hoist-layer'));
}
})();
EOF
Known Issues
the deps tree are resolved from top to bottom, and hoist from bottom to top, it's a reverse process.
- ā shared-workspace-lockfile=false, may š peers
- ā monorepo + shared-workspace-lockfile=false, but š default=true
- ā
pnpm cli at top-dir, but š sub-dir (
packages/*
) - ā
--resolution-only
resolvedevDependencies
, but āpnpm i
NOT. - ā do NOT use
link:
, it do NOT hook - ā do NOT deps indirectly , 2+ level deps NOT resolved
- ā this is a bad practice
Useful Commands
## init workspace top-project first
pnpm -w i --ignore-pnpmfile
## init workspace sub-project
pnpm -r i
## to debug with env DEBUG != null
DEBUG=1 pnpm i
## ignore if error
pnpm i --ignore-pnpmfile --ignore-scripts
## asdf nodejs+pnpm, should disable corepack
export PNPM_HOME="$(asdf where pnpm)"
pnpm -g add pnpm-hoist-layer
## only corepack
corepack enable pnpm
corepack use pnpm@latest
Test and Diff
Glossary
āāā multi pkg, one git (often called "monorepo")
āĀ Ā āāā with workspace (termed as "mono")
āĀ Ā āāā without workspace (termed as "poly")
āāā one pkg, one git (termed as "solo")
node -v #v20.16.0
pnpm -v #9.12.1
pnpm test
# ā
Success mono1, npmrc={}
# ā
Success mono1, npmrc={"shared-workspace-lockfile":false}
# ā
Success mono2, npmrc={}
# ā
Success mono2, npmrc={"shared-workspace-lockfile":false}
# ā
Success poly1, npmrc={}
# ā
Success poly2, npmrc={}
# ā
Success hoist, npmrc={}
- hoist - hoist auto/manual testing
- mono1 - multi-pkg + workspace, sub
hoistLayer
- mono2 - multi-pkg + workspace, top
hoistLayer
- poly1 - multi-pkg, sub
hoistLayer
- poly2 - multi-pkg, top
hoistLayer
- solo - single pkg as deps for test
Mono before and after
diff mono
from pnpm -r i --ignore-pnpmfile
to pnpm -r i
like this,
## pnpm -r list
Legend: production dependency, optional only, dev only
mono-test-0@1.0.0 pnpm-hoist-layer/test/mono/packages/pkg0
+ dependencies:
+ solo-prd-dep link:../../solo/prd
= devDependencies:
= mono-test-1 link:../pkg1
+ mono-test-2 link:../pkg2
+ solo-dev-dep link:../../solo/dev
mono-test-1@1.0.0 pnpm-hoist-layer/test/mono/packages/pkg1
+ dependencies:
+ solo-prd-dep link:../../solo/prd
= devDependencies:
= mono-test-2 link:../pkg2
+ solo-dev-dep link:../../solo/dev
mono-test-2@1.0.0 pnpm-hoist-layer/test/mono/packages/pkg2
= dependencies:
= solo-prd-dep link:../../solo/prd
= devDependencies:
= solo-dev-dep link:../../solo/dev
## tree -L 4
ā
mono
= āāā node_modules
= āāā package.json
= āāā packages
= ā āāā pkg0
= ā ā āāā node_modules
= ā ā ā āāā mono-test-1 -> ../../../node_modules/.pnpm/
+ ā ā ā āāā mono-test-2 -> ../../pkg2
+ ā ā ā āāā solo-dev-dep -> ../../../solo/dev
+ ā ā ā āāā solo-prd-dep -> ../../../solo/prd
= ā ā āāā package.json
= ā āāā pkg1
= ā ā āāā node_modules
= ā ā ā āāā mono-test-2 -> ../../pkg2
+ ā ā ā āāā solo-dev-dep -> ../../../solo/dev
+ ā ā ā āāā solo-prd-dep -> ../../../solo/prd
= ā ā āāā package.json
= ā āāā pkg2
= ā āāā node_modules
= ā ā āāā solo-dev-dep -> ../../../solo/dev
= ā ā āāā solo-prd-dep -> ../../../solo/prd
= ā āāā package.json
= āāā pnpm-lock.yaml
= āāā pnpm-workspace.yaml
Poly before and after
diff poly
from pnpm -r i --ignore-pnpmfile
to pnpm -r i
like this,
## pnpm -r list
Legend: production dependency, optional only, dev only
poly-test-0@1.0.0 pnpm-hoist-layer/test/poly/packages/pkg0
+ dependencies:
+ solo-prd-dep link:../../solo/prd
= devDependencies:
= poly-test-1 file:../pkg1
+ poly-test-2 file:../pkg2
+ solo-dev-dep link:../../solo/dev
poly-test-1@1.0.0 pnpm-hoist-layer/test/poly/packages/pkg1
+ dependencies:
+ solo-prd-dep link:../../solo/prd
= devDependencies:
= poly-test-2 file:../pkg2
+ solo-dev-dep link:../../solo/dev
poly-test-2@1.0.0 pnpm-hoist-layer/test/poly/packages/pkg2
= dependencies:
= solo-prd-dep link:../../solo/prd
= devDependencies:
= solo-dev-dep link:../../solo/dev
## tree -L 4
ā
poly
= āāā package.json
= āāā packages
= ā āāā pkg0
= ā ā āāā node_modules
= ā ā ā āāā poly-test-1 -> .pnpm/
+ ā ā ā āāā poly-test-2 -> .pnpm/
+ ā ā ā āāā solo-dev-dep -> ../../../solo/dev
+ ā ā ā āāā solo-prd-dep -> ../../../solo/prd
= ā ā āāā package.json
= ā ā āāā pnpm-lock.yaml
= ā āāā pkg1
= ā ā āāā node_modules
= ā ā ā āāā poly-test-2 -> .pnpm/
+ ā ā ā āāā solo-dev-dep -> ../../../solo/dev
+ ā ā ā āāā solo-prd-dep -> ../../../solo/prd
= ā ā āāā package.json
= ā ā āāā pnpm-lock.yaml
= ā āāā pkg2
= ā āāā node_modules
= ā ā āāā solo-dev-dep -> ../../../solo/dev
= ā ā āāā solo-prd-dep -> ../../../solo/prd
= ā āāā package.json
= ā āāā pnpm-lock.yaml
= āāā pnpm-lock.yaml
6 months ago
9 months ago
9 months ago
9 months ago
9 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago