mirror of
https://github.com/pnpm/pnpm.git
synced 2026-03-24 01:51:41 -04:00
27
README.md
27
README.md
@@ -27,6 +27,7 @@ Like this project? Let people know with a [tweet](https://bit.ly/tweet-pnpm).
|
||||
* [Install](#install)
|
||||
* [Usage](#usage)
|
||||
* [Configuring](#configuring)
|
||||
* [Hooks](#hooks)
|
||||
* [Benchmark](#benchmark)
|
||||
* [Limitations](#limitations)
|
||||
* [Frequently Asked Questions](#frequently-asked-questions)
|
||||
@@ -144,6 +145,32 @@ that rely on location but gives an average of **8% installation speed improvemen
|
||||
|
||||
If false, doesn't check whether packages in the store were mutated.
|
||||
|
||||
### Hooks
|
||||
|
||||
pnpm allows to step directly into the installation process via special functions called *hooks*.
|
||||
Hooks can be declared in a file called `pnpmfile.js`. `pnpmfile.js` should live in the root of the project.
|
||||
|
||||
An example of a `pnpmfile.js` that changes the dependencies field of a dependency:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
hooks: {
|
||||
readPackage
|
||||
}
|
||||
}
|
||||
|
||||
// This hook will override the manifest of foo@1 after downloading it from the registry
|
||||
// foo@1 will always be installed with the second version of bar
|
||||
function readPackage (pkg) {
|
||||
if (pkg.name === 'foo' && pkg.version.startsWith('1.')) {
|
||||
pkg.dependencies = {
|
||||
bar: '^2.0.0'
|
||||
}
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
```
|
||||
|
||||
## Benchmark
|
||||
|
||||
pnpm is faster than npm and Yarn. See [this](https://github.com/zkochan/node-package-manager-benchmark)
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
"pnpm-list": "^1.0.0",
|
||||
"pnpm-logger": "^0.5.4",
|
||||
"ramda": "^0.24.1",
|
||||
"supi": "^0.2.16",
|
||||
"supi": "^0.2.17",
|
||||
"update-notifier": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -24,7 +24,7 @@ dependencies:
|
||||
pnpm-logger: 0.5.4
|
||||
ramda: 0.24.1
|
||||
rimraf: 2.6.1
|
||||
supi: 0.2.16
|
||||
supi: 0.2.17
|
||||
update-notifier: 2.2.0
|
||||
devDependencies:
|
||||
'@types/mkdirp': 0.5.1
|
||||
@@ -2234,7 +2234,7 @@ packages:
|
||||
/strip-json-comments/2.0.1:
|
||||
resolution:
|
||||
integrity: sha1-PFMZQukIwml8DsNEhYwobHygpgo=
|
||||
/supi/0.2.16:
|
||||
/supi/0.2.17:
|
||||
dependencies:
|
||||
'@types/byline': 4.2.31
|
||||
'@types/common-tags': 1.2.5
|
||||
@@ -2292,7 +2292,7 @@ packages:
|
||||
write-pkg: 3.1.0
|
||||
write-yaml-file: 1.0.0
|
||||
resolution:
|
||||
integrity: sha512-BKYNiwcn9LeMczysq2CoyDK1IWNBD+ar0oFDZ3hHZSu70jjNyQaErz09FzELvXH1cc29Ekm5i/SL8PSmp+dNjA==
|
||||
integrity: sha512-vnfuOLiCHw4XxhG6fnyxo2oF/ly0U9LT/+y8d0IDSA+eukJGw6AhUsVEZhFdXh07txMRK2QFSMGFT4622YMYew==
|
||||
/supports-color/2.0.0:
|
||||
resolution:
|
||||
integrity: sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
|
||||
@@ -2609,7 +2609,7 @@ specifiers:
|
||||
pnpm-logger: ^0.5.4
|
||||
ramda: ^0.24.1
|
||||
rimraf: ^2.5.4
|
||||
supi: ^0.2.16
|
||||
supi: ^0.2.17
|
||||
tslint: ^5.4.2
|
||||
typescript: ^2.4.1
|
||||
update-notifier: ^2.1.0
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import {install, installPkgs, PnpmOptions} from 'supi'
|
||||
import path = require('path')
|
||||
import logger from 'pnpm-logger'
|
||||
|
||||
/**
|
||||
* Perform installation.
|
||||
@@ -9,8 +11,30 @@ export default function installCmd (input: string[], opts: PnpmOptions) {
|
||||
// `pnpm install ""` is going to be just `pnpm install`
|
||||
input = input.filter(Boolean)
|
||||
|
||||
const prefix = opts.prefix || process.cwd()
|
||||
opts['hooks'] = requireHooks(prefix)
|
||||
|
||||
if (!input || !input.length) {
|
||||
return install(opts)
|
||||
}
|
||||
return installPkgs(input, opts)
|
||||
}
|
||||
|
||||
function requireHooks (prefix: string) {
|
||||
try {
|
||||
const pnpmFilePath = path.join(prefix, 'pnpmfile.js')
|
||||
const pnpmFile = require(pnpmFilePath)
|
||||
const hooks = pnpmFile && pnpmFile.hooks
|
||||
if (!hooks) return {}
|
||||
if (hooks.readPackage) {
|
||||
if (typeof hooks.readPackage !== 'function') {
|
||||
throw new TypeError('hooks.readPackage should be a function')
|
||||
}
|
||||
logger.info('readPackage hook is declared. Manifests of dependencies might get overridden')
|
||||
}
|
||||
return hooks
|
||||
} catch (err) {
|
||||
if (err['code'] !== 'MODULE_NOT_FOUND') throw err
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
35
test/install/hooks.ts
Normal file
35
test/install/hooks.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import tape = require('tape')
|
||||
import promisifyTape from 'tape-promise'
|
||||
import {
|
||||
prepare,
|
||||
addDistTag,
|
||||
execPnpm
|
||||
} from '../utils'
|
||||
import fs = require('mz/fs')
|
||||
|
||||
const test = promisifyTape(tape)
|
||||
|
||||
test('readPackage hook', async (t: tape.Test) => {
|
||||
const project = prepare(t)
|
||||
|
||||
await fs.writeFile('pnpmfile.js', `
|
||||
'use strict'
|
||||
module.exports = {
|
||||
hooks: {
|
||||
readPackage (pkg) {
|
||||
if (pkg.name === 'pkg-with-1-dep') {
|
||||
pkg.dependencies['dep-of-pkg-with-1-dep'] = '100.0.0'
|
||||
}
|
||||
return pkg
|
||||
}
|
||||
}
|
||||
}
|
||||
`, 'utf8')
|
||||
|
||||
// w/o the hook, 100.1.0 would be installed
|
||||
await addDistTag('dep-of-pkg-with-1-dep', '100.1.0', 'latest')
|
||||
|
||||
await execPnpm('install', 'pkg-with-1-dep')
|
||||
|
||||
await project.storeHas('dep-of-pkg-with-1-dep', '100.0.0')
|
||||
})
|
||||
@@ -1,2 +1,3 @@
|
||||
import './misc'
|
||||
import './lifecycleScripts'
|
||||
import './hooks'
|
||||
|
||||
Reference in New Issue
Block a user