rsnext/packages/next/lib/patch-incorrect-lockfile.ts
Remco Haszing 8f9296c00d
Add final newline to package-lock.json (#36813)
This aligns the output with what npm outputs. Without this change,
Next.js causes unwanted changes in package-lock.json.

## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have helpful link attached, see `contributing.md`

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have helpful link attached, see `contributing.md`

## Documentation / Examples

- [x] Make sure the linting passes by running `yarn lint`
2022-05-10 17:38:25 +00:00

102 lines
3.3 KiB
TypeScript

import { promises } from 'fs'
import '../server/node-polyfill-fetch'
import * as Log from '../build/output/log'
import findUp from 'next/dist/compiled/find-up'
/**
* Attempts to patch npm package-lock.json when it
* fails to include optionalDependencies for other platforms
* this can occur when the package-lock is rebuilt from a current
* node_modules install instead of pulling fresh package data
*/
export async function patchIncorrectLockfile(dir: string) {
const lockfilePath = await findUp('package-lock.json', { cwd: dir })
if (!lockfilePath) {
// if no lockfile present there is no action to take
return
}
const content = await promises.readFile(lockfilePath, 'utf8')
const lockfileParsed = JSON.parse(content)
const foundSwcPkgs = new Set()
const nextPkg = lockfileParsed.packages?.['node_modules/next']
// if we don't find next in the package-lock we can't continue
if (!nextPkg) {
return
}
const nextVersion = nextPkg.version
const packageKeys = Object.keys(lockfileParsed.dependencies || {})
const expectedSwcPkgs = Object.keys(nextPkg?.optionalDependencies).filter(
(pkg) => pkg.startsWith('@next/swc-')
)
packageKeys.forEach((pkgKey) => {
const swcIndex = pkgKey.indexOf('@next/swc-')
if (swcIndex > -1) {
foundSwcPkgs.add(pkgKey.substring(swcIndex))
}
})
// if swc package keys are missing manually populate them
// so installs on different platforms can succeed
// user will need to run npm i after to ensure it's corrected
if (foundSwcPkgs.size !== expectedSwcPkgs.length) {
Log.warn(`Found lockfile missing swc dependencies, patching..`)
try {
// populate fields for each missing swc pkg
for (const pkg of expectedSwcPkgs) {
if (!foundSwcPkgs.has(pkg)) {
const res = await fetch(`https://registry.npmjs.org/${pkg}`)
if (!res.ok) {
throw new Error(
`Failed to fetch registry info for ${pkg}, got status ${res.status}`
)
}
const data = await res.json()
const version = data.versions[nextVersion]
if (!version) {
throw new Error(
`Failed to find matching version for ${pkg} at ${nextVersion}`
)
}
if (lockfileParsed.dependencies) {
lockfileParsed.dependencies[pkg] = {
version: nextVersion,
resolved: version.dist.tarball,
integrity: version.dist.integrity,
optional: true,
}
}
lockfileParsed.packages[`node_modules/${pkg}`] = {
version: nextVersion,
resolved: version.dist.tarball,
integrity: version.dist.integrity,
cpu: version.cpu,
optional: true,
os: version.os,
engines: version.engines,
}
}
}
await promises.writeFile(
lockfilePath,
`${JSON.stringify(lockfileParsed, null, 2)}\n`
)
Log.warn(
'Lockfile was successfully patched, please run "npm install" to ensure @next/swc dependencies are downloaded'
)
} catch (err) {
Log.error(
`Failed to patch lockfile, please try uninstalling and reinstalling next in this workspace`
)
console.error(err)
}
}
}