ec25b4742b
This adds handling for auto-detecting TypeScript being added to a project and installing the necessary dependencies instead of printing the command and requiring the user run the command. We have been testing the auto install handling for a while now with the `next lint` command and it has worked out pretty well. This also adds HMR handling for `jsconfig.json`/`tsconfig.json` in development so if the `baseURL` or `paths` configs are modified it doesn't require a dev server restart for the updates to be picked up. This also corrects our required dependencies detection as previously an incorrect `paths: []` value was being passed to `require.resolve` causing it to fail in specific situations. Closes: https://github.com/vercel/next.js/issues/36201 ### `next build` before https://user-images.githubusercontent.com/22380829/186039578-75f8c128-a13d-4e07-b5da-13bf186ee011.mp4 ### `next build` after https://user-images.githubusercontent.com/22380829/186039662-57af22a4-da5c-4ede-94ea-96541a032cca.mp4 ### `next dev` automatic setup and HMR handling https://user-images.githubusercontent.com/22380829/186039678-d78469ef-d00b-4ee6-8163-a4706394a7b4.mp4 ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [x] Errors have helpful link attached, see `contributing.md`
57 lines
1.5 KiB
TypeScript
57 lines
1.5 KiB
TypeScript
import { promises as fs } from 'fs'
|
|
import { fileExists } from './file-exists'
|
|
import { resolveFrom } from './resolve-from'
|
|
import { dirname, join, relative } from 'path'
|
|
|
|
export interface MissingDependency {
|
|
file: string
|
|
pkg: string
|
|
exportsRestrict: boolean
|
|
}
|
|
|
|
export type NecessaryDependencies = {
|
|
resolved: Map<string, string>
|
|
missing: MissingDependency[]
|
|
}
|
|
|
|
export async function hasNecessaryDependencies(
|
|
baseDir: string,
|
|
requiredPackages: MissingDependency[]
|
|
): Promise<NecessaryDependencies> {
|
|
let resolutions = new Map<string, string>()
|
|
const missingPackages: MissingDependency[] = []
|
|
|
|
await Promise.all(
|
|
requiredPackages.map(async (p) => {
|
|
try {
|
|
const pkgPath = await fs.realpath(
|
|
resolveFrom(baseDir, `${p.pkg}/package.json`)
|
|
)
|
|
const pkgDir = dirname(pkgPath)
|
|
|
|
if (p.exportsRestrict) {
|
|
const fileNameToVerify = relative(p.pkg, p.file)
|
|
if (fileNameToVerify) {
|
|
const fileToVerify = join(pkgDir, fileNameToVerify)
|
|
if (await fileExists(fileToVerify)) {
|
|
resolutions.set(p.pkg, fileToVerify)
|
|
} else {
|
|
return missingPackages.push(p)
|
|
}
|
|
} else {
|
|
resolutions.set(p.pkg, pkgPath)
|
|
}
|
|
} else {
|
|
resolutions.set(p.pkg, resolveFrom(baseDir, p.file))
|
|
}
|
|
} catch (_) {
|
|
return missingPackages.push(p)
|
|
}
|
|
})
|
|
)
|
|
|
|
return {
|
|
resolved: resolutions,
|
|
missing: missingPackages,
|
|
}
|
|
}
|