Skip to content

Commit 23c2327

Browse files
authored
feat(js): add lockfile generator to js plugin (#13968)
1 parent 942a6ae commit 23c2327

File tree

9 files changed

+315
-34
lines changed

9 files changed

+315
-34
lines changed

docs/generated/packages/js/executors/swc.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@
116116
"items": { "type": "string" },
117117
"description": "List of target names that annotate a build target for a project",
118118
"default": ["build"]
119+
},
120+
"generateLockfile": {
121+
"type": "boolean",
122+
"description": "Generate a lockfile (e.g. yarn.lock) that matches the workspace lockfile to ensure package versions match.",
123+
"default": false,
124+
"x-priority": "internal"
119125
}
120126
},
121127
"required": ["main", "outputPath", "tsConfig"],

docs/generated/packages/js/executors/tsc.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@
116116
"items": { "type": "string" },
117117
"description": "List of target names that annotate a build target for a project",
118118
"default": ["build"]
119+
},
120+
"generateLockfile": {
121+
"type": "boolean",
122+
"description": "Generate a lockfile (e.g. yarn.lock) that matches the workspace lockfile to ensure package versions match.",
123+
"default": false,
124+
"x-priority": "internal"
119125
}
120126
},
121127
"required": ["main", "outputPath", "tsConfig"],

e2e/js/src/js-swc.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@ import {
33
checkFilesDoNotExist,
44
checkFilesExist,
55
cleanupProject,
6+
detectPackageManager,
67
newProject,
8+
packageManagerLockFile,
79
readJson,
810
runCLI,
911
runCLIAsync,
12+
tmpProjPath,
1013
uniq,
1114
updateFile,
1215
updateJson,
@@ -80,6 +83,14 @@ describe('js e2e', () => {
8083
expect(output).toContain('1 task it depends on');
8184
expect(output).toContain('Successfully compiled: 2 files with swc');
8285

86+
runCLI(`build ${parentLib} --generateLockfile=true`);
87+
checkFilesExist(
88+
`dist/libs/${parentLib}/package.json`,
89+
`dist/libs/${parentLib}/${
90+
packageManagerLockFile[detectPackageManager(tmpProjPath())]
91+
}`
92+
);
93+
8394
updateJson(`libs/${lib}/.lib.swcrc`, (json) => {
8495
json.jsc.externalHelpers = true;
8596
return json;

e2e/js/src/js-tsc.test.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
checkFilesDoNotExist,
44
checkFilesExist,
55
cleanupProject,
6+
detectPackageManager,
67
getPackageManagerCommand,
78
newProject,
89
packageManagerLockFile,
@@ -12,6 +13,7 @@ import {
1213
runCLIAsync,
1314
runCommand,
1415
runCommandUntil,
16+
tmpProjPath,
1517
uniq,
1618
updateFile,
1719
updateJson,
@@ -49,6 +51,14 @@ describe('js e2e', () => {
4951
`dist/libs/${lib}/src/lib/${lib}.d.ts`
5052
);
5153

54+
runCLI(`build ${lib} --generateLockfile=true`);
55+
checkFilesExist(
56+
`dist/libs/${lib}/package.json`,
57+
`dist/libs/${lib}/${
58+
packageManagerLockFile[detectPackageManager(tmpProjPath())]
59+
}`
60+
);
61+
5262
updateJson(`libs/${lib}/project.json`, (json) => {
5363
json.targets.build.options.assets.push({
5464
input: `libs/${lib}/docs`,
@@ -187,9 +197,10 @@ describe('package.json updates', () => {
187197
runCLI(`build ${lib}`);
188198

189199
// Check that only 'react' exists, don't care about version
190-
expect(readJson(`dist/libs/${lib}/package.json`).dependencies).toEqual({});
191-
expect(readJson(`dist/libs/${lib}/package.json`).peerDependencies).toEqual({
200+
expect(readJson(`dist/libs/${lib}/package.json`).dependencies).toEqual({
192201
react: expect.any(String),
202+
});
203+
expect(readJson(`dist/libs/${lib}/package.json`).peerDependencies).toEqual({
193204
tslib: expect.any(String),
194205
});
195206
checkFilesDoNotExist(`dist/libs/${lib}/${packageManagerLockFile['npm']}`);

packages/js/src/executors/swc/schema.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,12 @@
9797
},
9898
"description": "List of target names that annotate a build target for a project",
9999
"default": ["build"]
100+
},
101+
"generateLockfile": {
102+
"type": "boolean",
103+
"description": "Generate a lockfile (e.g. yarn.lock) that matches the workspace lockfile to ensure package versions match.",
104+
"default": false,
105+
"x-priority": "internal"
100106
}
101107
},
102108
"required": ["main", "outputPath", "tsConfig"],

packages/js/src/executors/tsc/schema.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@
8686
},
8787
"description": "List of target names that annotate a build target for a project",
8888
"default": ["build"]
89+
},
90+
"generateLockfile": {
91+
"type": "boolean",
92+
"description": "Generate a lockfile (e.g. yarn.lock) that matches the workspace lockfile to ensure package versions match.",
93+
"default": false,
94+
"x-priority": "internal"
8995
}
9096
},
9197
"required": ["main", "outputPath", "tsConfig"],

packages/js/src/utils/package-json/update-package-json.spec.ts

Lines changed: 167 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1-
import { getUpdatedPackageJsonContent } from './update-package-json';
1+
import {
2+
getUpdatedPackageJsonContent,
3+
updatePackageJson,
4+
UpdatePackageJsonOption,
5+
} from './update-package-json';
6+
import { vol } from 'memfs';
7+
import { ExecutorContext, ProjectGraph } from '@nrwl/devkit';
8+
import { DependentBuildableProjectNode } from '@nrwl/workspace/src/utilities/buildable-libs-utils';
9+
10+
jest.mock('nx/src/utils/workspace-root', () => ({
11+
workspaceRoot: '/root',
12+
}));
13+
jest.mock('fs', () => require('memfs').fs);
214

315
describe('getUpdatedPackageJsonContent', () => {
416
it('should update fields for commonjs only (default)', () => {
@@ -259,3 +271,157 @@ describe('getUpdatedPackageJsonContent', () => {
259271
});
260272
});
261273
});
274+
275+
describe('updatePackageJson', () => {
276+
const originalPackageJson = {
277+
name: '@org/lib1',
278+
version: '0.0.3',
279+
dependencies: { lib2: '^0.0.1' },
280+
devDependencies: { jest: '27' },
281+
};
282+
const rootPackageJson = {
283+
name: '@org/root',
284+
version: '1.2.3',
285+
dependencies: { external1: '~1.0.0', external2: '^4.0.0' },
286+
devDependencies: { jest: '27' },
287+
};
288+
const projectGraph: ProjectGraph = {
289+
nodes: {
290+
'@org/lib1': {
291+
type: 'lib',
292+
name: '@org/lib1',
293+
data: {
294+
root: 'libs/lib1',
295+
targets: {
296+
build: {
297+
outputs: ['{workspaceRoot}/dist/libs/lib1'],
298+
},
299+
},
300+
files: [],
301+
},
302+
},
303+
},
304+
externalNodes: {
305+
'npm:external1': {
306+
type: 'npm',
307+
name: 'npm:external1',
308+
data: {
309+
packageName: 'external1',
310+
version: '1.0.0',
311+
},
312+
},
313+
'npm:external2': {
314+
type: 'npm',
315+
name: 'npm:external2',
316+
data: {
317+
packageName: 'external2',
318+
version: '4.5.6',
319+
},
320+
},
321+
'npm:jest': {
322+
type: 'npm',
323+
name: 'npm:jest',
324+
data: {
325+
packageName: 'jest',
326+
version: '21.1.0',
327+
},
328+
},
329+
},
330+
dependencies: {
331+
'@org/lib1': [
332+
{ source: '@org/lib1', target: 'npm:external1', type: 'static' },
333+
{ source: '@org/lib1', target: 'npm:external2', type: 'static' },
334+
],
335+
},
336+
};
337+
const context: ExecutorContext = {
338+
root: '/root',
339+
projectName: '@org/lib1',
340+
isVerbose: false,
341+
cwd: '',
342+
targetName: 'build',
343+
projectGraph,
344+
};
345+
346+
it('should generate new package if missing', () => {
347+
const fsJson = {};
348+
vol.fromJSON(fsJson, '/root');
349+
const options: UpdatePackageJsonOption = {
350+
outputPath: 'dist/libs/lib1',
351+
projectRoot: 'libs/lib1',
352+
main: 'libs/lib1/main.ts',
353+
};
354+
const dependencies: DependentBuildableProjectNode[] = [];
355+
updatePackageJson(options, context, undefined, dependencies);
356+
357+
expect(vol.existsSync('dist/libs/lib1/package.json')).toEqual(true);
358+
const distPackageJson = JSON.parse(
359+
vol.readFileSync('dist/libs/lib1/package.json', 'utf-8').toString()
360+
);
361+
expect(distPackageJson).toMatchInlineSnapshot(`
362+
Object {
363+
"main": "./main.js",
364+
"name": "@org/lib1",
365+
"types": "./main.d.ts",
366+
"version": "0.0.1",
367+
}
368+
`);
369+
});
370+
371+
it('should keep package unchanged if "updateBuildableProjectDepsInPackageJson" not set', () => {
372+
const fsJson = {
373+
'libs/lib1/package.json': JSON.stringify(originalPackageJson, null, 2),
374+
};
375+
vol.fromJSON(fsJson, '/root');
376+
const options: UpdatePackageJsonOption = {
377+
outputPath: 'dist/libs/lib1',
378+
projectRoot: 'libs/lib1',
379+
main: 'libs/lib1/main.ts',
380+
};
381+
const dependencies: DependentBuildableProjectNode[] = [];
382+
updatePackageJson(options, context, undefined, dependencies);
383+
384+
expect(vol.existsSync('dist/libs/lib1/package.json')).toEqual(true);
385+
const distPackageJson = JSON.parse(
386+
vol.readFileSync('dist/libs/lib1/package.json', 'utf-8').toString()
387+
);
388+
expect(distPackageJson.dependencies).toEqual(
389+
originalPackageJson.dependencies
390+
);
391+
expect(distPackageJson.main).toEqual('./main.js');
392+
expect(distPackageJson.types).toEqual('./main.d.ts');
393+
});
394+
395+
it('should modify package if "updateBuildableProjectDepsInPackageJson" is set', () => {
396+
const fsJson = {
397+
'package.json': JSON.stringify(rootPackageJson, null, 2),
398+
'libs/lib1/package.json': JSON.stringify(originalPackageJson, null, 2),
399+
};
400+
vol.fromJSON(fsJson, '/root');
401+
const options: UpdatePackageJsonOption = {
402+
outputPath: 'dist/libs/lib1',
403+
projectRoot: 'libs/lib1',
404+
main: 'libs/lib1/main.ts',
405+
updateBuildableProjectDepsInPackageJson: true,
406+
};
407+
const dependencies: DependentBuildableProjectNode[] = [];
408+
updatePackageJson(options, context, undefined, dependencies);
409+
410+
expect(vol.existsSync('dist/libs/lib1/package.json')).toEqual(true);
411+
const distPackageJson = JSON.parse(
412+
vol.readFileSync('dist/libs/lib1/package.json', 'utf-8').toString()
413+
);
414+
expect(distPackageJson).toMatchInlineSnapshot(`
415+
Object {
416+
"dependencies": Object {
417+
"external1": "1.0.0",
418+
"external2": "4.5.6",
419+
},
420+
"main": "./main.js",
421+
"name": "@org/lib1",
422+
"types": "./main.d.ts",
423+
"version": "0.0.1",
424+
}
425+
`);
426+
});
427+
});

0 commit comments

Comments
 (0)