mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
feat: ignoring the build of specific dependencies (#3080)
* feat: ignoring the build of specific dependencies close #3071 * test: add test for neverBuiltDependencies * docs: add changesets * test: lockfile-file
This commit is contained in:
6
.changeset/dirty-owls-prove.md
Normal file
6
.changeset/dirty-owls-prove.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/lockfile-file": minor
|
||||
"@pnpm/lockfile-types": minor
|
||||
---
|
||||
|
||||
Add optional neverBuiltDependencies property to the lockfile object.
|
||||
5
.changeset/olive-pianos-eat.md
Normal file
5
.changeset/olive-pianos-eat.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/resolve-dependencies": minor
|
||||
---
|
||||
|
||||
New option added for ignore scripts in specified dependencies: `neverBuiltDependencies`.
|
||||
6
.changeset/shaggy-experts-worry.md
Normal file
6
.changeset/shaggy-experts-worry.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"supi": minor
|
||||
"@pnpm/types": minor
|
||||
---
|
||||
|
||||
Allow to ignore builds of specified dependencies throught the `pnpm.neverBuiltDependencies` field in `package.json`.
|
||||
@@ -72,7 +72,7 @@ function isEmptyLockfile (lockfile: Lockfile) {
|
||||
|
||||
type LockfileFile = Omit<Lockfile, 'importers'> & Partial<ProjectSnapshot> & Partial<Pick<Lockfile, 'importers'>>
|
||||
|
||||
function normalizeLockfile (lockfile: Lockfile, forceSharedFormat: boolean) {
|
||||
export function normalizeLockfile (lockfile: Lockfile, forceSharedFormat: boolean) {
|
||||
let lockfileToSave!: LockfileFile
|
||||
if (!forceSharedFormat && R.equals(R.keys(lockfile.importers), ['.'])) {
|
||||
lockfileToSave = {
|
||||
@@ -112,6 +112,13 @@ function normalizeLockfile (lockfile: Lockfile, forceSharedFormat: boolean) {
|
||||
if (lockfileToSave.overrides && R.isEmpty(lockfileToSave.overrides)) {
|
||||
delete lockfileToSave.overrides
|
||||
}
|
||||
if (lockfileToSave.neverBuiltDependencies) {
|
||||
if (R.isEmpty(lockfileToSave.neverBuiltDependencies)) {
|
||||
delete lockfileToSave.neverBuiltDependencies
|
||||
} else {
|
||||
lockfileToSave.neverBuiltDependencies = lockfileToSave.neverBuiltDependencies.sort()
|
||||
}
|
||||
}
|
||||
return lockfileToSave
|
||||
}
|
||||
|
||||
|
||||
33
packages/lockfile-file/test/normalizeLockfile.test.ts
Normal file
33
packages/lockfile-file/test/normalizeLockfile.test.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { LOCKFILE_VERSION } from '@pnpm/constants'
|
||||
import { normalizeLockfile } from '@pnpm/lockfile-file/lib/write'
|
||||
|
||||
test('empty overrides and neverBuiltDependencies are removed during lockfile normalization', () => {
|
||||
expect(normalizeLockfile({
|
||||
lockfileVersion: LOCKFILE_VERSION,
|
||||
overrides: {},
|
||||
neverBuiltDependencies: [],
|
||||
packages: {},
|
||||
importers: {
|
||||
foo: {
|
||||
dependencies: {
|
||||
bar: 'link:../bar',
|
||||
},
|
||||
specifiers: {
|
||||
bar: 'link:../bar',
|
||||
},
|
||||
},
|
||||
},
|
||||
}, false)).toStrictEqual({
|
||||
lockfileVersion: LOCKFILE_VERSION,
|
||||
importers: {
|
||||
foo: {
|
||||
dependencies: {
|
||||
bar: 'link:../bar',
|
||||
},
|
||||
specifiers: {
|
||||
bar: 'link:../bar',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
@@ -2,6 +2,7 @@ export interface Lockfile {
|
||||
importers: Record<string, ProjectSnapshot>
|
||||
lockfileVersion: number
|
||||
packages?: PackageSnapshots
|
||||
neverBuiltDependencies?: string[]
|
||||
overrides?: Record<string, string>
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,7 @@ export interface ResolutionContext {
|
||||
currentLockfile: Lockfile
|
||||
linkWorkspacePackagesDepth: number
|
||||
lockfileDir: string
|
||||
neverBuiltDependencies: Set<string>
|
||||
storeController: StoreController
|
||||
// the IDs of packages that are not installable
|
||||
skipped: Set<string>
|
||||
@@ -786,6 +787,7 @@ async function resolveDependency (
|
||||
depPath,
|
||||
force: ctx.force,
|
||||
hasBin,
|
||||
neverBuiltDependencies: ctx.neverBuiltDependencies,
|
||||
pkg,
|
||||
pkgResponse,
|
||||
prepare,
|
||||
@@ -838,6 +840,7 @@ function getResolvedPackage (
|
||||
depPath: string
|
||||
force: boolean
|
||||
hasBin: boolean
|
||||
neverBuiltDependencies: Set<string>
|
||||
pkg: PackageManifest
|
||||
pkgResponse: PackageResponse
|
||||
prepare: boolean
|
||||
@@ -871,7 +874,8 @@ function getResolvedPackage (
|
||||
peerDependenciesMeta: options.pkg.peerDependenciesMeta,
|
||||
prepare: options.prepare,
|
||||
prod: !options.wantedDependency.dev && !options.wantedDependency.optional,
|
||||
requiresBuild: options.dependencyLockfile && Boolean(options.dependencyLockfile.requiresBuild),
|
||||
requiresBuild: options.neverBuiltDependencies.has(options.pkg.name)
|
||||
? false : (options.dependencyLockfile && Boolean(options.dependencyLockfile.requiresBuild)),
|
||||
resolution: options.pkgResponse.body.resolution,
|
||||
version: options.pkg.version,
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ export interface ResolveDependenciesOptions {
|
||||
hooks: {
|
||||
readPackage?: ReadPackageHook
|
||||
}
|
||||
neverBuiltDependencies?: Set<string>
|
||||
nodeVersion: string
|
||||
registries: Registries
|
||||
pnpmVersion: string
|
||||
@@ -85,6 +86,7 @@ export default async function<T> (
|
||||
forceFullResolution: opts.forceFullResolution,
|
||||
linkWorkspacePackagesDepth: opts.linkWorkspacePackagesDepth ?? -1,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
neverBuiltDependencies: opts.neverBuiltDependencies ?? new Set(),
|
||||
nodeVersion: opts.nodeVersion,
|
||||
outdatedDependencies: {} as {[pkgId: string]: string},
|
||||
pendingNodes: [] as PendingNode[],
|
||||
|
||||
@@ -148,6 +148,7 @@ export async function mutateModules (
|
||||
const overrides = rootProjectManifest
|
||||
? rootProjectManifest.pnpm?.overrides ?? rootProjectManifest.resolutions
|
||||
: undefined
|
||||
const neverBuiltDependencies = rootProjectManifest?.pnpm?.neverBuiltDependencies ?? []
|
||||
if (!R.isEmpty(overrides ?? {})) {
|
||||
const versionsOverrider = createVersionsOverrider(overrides!)
|
||||
if (opts.hooks.readPackage) {
|
||||
@@ -175,8 +176,10 @@ export async function mutateModules (
|
||||
return result
|
||||
|
||||
async function _install (): Promise<Array<{ rootDir: string, manifest: ProjectManifest }>> {
|
||||
const needsFullResolution = !R.equals(ctx.wantedLockfile.overrides ?? {}, overrides ?? {})
|
||||
const needsFullResolution = !R.equals(ctx.wantedLockfile.overrides ?? {}, overrides ?? {}) ||
|
||||
!R.equals((ctx.wantedLockfile.neverBuiltDependencies ?? []).sort(), (neverBuiltDependencies ?? []).sort())
|
||||
ctx.wantedLockfile.overrides = overrides
|
||||
ctx.wantedLockfile.neverBuiltDependencies = neverBuiltDependencies
|
||||
const frozenLockfile = opts.frozenLockfile ||
|
||||
opts.frozenLockfileIfExists && ctx.existsWantedLockfile
|
||||
if (
|
||||
@@ -434,6 +437,7 @@ export async function mutateModules (
|
||||
currentLockfileIsUpToDate: !ctx.existsWantedLockfile || ctx.currentLockfileIsUpToDate,
|
||||
makePartialCurrentLockfile,
|
||||
needsFullResolution,
|
||||
neverBuiltDependencies,
|
||||
overrides,
|
||||
update: opts.update || !installsOnly,
|
||||
updateLockfileMinorVersion: true,
|
||||
@@ -580,6 +584,7 @@ async function installInContext (
|
||||
opts: StrictInstallOptions & {
|
||||
makePartialCurrentLockfile: boolean
|
||||
needsFullResolution: boolean
|
||||
neverBuiltDependencies: string[]
|
||||
overrides?: Record<string, string>
|
||||
updateLockfileMinorVersion: boolean
|
||||
preferredVersions?: PreferredVersions
|
||||
@@ -667,6 +672,7 @@ async function installInContext (
|
||||
hooks: opts.hooks,
|
||||
linkWorkspacePackagesDepth: opts.linkWorkspacePackagesDepth ?? (opts.saveWorkspaceProtocol ? 0 : -1),
|
||||
lockfileDir: opts.lockfileDir,
|
||||
neverBuiltDependencies: new Set(opts.neverBuiltDependencies),
|
||||
nodeVersion: opts.nodeVersion,
|
||||
pnpmVersion: opts.packageManager.name === 'pnpm' ? opts.packageManager.version : '',
|
||||
preferWorkspacePackages: opts.preferWorkspacePackages,
|
||||
|
||||
@@ -432,3 +432,29 @@ test('scripts have access to unlisted bins when hoisting is used', async () => {
|
||||
|
||||
expect(project.requireModule('pkg-that-calls-unlisted-dep-in-hooks/output.json')).toStrictEqual(['Hello world!'])
|
||||
})
|
||||
|
||||
test('selectively ignore scripts in some dependencies', async () => {
|
||||
const project = prepareEmpty()
|
||||
const neverBuiltDependencies = ['pre-and-postinstall-scripts-example']
|
||||
const manifest = await addDependenciesToPackage({ pnpm: { neverBuiltDependencies } },
|
||||
['pre-and-postinstall-scripts-example', 'install-script-example'],
|
||||
await testDefaults({ fastUnpack: false })
|
||||
)
|
||||
|
||||
expect(await exists('node_modules/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
|
||||
expect(await exists('node_modules/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
|
||||
expect(await exists('node_modules/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
|
||||
const lockfile = await project.readLockfile()
|
||||
expect(lockfile.neverBuiltDependencies).toStrictEqual(neverBuiltDependencies)
|
||||
expect(lockfile.packages['/pre-and-postinstall-scripts-example/1.0.0'].requiresBuild).toBe(undefined)
|
||||
expect(lockfile.packages['/install-script-example/1.0.0'].requiresBuild).toBeTruthy()
|
||||
|
||||
await rimraf('node_modules')
|
||||
|
||||
await install(manifest, await testDefaults({ fastUnpack: false, frozenLockfile: true }))
|
||||
|
||||
expect(await exists('node_modules/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
|
||||
expect(await exists('node_modules/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
|
||||
expect(await exists('node_modules/install-script-example/generated-by-install.js')).toBeTruthy()
|
||||
})
|
||||
|
||||
@@ -83,6 +83,7 @@ export type DependencyManifest = BaseManifest & Required<Pick<BaseManifest, 'nam
|
||||
|
||||
export type ProjectManifest = BaseManifest & {
|
||||
pnpm?: {
|
||||
neverBuiltDependencies?: string[]
|
||||
overrides?: Record<string, string>
|
||||
}
|
||||
private?: boolean
|
||||
|
||||
Reference in New Issue
Block a user