-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(nextjs): include peer dependencies in built package.json
- Loading branch information
Showing
4 changed files
with
134 additions
and
129 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 20 additions & 64 deletions
84
packages/next/src/executors/build/lib/create-package-json.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,32 @@ | ||
import { ExecutorContext } from '@nrwl/devkit'; | ||
|
||
import { writeFileSync } from 'fs'; | ||
import { join } from 'path'; | ||
|
||
import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph'; | ||
import { readJsonFile } from '@nrwl/workspace/src/utilities/fileutils'; | ||
import { calculateProjectDependencies } from '@nrwl/workspace/src/utilities/buildable-libs-utils'; | ||
import { writeJsonFile } from '@nrwl/workspace/src/utilities/fileutils'; | ||
import { createPackageJson as generatePackageJson } from '@nrwl/workspace/src/utilities/create-package-json'; | ||
|
||
import { NextBuildBuilderOptions } from '../../../utils/types'; | ||
|
||
function getProjectDeps(context: ExecutorContext, rootPackageJson: any) { | ||
const projGraph = createProjectGraph(); | ||
const { dependencies: deps } = calculateProjectDependencies( | ||
projGraph, | ||
context.root, | ||
context.projectName, | ||
context.targetName, | ||
context.configurationName | ||
); | ||
const depNames = deps | ||
.map((d) => d.node) | ||
.filter((node) => node.type === 'npm') | ||
.map((node) => node.data.packageName) | ||
// Need to make sure @nrwl/workspace is installed | ||
// It is only a peer dependency of @nrwl/next so does not get installed automatically | ||
// See: https://github.com/nrwl/nx/issues/4336 | ||
.concat('@nrwl/workspace'); | ||
const dependencies: string[] = depNames | ||
.filter((packageName) => packageName in rootPackageJson.dependencies) | ||
.reduce((deps, pkgName) => { | ||
return { ...deps, [pkgName]: rootPackageJson.dependencies[pkgName] }; | ||
}, {}); | ||
const devDependencies = depNames | ||
.filter((packageName) => packageName in rootPackageJson.devDependencies) | ||
.reduce((deps, pkgName) => { | ||
return { ...deps, [pkgName]: rootPackageJson.devDependencies[pkgName] }; | ||
}, {}); | ||
return { | ||
dependencies, | ||
devDependencies, | ||
}; | ||
} | ||
|
||
export function createPackageJson( | ||
options: NextBuildBuilderOptions, | ||
context: ExecutorContext | ||
) { | ||
const rootPackageJson = readJsonFile(join(context.root, 'package.json')); | ||
const { dependencies, devDependencies } = getProjectDeps( | ||
context, | ||
rootPackageJson | ||
); | ||
|
||
const outPackageJson = { | ||
name: context.projectName, | ||
version: '0.0.1', | ||
scripts: { | ||
start: 'next start', | ||
}, | ||
dependencies: { | ||
...dependencies, | ||
// peer deps of next, so we need to add them here | ||
react: rootPackageJson.dependencies['react'], | ||
'react-dom': rootPackageJson.dependencies['react-dom'], | ||
next: rootPackageJson.dependencies['next'], | ||
}, | ||
// needed for the next.config.js file | ||
devDependencies, | ||
}; | ||
const depGraph = createProjectGraph(); | ||
const packageJson = generatePackageJson(context.projectName, depGraph, { | ||
root: context.root, | ||
projectRoot: context.workspace.projects[context.projectName].sourceRoot, | ||
}); | ||
if (!packageJson.scripts) { | ||
packageJson.scripts = {}; | ||
} | ||
packageJson.scripts.start = 'next start'; | ||
if (!packageJson.devDependencies) { | ||
packageJson.devDependencies = {}; | ||
} | ||
const nrwlWorkspaceNode = depGraph.nodes['npm:@nrwl/workspace']; | ||
|
||
writeFileSync( | ||
join(options.outputPath, 'package.json'), | ||
JSON.stringify(outPackageJson, null, 2) | ||
); | ||
if (nrwlWorkspaceNode) { | ||
packageJson.devDependencies['@nrwl/workspace'] = | ||
nrwlWorkspaceNode.data.version; | ||
} | ||
writeJsonFile(`${options.outputPath}/package.json`, packageJson); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,17 @@ | ||
import { ProjectGraph } from '@nrwl/workspace/src/core/project-graph'; | ||
import { | ||
readJsonFile, | ||
writeJsonFile, | ||
} from '@nrwl/workspace/src/utilities/fileutils'; | ||
import { writeJsonFile } from '@nrwl/workspace/src/utilities/fileutils'; | ||
|
||
import { BuildNodeBuilderOptions } from './types'; | ||
import { createPackageJson } from '@nrwl/workspace/src/utilities/create-package-json'; | ||
import { OUT_FILENAME } from './config'; | ||
|
||
/** | ||
* Creates a package.json in the output directory for support to install dependencies within containers. | ||
* | ||
* If a package.json exists in the project, it will reuse that. | ||
* | ||
* @param projectName | ||
* @param graph | ||
* @param options | ||
* @constructor | ||
*/ | ||
export function generatePackageJson( | ||
projectName: string, | ||
graph: ProjectGraph, | ||
options: BuildNodeBuilderOptions | ||
) { | ||
const npmDeps = findAllNpmDeps(projectName, graph); | ||
// default package.json if one does not exist | ||
let packageJson = { | ||
name: projectName, | ||
version: '0.0.1', | ||
main: OUT_FILENAME, | ||
dependencies: {}, | ||
}; | ||
|
||
try { | ||
packageJson = readJsonFile(`${options.projectRoot}/package.json`); | ||
if (!packageJson.dependencies) { | ||
packageJson.dependencies = {}; | ||
} | ||
} catch (e) {} | ||
|
||
const rootPackageJson = readJsonFile(`${options.root}/package.json`); | ||
|
||
Object.entries(npmDeps).forEach(([packageName, version]) => { | ||
// don't include devDeps | ||
if (rootPackageJson.devDependencies?.[packageName]) { | ||
return; | ||
} | ||
|
||
packageJson.dependencies[packageName] = version; | ||
}); | ||
|
||
const packageJson = createPackageJson(projectName, graph, options); | ||
packageJson.main = OUT_FILENAME; | ||
delete packageJson.devDependencies; | ||
writeJsonFile(`${options.outputPath}/package.json`, packageJson); | ||
} | ||
|
||
function findAllNpmDeps( | ||
projectName: string, | ||
graph: ProjectGraph, | ||
list: { [packageName: string]: string } = {}, | ||
seen = new Set<string>() | ||
) { | ||
if (seen.has(projectName)) { | ||
return list; | ||
} | ||
|
||
seen.add(projectName); | ||
|
||
const node = graph.nodes[projectName]; | ||
|
||
if (node.type === 'npm') { | ||
list[node.data.packageName] = node.data.version; | ||
} | ||
graph.dependencies[projectName]?.forEach((dep) => { | ||
findAllNpmDeps(dep.target, graph, list, seen); | ||
}); | ||
|
||
return list; | ||
} |
106 changes: 106 additions & 0 deletions
106
packages/workspace/src/utilities/create-package-json.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { ProjectGraph } from '../core/project-graph'; | ||
import { readJsonFile } from './fileutils'; | ||
|
||
/** | ||
* Creates a package.json in the output directory for support to install dependencies within containers. | ||
* | ||
* If a package.json exists in the project, it will reuse that. | ||
*/ | ||
export function createPackageJson( | ||
projectName: string, | ||
graph: ProjectGraph, | ||
options: { | ||
projectRoot?: string; | ||
root?: string; | ||
} | ||
): any { | ||
const npmDeps = findAllNpmDeps(projectName, graph); | ||
// default package.json if one does not exist | ||
let packageJson = { | ||
name: projectName, | ||
version: '0.0.1', | ||
dependencies: {}, | ||
devDependencies: {}, | ||
}; | ||
try { | ||
packageJson = readJsonFile(`${options.projectRoot}/package.json`); | ||
if (!packageJson.dependencies) { | ||
packageJson.dependencies = {}; | ||
} | ||
if (!packageJson.devDependencies) { | ||
packageJson.devDependencies = {}; | ||
} | ||
} catch (e) {} | ||
|
||
const rootPackageJson = readJsonFile(`${options.root}/package.json`); | ||
Object.entries(npmDeps).forEach(([packageName, version]) => { | ||
if (rootPackageJson.devDependencies?.[packageName]) { | ||
packageJson.devDependencies[packageName] = version; | ||
} else { | ||
packageJson.dependencies[packageName] = version; | ||
} | ||
}); | ||
|
||
return packageJson; | ||
} | ||
|
||
function findAllNpmDeps( | ||
projectName: string, | ||
graph: ProjectGraph, | ||
list: { [packageName: string]: string } = {}, | ||
seen = new Set<string>() | ||
) { | ||
if (seen.has(projectName)) { | ||
return list; | ||
} | ||
|
||
seen.add(projectName); | ||
|
||
const node = graph.nodes[projectName]; | ||
|
||
if (node.type === 'npm') { | ||
list[node.data.packageName] = node.data.version; | ||
recursivelyCollectPeerDependencies(node.name, graph, list); | ||
} | ||
graph.dependencies[projectName]?.forEach((dep) => { | ||
findAllNpmDeps(dep.target, graph, list, seen); | ||
}); | ||
|
||
return list; | ||
} | ||
|
||
function recursivelyCollectPeerDependencies( | ||
projectName: string, | ||
graph: ProjectGraph, | ||
list: { [packageName: string]: string } = {}, | ||
seen = new Set<string>() | ||
) { | ||
if ( | ||
!graph.nodes[projectName] || | ||
graph.nodes[projectName].type !== 'npm' || | ||
seen.has(projectName) | ||
) { | ||
return list; | ||
} | ||
|
||
seen.add(projectName); | ||
const packageName = graph.nodes[projectName].data.packageName; | ||
try { | ||
const packageJson = require(`${packageName}/package.json`); | ||
if (!packageJson.peerDependencies) { | ||
return list; | ||
} | ||
|
||
Object.keys(packageJson.peerDependencies) | ||
.map((dependencyName) => `npm:${dependencyName}`) | ||
.map((dependency) => graph.nodes[dependency]) | ||
.filter(Boolean) | ||
.forEach((node) => { | ||
list[node.data.packageName] = node.data.version; | ||
recursivelyCollectPeerDependencies(node.name, graph, list, seen); | ||
}); | ||
return list; | ||
} catch (e) { | ||
return list; | ||
} | ||
} |