Skip to content

Commit 3ccec47

Browse files
leosvelperezFrozenPandaz
authored andcommitted
fix(js): ensure js libraries' build produce esm output in ts solution setup (#29546)
- Update js libraries for bundlers `esbuild`, `swc`, and `tsc` to produce ESM output when using the TS solution setup. - Fix `esbuild` and `swc` executors so they generate declaration files even when skipping type-checking. - Add `cjs` and `cts` to the `ignoredFiles` pattern for the rollup config file in the eslint config. - Ensure running an install after a js library is generated when using the TS solution setup. <!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- 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 #
1 parent 7fa5994 commit 3ccec47

File tree

13 files changed

+471
-29
lines changed

13 files changed

+471
-29
lines changed

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

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
import {
2+
cleanupProject,
3+
getPackageManagerCommand,
4+
getSelectedPackageManager,
5+
newProject,
6+
runCLI,
7+
runCommand,
8+
uniq,
9+
updateFile,
10+
updateJson,
11+
} from '@nx/e2e/utils';
12+
13+
describe('JS - TS solution setup', () => {
14+
beforeAll(() => {
15+
newProject({
16+
packages: ['@nx/js'],
17+
preset: 'ts',
18+
});
19+
});
20+
21+
afterAll(() => {
22+
cleanupProject();
23+
});
24+
25+
it('should generate libraries with different bundlers and link them successfully', () => {
26+
const esbuildParentLib = uniq('esbuild-parent-lib');
27+
const esbuildChildLib = uniq('esbuild-child-lib');
28+
const rollupParentLib = uniq('rollup-parent-lib');
29+
const rollupChildLib = uniq('rollup-child-lib');
30+
const swcParentLib = uniq('swc-parent-lib');
31+
const swcChildLib = uniq('swc-child-lib');
32+
const tscParentLib = uniq('tsc-parent-lib');
33+
const tscChildLib = uniq('tsc-child-lib');
34+
const viteParentLib = uniq('vite-parent-lib');
35+
const viteChildLib = uniq('vite-child-lib');
36+
37+
runCLI(
38+
`generate @nx/js:lib packages/${esbuildParentLib} --bundler=esbuild --linter=eslint --unitTestRunner=jest`
39+
);
40+
runCLI(
41+
`generate @nx/js:lib packages/${esbuildChildLib} --bundler=esbuild --linter=eslint --unitTestRunner=jest`
42+
);
43+
runCLI(
44+
`generate @nx/js:lib packages/${rollupParentLib} --bundler=rollup --linter=eslint --unitTestRunner=jest`
45+
);
46+
runCLI(
47+
`generate @nx/js:lib packages/${rollupChildLib} --bundler=rollup --linter=eslint --unitTestRunner=jest`
48+
);
49+
runCLI(
50+
`generate @nx/js:lib packages/${swcParentLib} --bundler=swc --linter=eslint --unitTestRunner=jest`
51+
);
52+
runCLI(
53+
`generate @nx/js:lib packages/${swcChildLib} --bundler=swc --linter=eslint --unitTestRunner=jest`
54+
);
55+
runCLI(
56+
`generate @nx/js:lib packages/${tscParentLib} --bundler=tsc --linter=eslint --unitTestRunner=jest`
57+
);
58+
runCLI(
59+
`generate @nx/js:lib packages/${tscChildLib} --bundler=tsc --linter=eslint --unitTestRunner=jest`
60+
);
61+
runCLI(
62+
`generate @nx/js:lib packages/${viteParentLib} --bundler=vite --linter=eslint --unitTestRunner=jest`
63+
);
64+
runCLI(
65+
`generate @nx/js:lib packages/${viteChildLib} --bundler=vite --linter=eslint --unitTestRunner=jest`
66+
);
67+
68+
// add deps, each parent lib imports all child libs
69+
const addImports = (parentLib: string) => {
70+
updateFile(
71+
`packages/${parentLib}/src/index.ts`,
72+
(content) => `export * from '@proj/${esbuildChildLib}';
73+
export * from '@proj/${rollupChildLib}';
74+
export * from '@proj/${swcChildLib}';
75+
export * from '@proj/${tscChildLib}';
76+
export * from '@proj/${viteChildLib}';
77+
${content}`
78+
);
79+
};
80+
81+
addImports(esbuildParentLib);
82+
addImports(rollupParentLib);
83+
addImports(swcParentLib);
84+
addImports(tscParentLib);
85+
addImports(viteParentLib);
86+
87+
const pm = getSelectedPackageManager();
88+
if (pm === 'pnpm') {
89+
// for pnpm we need to add the local packages as dependencies to each consumer package.json
90+
const addDeps = (parentLib: string) => {
91+
updateJson(`packages/${parentLib}/package.json`, (json) => {
92+
json.dependencies ??= {};
93+
json.dependencies[`@proj/${esbuildChildLib}`] = 'workspace:*';
94+
json.dependencies[`@proj/${rollupChildLib}`] = 'workspace:*';
95+
json.dependencies[`@proj/${swcChildLib}`] = 'workspace:*';
96+
json.dependencies[`@proj/${tscChildLib}`] = 'workspace:*';
97+
json.dependencies[`@proj/${viteChildLib}`] = 'workspace:*';
98+
return json;
99+
});
100+
};
101+
102+
addDeps(esbuildParentLib);
103+
addDeps(rollupParentLib);
104+
addDeps(swcParentLib);
105+
addDeps(tscParentLib);
106+
addDeps(viteParentLib);
107+
108+
const pmc = getPackageManagerCommand({ packageManager: pm });
109+
runCommand(pmc.install);
110+
}
111+
112+
// sync to ensure the TS project references are updated
113+
runCLI(`sync`);
114+
115+
// check build
116+
expect(runCLI(`build ${esbuildParentLib}`)).toContain(
117+
`Successfully ran target build for project ${esbuildParentLib} and 5 tasks it depends on`
118+
);
119+
expect(runCLI(`build ${rollupParentLib}`)).toContain(
120+
`Successfully ran target build for project ${rollupParentLib} and 5 tasks it depends on`
121+
);
122+
expect(runCLI(`build ${swcParentLib}`)).toContain(
123+
`Successfully ran target build for project ${swcParentLib} and 5 tasks it depends on`
124+
);
125+
expect(runCLI(`build ${tscParentLib}`)).toContain(
126+
`Successfully ran target build for project ${tscParentLib} and 5 tasks it depends on`
127+
);
128+
expect(runCLI(`build ${viteParentLib}`)).toContain(
129+
`Successfully ran target build for project ${viteParentLib} and 5 tasks it depends on`
130+
);
131+
132+
// check typecheck
133+
expect(runCLI(`typecheck ${esbuildParentLib}`)).toContain(
134+
`Successfully ran target typecheck for project ${esbuildParentLib} and 5 tasks it depends on`
135+
);
136+
expect(runCLI(`typecheck ${rollupParentLib}`)).toContain(
137+
`Successfully ran target typecheck for project ${rollupParentLib} and 5 tasks it depends on`
138+
);
139+
expect(runCLI(`typecheck ${swcParentLib}`)).toContain(
140+
`Successfully ran target typecheck for project ${swcParentLib} and 5 tasks it depends on`
141+
);
142+
expect(runCLI(`typecheck ${tscParentLib}`)).toContain(
143+
`Successfully ran target typecheck for project ${tscParentLib} and 5 tasks it depends on`
144+
);
145+
expect(runCLI(`typecheck ${viteParentLib}`)).toContain(
146+
`Successfully ran target typecheck for project ${viteParentLib} and 5 tasks it depends on`
147+
);
148+
149+
// check lint
150+
expect(runCLI(`lint ${esbuildParentLib}`)).toContain(
151+
`Successfully ran target lint for project ${esbuildParentLib}`
152+
);
153+
expect(runCLI(`lint ${rollupParentLib}`)).toContain(
154+
`Successfully ran target lint for project ${rollupParentLib}`
155+
);
156+
expect(runCLI(`lint ${swcParentLib}`)).toContain(
157+
`Successfully ran target lint for project ${swcParentLib}`
158+
);
159+
expect(runCLI(`lint ${tscParentLib}`)).toContain(
160+
`Successfully ran target lint for project ${tscParentLib}`
161+
);
162+
expect(runCLI(`lint ${viteParentLib}`)).toContain(
163+
`Successfully ran target lint for project ${viteParentLib}`
164+
);
165+
166+
// check test
167+
expect(runCLI(`test ${esbuildParentLib}`)).toContain(
168+
`Successfully ran target test for project ${esbuildParentLib}`
169+
);
170+
expect(runCLI(`test ${rollupParentLib}`)).toContain(
171+
`Successfully ran target test for project ${rollupParentLib}`
172+
);
173+
expect(runCLI(`test ${swcParentLib}`)).toContain(
174+
`Successfully ran target test for project ${swcParentLib}`
175+
);
176+
expect(runCLI(`test ${tscParentLib}`)).toContain(
177+
`Successfully ran target test for project ${tscParentLib}`
178+
);
179+
expect(runCLI(`test ${viteParentLib}`)).toContain(
180+
`Successfully ran target test for project ${viteParentLib}`
181+
);
182+
}, 300_000);
183+
});

e2e/vite/src/vite-ts-solution.test.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import { names } from '@nx/devkit';
2+
import {
3+
cleanupProject,
4+
getPackageManagerCommand,
5+
getSelectedPackageManager,
6+
newProject,
7+
runCLI,
8+
runCommand,
9+
uniq,
10+
updateFile,
11+
updateJson,
12+
} from '@nx/e2e/utils';
13+
14+
describe('Vite - TS solution setup', () => {
15+
beforeAll(() => {
16+
newProject({
17+
packages: ['@nx/react', '@nx/js'],
18+
preset: 'ts',
19+
});
20+
});
21+
22+
afterAll(() => {
23+
cleanupProject();
24+
});
25+
26+
it('should generate app and consume libraries with different bundlers', () => {
27+
const reactApp = uniq('react-app');
28+
const esbuildLib = uniq('esbuild-lib');
29+
const rollupLib = uniq('rollup-lib');
30+
const swcLib = uniq('swc-lib');
31+
const tscLib = uniq('tsc-lib');
32+
const viteLib = uniq('vite-lib');
33+
const noBundlerLib = uniq('no-bundler-lib');
34+
35+
runCLI(`generate @nx/react:app apps/${reactApp} --bundler=vite`);
36+
runCLI(`generate @nx/js:lib packages/${esbuildLib} --bundler=esbuild`);
37+
runCLI(`generate @nx/js:lib packages/${rollupLib} --bundler=rollup`);
38+
runCLI(`generate @nx/js:lib packages/${swcLib} --bundler=swc`);
39+
runCLI(`generate @nx/js:lib packages/${tscLib} --bundler=tsc`);
40+
runCLI(`generate @nx/js:lib packages/${viteLib} --bundler=vite`);
41+
runCLI(`generate @nx/js:lib packages/${noBundlerLib} --bundler=none`);
42+
43+
// import all libs from the app
44+
updateFile(
45+
`apps/${reactApp}/src/app/app.tsx`,
46+
(content) => `import { ${
47+
names(esbuildLib).propertyName
48+
} } from '@proj/${esbuildLib}';
49+
import { ${names(rollupLib).propertyName} } from '@proj/${rollupLib}';
50+
import { ${names(swcLib).propertyName} } from '@proj/${swcLib}';
51+
import { ${names(tscLib).propertyName} } from '@proj/${tscLib}';
52+
import { ${names(viteLib).propertyName} } from '@proj/${viteLib}';
53+
import { ${names(noBundlerLib).propertyName} } from '@proj/${noBundlerLib}';
54+
55+
console.log(
56+
${names(esbuildLib).propertyName}(),
57+
${names(rollupLib).propertyName}(),
58+
${names(swcLib).propertyName}(),
59+
${names(tscLib).propertyName}(),
60+
${names(viteLib).propertyName}(),
61+
${names(noBundlerLib).propertyName}()
62+
);
63+
64+
${content}`
65+
);
66+
67+
const pm = getSelectedPackageManager();
68+
if (pm === 'pnpm') {
69+
// for pnpm we need to add the local packages as dependencies to each consumer package.json
70+
updateJson(`apps/${reactApp}/package.json`, (json) => {
71+
json.dependencies ??= {};
72+
json.dependencies[`@proj/${esbuildLib}`] = 'workspace:*';
73+
json.dependencies[`@proj/${rollupLib}`] = 'workspace:*';
74+
json.dependencies[`@proj/${swcLib}`] = 'workspace:*';
75+
json.dependencies[`@proj/${tscLib}`] = 'workspace:*';
76+
json.dependencies[`@proj/${viteLib}`] = 'workspace:*';
77+
json.dependencies[`@proj/${noBundlerLib}`] = 'workspace:*';
78+
return json;
79+
});
80+
81+
const pmc = getPackageManagerCommand({ packageManager: pm });
82+
runCommand(pmc.install);
83+
}
84+
85+
// sync to ensure the TS project references are updated
86+
runCLI(`sync`);
87+
88+
// check build
89+
expect(runCLI(`build ${reactApp}`)).toContain(
90+
`Successfully ran target build for project ${reactApp} and 5 tasks it depends on`
91+
);
92+
93+
// check typecheck
94+
expect(runCLI(`typecheck ${reactApp}`)).toContain(
95+
`Successfully ran target typecheck for project ${reactApp} and 6 tasks it depends on`
96+
);
97+
}, 300_000);
98+
});

packages/esbuild/src/executors/esbuild/esbuild.impl.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,8 @@ export async function* esbuildExecutor(
134134
setup(build: esbuild.PluginBuild) {
135135
build.onEnd(async (result: esbuild.BuildResult) => {
136136
if (
137-
!options.skipTypeCheck &&
138-
!options.isTsSolutionSetup
137+
!options.skipTypeCheck ||
138+
options.isTsSolutionSetup
139139
) {
140140
const { errors } = await runTypeCheck(
141141
options,
@@ -183,7 +183,7 @@ export async function* esbuildExecutor(
183183
);
184184
} else {
185185
// Run type-checks first and bail if they don't pass.
186-
if (!options.skipTypeCheck && !options.isTsSolutionSetup) {
186+
if (!options.skipTypeCheck || options.isTsSolutionSetup) {
187187
const { errors } = await runTypeCheck(options, context);
188188
if (errors.length > 0) {
189189
yield { success: false };
@@ -245,6 +245,10 @@ function getTypeCheckOptions(
245245
typeCheckOptions.cacheDir = cacheDir;
246246
}
247247

248+
if (options.isTsSolutionSetup && options.skipTypeCheck) {
249+
typeCheckOptions.ignoreDiagnostics = true;
250+
}
251+
248252
return typeCheckOptions;
249253
}
250254

packages/js/src/executors/swc/swc.impl.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,7 @@ function normalizeOptions(
5656

5757
const outputPath = join(root, options.outputPath);
5858

59-
if (options.skipTypeCheck == null && !isTsSolutionSetup) {
60-
options.skipTypeCheck = false;
61-
}
59+
options.skipTypeCheck ??= !isTsSolutionSetup;
6260

6361
if (options.watch == null) {
6462
options.watch = false;

packages/js/src/generators/library/files/lib/src/lib/__fileName__.spec.ts__tmpl__

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { <%= propertyName %> } from './<%= fileName %>';
1+
import { <%= propertyName %> } from './<%= fileNameImport %>';
22

33
describe('<%= propertyName %>', () => {
44
it('should work', () => {

0 commit comments

Comments
 (0)