@nx/js 20.2.0-beta.3 → 20.2.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/generators/library/library.js +15 -0
- package/src/generators/library/schema.d.ts +1 -5
- package/src/plugins/typescript/plugin.js +41 -10
- package/src/utils/package-manager-workspaces.d.ts +1 -0
- package/src/utils/package-manager-workspaces.js +14 -1
- package/src/utils/typescript/ts-solution-setup.d.ts +1 -0
- package/src/utils/typescript/ts-solution-setup.js +62 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/js",
|
|
3
|
-
"version": "20.2.0-beta.
|
|
3
|
+
"version": "20.2.0-beta.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The JS plugin for Nx contains executors and generators that provide the best experience for developing JavaScript and TypeScript projects. ",
|
|
6
6
|
"repository": {
|
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
"@babel/preset-env": "^7.23.2",
|
|
40
40
|
"@babel/preset-typescript": "^7.22.5",
|
|
41
41
|
"@babel/runtime": "^7.22.6",
|
|
42
|
-
"@nx/devkit": "20.2.0-beta.
|
|
43
|
-
"@nx/workspace": "20.2.0-beta.
|
|
42
|
+
"@nx/devkit": "20.2.0-beta.4",
|
|
43
|
+
"@nx/workspace": "20.2.0-beta.4",
|
|
44
44
|
"@zkochan/js-yaml": "0.0.7",
|
|
45
45
|
"babel-plugin-const-enum": "^1.0.1",
|
|
46
46
|
"babel-plugin-macros": "^2.8.0",
|
|
@@ -135,6 +135,10 @@ async function libraryGeneratorInternal(tree, schema) {
|
|
|
135
135
|
logNxReleaseDocsInfo();
|
|
136
136
|
});
|
|
137
137
|
}
|
|
138
|
+
// Always run install to link packages.
|
|
139
|
+
if (options.isUsingTsSolutionConfig) {
|
|
140
|
+
tasks.push(() => (0, devkit_1.installPackagesTask)(tree));
|
|
141
|
+
}
|
|
138
142
|
tasks.push(() => {
|
|
139
143
|
(0, log_show_project_command_1.logShowProjectCommand)(options.name);
|
|
140
144
|
});
|
|
@@ -816,6 +820,17 @@ function determineEntryFields(options) {
|
|
|
816
820
|
// Safest option is to not set a type field.
|
|
817
821
|
// Allow the user to decide which module format their library is using
|
|
818
822
|
type: undefined,
|
|
823
|
+
// For non-buildable libraries, point to source so we can still use them in apps via bundlers like Vite.
|
|
824
|
+
main: options.isUsingTsSolutionConfig
|
|
825
|
+
? options.js
|
|
826
|
+
? './src/index.js'
|
|
827
|
+
: './src/index.ts'
|
|
828
|
+
: undefined,
|
|
829
|
+
types: options.isUsingTsSolutionConfig
|
|
830
|
+
? options.js
|
|
831
|
+
? './src/index.js'
|
|
832
|
+
: './src/index.ts'
|
|
833
|
+
: undefined,
|
|
819
834
|
};
|
|
820
835
|
}
|
|
821
836
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ProjectNameAndRootFormat,
|
|
3
|
-
ProjectNameAndRootOptions,
|
|
4
|
-
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
|
1
|
+
import type { ProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
|
5
2
|
// nx-ignore-next-line
|
|
6
3
|
const { Linter, LinterType } = require('@nx/eslint'); // use require to import to avoid circular dependency
|
|
7
4
|
import type { ProjectPackageManagerWorkspaceState } from '../../utils/package-manager-workspaces';
|
|
@@ -12,7 +9,6 @@ export type Bundler = 'swc' | 'tsc' | 'rollup' | 'vite' | 'esbuild' | 'none';
|
|
|
12
9
|
export interface LibraryGeneratorSchema {
|
|
13
10
|
directory: string;
|
|
14
11
|
name?: string;
|
|
15
|
-
projectNameAndRootFormat?: ProjectNameAndRootFormat;
|
|
16
12
|
skipFormat?: boolean;
|
|
17
13
|
tags?: string;
|
|
18
14
|
skipTsConfig?: boolean;
|
|
@@ -72,12 +72,20 @@ async function createNodesInternal(configFilePath, options, context, lockFileNam
|
|
|
72
72
|
!siblingFiles.includes('tsconfig.json')) {
|
|
73
73
|
return {};
|
|
74
74
|
}
|
|
75
|
+
// Do not create project for Next.js projects since they are not compatible with
|
|
76
|
+
// project references and typecheck will fail.
|
|
77
|
+
if (siblingFiles.includes('next.config.js') ||
|
|
78
|
+
siblingFiles.includes('next.config.cjs') ||
|
|
79
|
+
siblingFiles.includes('next.config.mjs') ||
|
|
80
|
+
siblingFiles.includes('next.config.ts')) {
|
|
81
|
+
return {};
|
|
82
|
+
}
|
|
75
83
|
/**
|
|
76
84
|
* The cache key is composed by:
|
|
77
85
|
* - hashes of the content of the relevant files that can affect what's inferred by the plugin:
|
|
78
86
|
* - current config file
|
|
79
87
|
* - config files extended by the current config file (recursively up to the root config file)
|
|
80
|
-
* - referenced config files that are internal to the owning Nx project of the current config file
|
|
88
|
+
* - referenced config files that are internal to the owning Nx project of the current config file, or is a shallow external reference of the owning Nx project
|
|
81
89
|
* - lock file
|
|
82
90
|
* - hash of the plugin options
|
|
83
91
|
* - current config file path
|
|
@@ -85,11 +93,13 @@ async function createNodesInternal(configFilePath, options, context, lockFileNam
|
|
|
85
93
|
const tsConfig = readCachedTsConfig(fullConfigPath);
|
|
86
94
|
const extendedConfigFiles = getExtendedConfigFiles(fullConfigPath, tsConfig);
|
|
87
95
|
const internalReferencedFiles = resolveInternalProjectReferences(tsConfig, context.workspaceRoot, projectRoot);
|
|
96
|
+
const externalProjectReferences = resolveShallowExternalProjectReferences(tsConfig, context.workspaceRoot, projectRoot);
|
|
88
97
|
const nodeHash = (0, file_hasher_1.hashArray)([
|
|
89
98
|
...[
|
|
90
99
|
fullConfigPath,
|
|
91
100
|
...extendedConfigFiles.files,
|
|
92
101
|
...Object.keys(internalReferencedFiles),
|
|
102
|
+
...Object.keys(externalProjectReferences),
|
|
93
103
|
(0, node_path_1.join)(context.workspaceRoot, lockFileName),
|
|
94
104
|
].map(file_hasher_1.hashFile),
|
|
95
105
|
(0, file_hasher_1.hashObject)(options),
|
|
@@ -119,14 +129,15 @@ function buildTscTargets(configFilePath, projectRoot, options, context) {
|
|
|
119
129
|
// Typecheck target
|
|
120
130
|
if ((0, node_path_1.basename)(configFilePath) === 'tsconfig.json' && options.typecheck) {
|
|
121
131
|
internalProjectReferences = resolveInternalProjectReferences(tsConfig, context.workspaceRoot, projectRoot);
|
|
132
|
+
const externalProjectReferences = resolveShallowExternalProjectReferences(tsConfig, context.workspaceRoot, projectRoot);
|
|
122
133
|
const targetName = options.typecheck.targetName;
|
|
123
134
|
if (!targets[targetName]) {
|
|
124
135
|
let command = `tsc --build --emitDeclarationOnly --pretty --verbose`;
|
|
125
136
|
if (tsConfig.options.noEmit ||
|
|
126
|
-
Object.values(internalProjectReferences).some((ref) => ref.options.noEmit)
|
|
127
|
-
|
|
128
|
-
//
|
|
129
|
-
command = `
|
|
137
|
+
Object.values(internalProjectReferences).some((ref) => ref.options.noEmit) ||
|
|
138
|
+
Object.values(externalProjectReferences).some((ref) => ref.options.noEmit)) {
|
|
139
|
+
// `tsc --build` does not work with `noEmit: true`
|
|
140
|
+
command = `echo "The 'typecheck' target is disabled because one or more project references set 'noEmit: true' in their tsconfig. Remove this property to resolve this issue."`;
|
|
130
141
|
}
|
|
131
142
|
targets[targetName] = {
|
|
132
143
|
dependsOn: [`^${targetName}`],
|
|
@@ -321,6 +332,27 @@ function getExtendedConfigFiles(tsConfigPath, tsConfig) {
|
|
|
321
332
|
};
|
|
322
333
|
}
|
|
323
334
|
function resolveInternalProjectReferences(tsConfig, workspaceRoot, projectRoot, projectReferences = {}) {
|
|
335
|
+
walkProjectReferences(tsConfig, workspaceRoot, projectRoot, (configPath, config) => {
|
|
336
|
+
if (isExternalProjectReference(configPath, workspaceRoot, projectRoot)) {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
projectReferences[configPath] = config;
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
return projectReferences;
|
|
344
|
+
}
|
|
345
|
+
function resolveShallowExternalProjectReferences(tsConfig, workspaceRoot, projectRoot, projectReferences = {}) {
|
|
346
|
+
walkProjectReferences(tsConfig, workspaceRoot, projectRoot, (configPath, config) => {
|
|
347
|
+
if (isExternalProjectReference(configPath, workspaceRoot, projectRoot)) {
|
|
348
|
+
projectReferences[configPath] = config;
|
|
349
|
+
}
|
|
350
|
+
return false;
|
|
351
|
+
});
|
|
352
|
+
return projectReferences;
|
|
353
|
+
}
|
|
354
|
+
function walkProjectReferences(tsConfig, workspaceRoot, projectRoot, visitor, // false stops recursion
|
|
355
|
+
projectReferences = {}) {
|
|
324
356
|
if (!tsConfig.projectReferences?.length) {
|
|
325
357
|
return projectReferences;
|
|
326
358
|
}
|
|
@@ -334,15 +366,14 @@ function resolveInternalProjectReferences(tsConfig, workspaceRoot, projectRoot,
|
|
|
334
366
|
// the referenced tsconfig doesn't exist, ignore it
|
|
335
367
|
continue;
|
|
336
368
|
}
|
|
337
|
-
if (isExternalProjectReference(refConfigPath, workspaceRoot, projectRoot)) {
|
|
338
|
-
continue;
|
|
339
|
-
}
|
|
340
369
|
if (!refConfigPath.endsWith('.json')) {
|
|
341
370
|
refConfigPath = (0, node_path_1.join)(refConfigPath, 'tsconfig.json');
|
|
342
371
|
}
|
|
343
372
|
const refTsConfig = readCachedTsConfig(refConfigPath);
|
|
344
|
-
|
|
345
|
-
|
|
373
|
+
const result = visitor(refConfigPath, refTsConfig);
|
|
374
|
+
if (result !== false) {
|
|
375
|
+
walkProjectReferences(refTsConfig, workspaceRoot, projectRoot, visitor);
|
|
376
|
+
}
|
|
346
377
|
}
|
|
347
378
|
return projectReferences;
|
|
348
379
|
}
|
|
@@ -2,4 +2,5 @@ import { type GeneratorCallback, type Tree } from '@nx/devkit';
|
|
|
2
2
|
export type ProjectPackageManagerWorkspaceState = 'included' | 'excluded' | 'no-workspaces';
|
|
3
3
|
export declare function getProjectPackageManagerWorkspaceState(tree: Tree, projectRoot: string): ProjectPackageManagerWorkspaceState;
|
|
4
4
|
export declare function isUsingPackageManagerWorkspaces(tree: Tree): boolean;
|
|
5
|
+
export declare function isWorkspacesEnabled(tree: Tree): boolean;
|
|
5
6
|
export declare function getProjectPackageManagerWorkspaceStateWarningTask(projectPackageManagerWorkspaceState: ProjectPackageManagerWorkspaceState, workspaceRoot: string): GeneratorCallback;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getProjectPackageManagerWorkspaceState = getProjectPackageManagerWorkspaceState;
|
|
4
4
|
exports.isUsingPackageManagerWorkspaces = isUsingPackageManagerWorkspaces;
|
|
5
|
+
exports.isWorkspacesEnabled = isWorkspacesEnabled;
|
|
5
6
|
exports.getProjectPackageManagerWorkspaceStateWarningTask = getProjectPackageManagerWorkspaceStateWarningTask;
|
|
6
7
|
const devkit_1 = require("@nx/devkit");
|
|
7
8
|
const minimatch_1 = require("minimatch");
|
|
@@ -17,7 +18,19 @@ function getProjectPackageManagerWorkspaceState(tree, projectRoot) {
|
|
|
17
18
|
return isIncluded ? 'included' : 'excluded';
|
|
18
19
|
}
|
|
19
20
|
function isUsingPackageManagerWorkspaces(tree) {
|
|
20
|
-
return
|
|
21
|
+
return isWorkspacesEnabled(tree);
|
|
22
|
+
}
|
|
23
|
+
function isWorkspacesEnabled(tree
|
|
24
|
+
// packageManager: PackageManager = detectPackageManager(),
|
|
25
|
+
// root: string = workspaceRoot
|
|
26
|
+
) {
|
|
27
|
+
const packageManager = (0, devkit_1.detectPackageManager)(tree.root);
|
|
28
|
+
if (packageManager === 'pnpm') {
|
|
29
|
+
return tree.exists('pnpm-workspace.yaml');
|
|
30
|
+
}
|
|
31
|
+
// yarn and npm both use the same 'workspaces' property in package.json
|
|
32
|
+
const packageJson = (0, devkit_1.readJson)(tree, 'package.json');
|
|
33
|
+
return !!packageJson?.workspaces;
|
|
21
34
|
}
|
|
22
35
|
function getProjectPackageManagerWorkspaceStateWarningTask(projectPackageManagerWorkspaceState, workspaceRoot) {
|
|
23
36
|
return () => {
|
|
@@ -2,3 +2,4 @@ import { type Tree } from '@nx/devkit';
|
|
|
2
2
|
export declare function isUsingTypeScriptPlugin(tree: Tree): boolean;
|
|
3
3
|
export declare function isUsingTsSolutionSetup(tree?: Tree): boolean;
|
|
4
4
|
export declare function assertNotUsingTsSolutionSetup(tree: Tree, pluginName: string, generatorName: string): void;
|
|
5
|
+
export declare function updateTsconfigFiles(tree: Tree, projectRoot: string, runtimeTsconfigFileName: string, compilerOptions: Record<string, string | boolean | string[]>, exclude?: string[], rootDir?: string): void;
|
|
@@ -3,9 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.isUsingTypeScriptPlugin = isUsingTypeScriptPlugin;
|
|
4
4
|
exports.isUsingTsSolutionSetup = isUsingTsSolutionSetup;
|
|
5
5
|
exports.assertNotUsingTsSolutionSetup = assertNotUsingTsSolutionSetup;
|
|
6
|
+
exports.updateTsconfigFiles = updateTsconfigFiles;
|
|
6
7
|
const devkit_1 = require("@nx/devkit");
|
|
7
8
|
const tree_1 = require("nx/src/generators/tree");
|
|
8
9
|
const package_manager_workspaces_1 = require("../package-manager-workspaces");
|
|
10
|
+
const posix_1 = require("node:path/posix");
|
|
9
11
|
function isUsingTypeScriptPlugin(tree) {
|
|
10
12
|
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
11
13
|
return (nxJson?.plugins?.some((p) => typeof p === 'string'
|
|
@@ -65,3 +67,63 @@ function assertNotUsingTsSolutionSetup(tree, pluginName, generatorName) {
|
|
|
65
67
|
});
|
|
66
68
|
process.exit(1);
|
|
67
69
|
}
|
|
70
|
+
function updateTsconfigFiles(tree, projectRoot, runtimeTsconfigFileName, compilerOptions, exclude = [], rootDir = 'src') {
|
|
71
|
+
if (!isUsingTsSolutionSetup(tree))
|
|
72
|
+
return;
|
|
73
|
+
const offset = (0, devkit_1.offsetFromRoot)(projectRoot);
|
|
74
|
+
const tsconfig = `${projectRoot}/${runtimeTsconfigFileName}`;
|
|
75
|
+
const tsconfigSpec = `${projectRoot}/tsconfig.spec.json`;
|
|
76
|
+
const e2eRoot = `${projectRoot}-e2e`;
|
|
77
|
+
const tsconfigE2E = `${e2eRoot}/tsconfig.json`;
|
|
78
|
+
if (tree.exists(tsconfig)) {
|
|
79
|
+
(0, devkit_1.updateJson)(tree, tsconfig, (json) => {
|
|
80
|
+
json.extends = (0, devkit_1.joinPathFragments)(offset, 'tsconfig.base.json');
|
|
81
|
+
json.compilerOptions = {
|
|
82
|
+
...json.compilerOptions,
|
|
83
|
+
// Make sure d.ts files from typecheck does not conflict with bundlers.
|
|
84
|
+
// Other tooling like jest write to "out-tsc/jest" to we just default to "out-tsc/<project-name>".
|
|
85
|
+
outDir: (0, devkit_1.joinPathFragments)('out-tsc', projectRoot.split('/').at(-1)),
|
|
86
|
+
rootDir,
|
|
87
|
+
...compilerOptions,
|
|
88
|
+
};
|
|
89
|
+
const excludeSet = json.exclude
|
|
90
|
+
? new Set(['dist', ...json.exclude, ...exclude])
|
|
91
|
+
: new Set(exclude);
|
|
92
|
+
json.exclude = Array.from(excludeSet);
|
|
93
|
+
return json;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (tree.exists(tsconfigSpec)) {
|
|
97
|
+
(0, devkit_1.updateJson)(tree, tsconfigSpec, (json) => {
|
|
98
|
+
json.extends = (0, devkit_1.joinPathFragments)(offset, 'tsconfig.base.json');
|
|
99
|
+
json.compilerOptions = {
|
|
100
|
+
...json.compilerOptions,
|
|
101
|
+
...compilerOptions,
|
|
102
|
+
};
|
|
103
|
+
const runtimePath = `./${runtimeTsconfigFileName}`;
|
|
104
|
+
json.references ??= [];
|
|
105
|
+
if (!json.references.some((x) => x.path === runtimePath))
|
|
106
|
+
json.references.push({ path: runtimePath });
|
|
107
|
+
return json;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (tree.exists(tsconfigE2E)) {
|
|
111
|
+
// tsconfig.json for e2e projects need to have references array
|
|
112
|
+
(0, devkit_1.updateJson)(tree, tsconfigE2E, (json) => {
|
|
113
|
+
json.references ??= [];
|
|
114
|
+
const projectPath = (0, posix_1.relative)(e2eRoot, projectRoot);
|
|
115
|
+
if (!json.references.some((x) => x.path === projectPath))
|
|
116
|
+
json.references.push({ path: projectPath });
|
|
117
|
+
return json;
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (tree.exists('tsconfig.json')) {
|
|
121
|
+
(0, devkit_1.updateJson)(tree, 'tsconfig.json', (json) => {
|
|
122
|
+
const projectPath = './' + projectRoot;
|
|
123
|
+
json.references ??= [];
|
|
124
|
+
if (!json.references.some((x) => x.path === projectPath))
|
|
125
|
+
json.references.push({ path: projectPath });
|
|
126
|
+
return json;
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|