feat(js): generate package.json with overrides and resolutions (#27601)
This PR ensures that `overrides` and `resolutions` are in the generated package.json file as well. If they are missing, then using `--frozen-lockfile` will fail due to mismatched overrides in the lockfile. Also adds a `skipOverrides` flag to the affected executors and plugins -- same as `skipPackageManger` that was added previously. Affected executors/plugins: - `@nx/vite:build` - `@nx/webpack:webpack` - `@nx/remix:build` - `@nx/next:build` - `NxAppWebpackPlugin` <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #26884
This commit is contained in:
parent
35899e3a25
commit
042049c785
@ -61,6 +61,10 @@
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"skipOverrides": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `overrides` and `resolutions` entries to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
},
|
||||
"skipPackageManager": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `packageManager` entry to the generated package.json file."
|
||||
|
||||
@ -31,6 +31,10 @@
|
||||
"description": "Generate a lockfile (e.g. package-lock.json) that matches the workspace lockfile to ensure package versions match.",
|
||||
"default": false
|
||||
},
|
||||
"skipOverrides": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `overrides` and `resolutions` entries to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
},
|
||||
"skipPackageManager": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `packageManager` entry to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
|
||||
@ -51,6 +51,10 @@
|
||||
"description": "Include devDependencies in the generated package.json.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"skipOverrides": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `overrides` and `resolutions` entries to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
},
|
||||
"skipPackageManager": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `packageManager` entry to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
|
||||
@ -239,6 +239,10 @@
|
||||
"type": "boolean",
|
||||
"description": "Generates a `package.json` and pruned lock file with the project's `node_module` dependencies populated for installing in a container. If a `package.json` exists in the project's directory, it will be reused with dependencies populated."
|
||||
},
|
||||
"skipOverrides": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `overrides` and `resolutions` entries to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
},
|
||||
"skipPackageManager": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `packageManager` entry to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
|
||||
@ -215,6 +215,18 @@ Type: `string[]`
|
||||
|
||||
External scripts that will be included before the main application entry.
|
||||
|
||||
##### skipOverrides
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Do not add a `overrides` and `resolutions` entries to the generated package.json file. Only works in conjunction with `generatePackageJson` option.
|
||||
|
||||
##### skipPackageManager
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
Do not add a `packageManager` entry to the generated package.json file. Only works in conjunction with `generatePackageJson` option.
|
||||
|
||||
##### skipTypeChecking
|
||||
|
||||
Type: `boolean`
|
||||
|
||||
@ -81,6 +81,7 @@ export default async function buildExecutor(
|
||||
target: context.targetName,
|
||||
root: context.root,
|
||||
isProduction: !options.includeDevDependenciesInPackageJson, // By default we remove devDependencies since this is a production build.
|
||||
skipOverrides: options.skipOverrides,
|
||||
skipPackageManager: options.skipPackageManager,
|
||||
}
|
||||
);
|
||||
|
||||
@ -58,6 +58,10 @@
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"skipOverrides": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `overrides` and `resolutions` entries to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
},
|
||||
"skipPackageManager": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `packageManager` entry to the generated package.json file."
|
||||
|
||||
@ -39,6 +39,7 @@ export interface NextBuildBuilderOptions {
|
||||
nextConfig?: string;
|
||||
outputPath: string;
|
||||
profile?: boolean;
|
||||
skipOverrides?: boolean;
|
||||
skipPackageManager?: boolean;
|
||||
watch?: boolean;
|
||||
}
|
||||
|
||||
@ -779,6 +779,227 @@ describe('createPackageJson', () => {
|
||||
/Package Manager Mismatch/
|
||||
);
|
||||
});
|
||||
|
||||
it('should add overrides (pnpm)', () => {
|
||||
spies.push(
|
||||
jest
|
||||
.spyOn(fs, 'existsSync')
|
||||
.mockImplementation(
|
||||
(path) =>
|
||||
path === 'libs/lib1/package.json' ||
|
||||
path === 'apps/app1/package.json' ||
|
||||
path === 'package.json'
|
||||
)
|
||||
);
|
||||
spies.push(
|
||||
jest
|
||||
.spyOn(fileutilsModule, 'readJsonFile')
|
||||
.mockImplementation((path) => {
|
||||
if (path === 'package.json') {
|
||||
return {
|
||||
...rootPackageJson(),
|
||||
pnpm: {
|
||||
overrides: {
|
||||
foo: '1.0.0',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
if (path === 'libs/lib1/package.json') {
|
||||
return projectPackageJson();
|
||||
}
|
||||
if (path === 'apps/app1/package.json') {
|
||||
return {
|
||||
...projectPackageJson(),
|
||||
pnpm: {
|
||||
overrides: {
|
||||
foo: '2.0.0',
|
||||
bar: '1.0.0',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
expect(
|
||||
createPackageJson('lib1', graph, {
|
||||
root: '',
|
||||
})
|
||||
).toEqual({
|
||||
dependencies: {
|
||||
random: '1.0.0',
|
||||
typescript: '^4.8.4',
|
||||
},
|
||||
name: 'other-name',
|
||||
version: '1.2.3',
|
||||
pnpm: {
|
||||
overrides: {
|
||||
foo: '1.0.0',
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
createPackageJson('app1', graph, {
|
||||
root: '',
|
||||
})
|
||||
).toEqual({
|
||||
dependencies: {
|
||||
random: '1.0.0',
|
||||
typescript: '^4.8.4',
|
||||
},
|
||||
name: 'other-name',
|
||||
version: '1.2.3',
|
||||
pnpm: {
|
||||
overrides: {
|
||||
foo: '2.0.0',
|
||||
bar: '1.0.0',
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should add overrides (npm)', () => {
|
||||
spies.push(
|
||||
jest
|
||||
.spyOn(fs, 'existsSync')
|
||||
.mockImplementation(
|
||||
(path) =>
|
||||
path === 'libs/lib1/package.json' ||
|
||||
path === 'apps/app1/package.json' ||
|
||||
path === 'package.json'
|
||||
)
|
||||
);
|
||||
spies.push(
|
||||
jest
|
||||
.spyOn(fileutilsModule, 'readJsonFile')
|
||||
.mockImplementation((path) => {
|
||||
if (path === 'package.json') {
|
||||
return {
|
||||
...rootPackageJson(),
|
||||
overrides: {
|
||||
foo: '1.0.0',
|
||||
},
|
||||
};
|
||||
}
|
||||
if (path === 'libs/lib1/package.json') {
|
||||
return projectPackageJson();
|
||||
}
|
||||
if (path === 'apps/app1/package.json') {
|
||||
return {
|
||||
...projectPackageJson(),
|
||||
overrides: {
|
||||
foo: '2.0.0',
|
||||
bar: '1.0.0',
|
||||
},
|
||||
};
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
expect(
|
||||
createPackageJson('lib1', graph, {
|
||||
root: '',
|
||||
})
|
||||
).toEqual({
|
||||
dependencies: {
|
||||
random: '1.0.0',
|
||||
typescript: '^4.8.4',
|
||||
},
|
||||
name: 'other-name',
|
||||
version: '1.2.3',
|
||||
overrides: {
|
||||
foo: '1.0.0',
|
||||
},
|
||||
});
|
||||
expect(
|
||||
createPackageJson('app1', graph, {
|
||||
root: '',
|
||||
})
|
||||
).toEqual({
|
||||
dependencies: {
|
||||
random: '1.0.0',
|
||||
typescript: '^4.8.4',
|
||||
},
|
||||
name: 'other-name',
|
||||
version: '1.2.3',
|
||||
overrides: {
|
||||
foo: '2.0.0',
|
||||
bar: '1.0.0',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should add resolutions (yarn)', () => {
|
||||
spies.push(
|
||||
jest
|
||||
.spyOn(fs, 'existsSync')
|
||||
.mockImplementation(
|
||||
(path) =>
|
||||
path === 'libs/lib1/package.json' ||
|
||||
path === 'apps/app1/package.json' ||
|
||||
path === 'package.json'
|
||||
)
|
||||
);
|
||||
spies.push(
|
||||
jest
|
||||
.spyOn(fileutilsModule, 'readJsonFile')
|
||||
.mockImplementation((path) => {
|
||||
if (path === 'package.json') {
|
||||
return {
|
||||
...rootPackageJson(),
|
||||
resolutions: {
|
||||
foo: '1.0.0',
|
||||
},
|
||||
};
|
||||
}
|
||||
if (path === 'libs/lib1/package.json') {
|
||||
return projectPackageJson();
|
||||
}
|
||||
if (path === 'apps/app1/package.json') {
|
||||
return {
|
||||
...projectPackageJson(),
|
||||
resolutions: {
|
||||
foo: '2.0.0',
|
||||
bar: '1.0.0',
|
||||
},
|
||||
};
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
expect(
|
||||
createPackageJson('lib1', graph, {
|
||||
root: '',
|
||||
})
|
||||
).toEqual({
|
||||
dependencies: {
|
||||
random: '1.0.0',
|
||||
typescript: '^4.8.4',
|
||||
},
|
||||
name: 'other-name',
|
||||
version: '1.2.3',
|
||||
resolutions: {
|
||||
foo: '1.0.0',
|
||||
},
|
||||
});
|
||||
expect(
|
||||
createPackageJson('app1', graph, {
|
||||
root: '',
|
||||
})
|
||||
).toEqual({
|
||||
dependencies: {
|
||||
random: '1.0.0',
|
||||
typescript: '^4.8.4',
|
||||
},
|
||||
name: 'other-name',
|
||||
version: '1.2.3',
|
||||
resolutions: {
|
||||
foo: '2.0.0',
|
||||
bar: '1.0.0',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -39,6 +39,7 @@ export function createPackageJson(
|
||||
isProduction?: boolean;
|
||||
helperDependencies?: string[];
|
||||
skipPackageManager?: boolean;
|
||||
skipOverrides?: boolean;
|
||||
} = {},
|
||||
fileMap: ProjectFileMap = null
|
||||
): PackageJson {
|
||||
@ -198,6 +199,34 @@ export function createPackageJson(
|
||||
packageJson.packageManager = rootPackageJson.packageManager;
|
||||
}
|
||||
|
||||
// region Overrides/Resolutions
|
||||
|
||||
// npm
|
||||
if (rootPackageJson.overrides && !options.skipOverrides) {
|
||||
packageJson.overrides = {
|
||||
...rootPackageJson.overrides,
|
||||
...packageJson.overrides,
|
||||
};
|
||||
}
|
||||
|
||||
// pnpm
|
||||
if (rootPackageJson.pnpm?.overrides && !options.skipOverrides) {
|
||||
packageJson.pnpm ??= {};
|
||||
packageJson.pnpm.overrides = {
|
||||
...rootPackageJson.pnpm.overrides,
|
||||
...packageJson.pnpm.overrides,
|
||||
};
|
||||
}
|
||||
|
||||
// yarn
|
||||
if (rootPackageJson.resolutions && !options.skipOverrides) {
|
||||
packageJson.resolutions = {
|
||||
...rootPackageJson.resolutions,
|
||||
...packageJson.resolutions,
|
||||
};
|
||||
}
|
||||
// endregion Overrides/Resolutions
|
||||
|
||||
return packageJson;
|
||||
}
|
||||
|
||||
|
||||
@ -54,6 +54,9 @@ export interface PackageJson {
|
||||
peerDependencies?: Record<string, string>;
|
||||
peerDependenciesMeta?: Record<string, { optional: boolean }>;
|
||||
resolutions?: Record<string, string>;
|
||||
pnpm?: {
|
||||
overrides?: PackageOverride;
|
||||
};
|
||||
overrides?: PackageOverride;
|
||||
bin?: Record<string, string> | string;
|
||||
workspaces?:
|
||||
|
||||
@ -28,6 +28,10 @@
|
||||
"description": "Generate a lockfile (e.g. package-lock.json) that matches the workspace lockfile to ensure package versions match.",
|
||||
"default": false
|
||||
},
|
||||
"skipOverrides": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `overrides` and `resolutions` entries to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
},
|
||||
"skipPackageManager": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `packageManager` entry to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
|
||||
@ -126,6 +126,7 @@ export async function* viteBuildExecutor(
|
||||
target: context.targetName,
|
||||
root: context.root,
|
||||
isProduction: !options.includeDevDependenciesInPackageJson, // By default we remove devDependencies since this is a production build.
|
||||
skipOverrides: options.skipOverrides,
|
||||
skipPackageManager: options.skipPackageManager,
|
||||
}
|
||||
);
|
||||
|
||||
@ -4,6 +4,7 @@ export interface ViteBuildExecutorOptions {
|
||||
generatePackageJson?: boolean;
|
||||
includeDevDependenciesInPackageJson?: boolean;
|
||||
outputPath?: string;
|
||||
skipOverrides?: boolean;
|
||||
skipPackageManager?: boolean;
|
||||
skipTypeCheck?: boolean;
|
||||
tsConfig?: string;
|
||||
|
||||
@ -60,6 +60,10 @@
|
||||
"description": "Include devDependencies in the generated package.json.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"skipOverrides": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `overrides` and `resolutions` entries to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
},
|
||||
"skipPackageManager": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `packageManager` entry to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
|
||||
@ -163,6 +163,10 @@
|
||||
"type": "boolean",
|
||||
"description": "Generates a `package.json` and pruned lock file with the project's `node_module` dependencies populated for installing in a container. If a `package.json` exists in the project's directory, it will be reused with dependencies populated."
|
||||
},
|
||||
"skipOverrides": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `overrides` and `resolutions` entries to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
},
|
||||
"skipPackageManager": {
|
||||
"type": "boolean",
|
||||
"description": "Do not add a `packageManager` entry to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||
|
||||
@ -167,6 +167,10 @@ export interface NxAppWebpackPluginOptions {
|
||||
* External scripts that will be included before the main application entry.
|
||||
*/
|
||||
scripts?: Array<ExtraEntryPointClass | string>;
|
||||
/**
|
||||
* Do not add a `overrides` and `resolutions` entries to the generated package.json file. Only works in conjunction with `generatePackageJson` option.
|
||||
*/
|
||||
skipOverrides?: boolean;
|
||||
/**
|
||||
* Do not add a `packageManager` entry to the generated package.json file. Only works in conjunction with `generatePackageJson` option.
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user