@nx/workspace 17.0.3 → 17.0.5
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/LICENSE +1 -1
- package/README.md +9 -4
- package/migrations.json +37 -0
- package/package.json +4 -4
- package/src/generators/ci-workflow/ci-workflow.d.ts +1 -1
- package/src/generators/ci-workflow/ci-workflow.js +30 -18
- package/src/generators/ci-workflow/files/azure/azure-pipelines.yml__tmpl__ +31 -33
- package/src/generators/ci-workflow/files/bitbucket-pipelines/bitbucket-pipelines.yml__tmpl__ +35 -29
- package/src/generators/ci-workflow/files/circleci/.circleci/config.yml__tmpl__ +17 -53
- package/src/generators/ci-workflow/files/github/.github/workflows/__workflowFileName__.yml__tmpl__ +26 -19
- package/src/generators/ci-workflow/files/gitlab/.gitlab-ci.yml__tmpl__ +12 -35
- package/src/generators/ci-workflow/schema.json +1 -1
- package/src/generators/convert-to-monorepo/convert-to-monorepo.js +6 -2
- package/src/generators/convert-to-monorepo/schema.json +1 -1
- package/src/generators/convert-to-nx-project/schema.json +1 -1
- package/src/generators/move/lib/create-project-configuration-in-new-destination.js +7 -2
- package/src/generators/move/lib/extract-base-configs.d.ts +1 -1
- package/src/generators/move/lib/extract-base-configs.js +4 -10
- package/src/generators/move/lib/move-project-files.js +4 -4
- package/src/generators/move/lib/normalize-schema.d.ts +1 -1
- package/src/generators/move/lib/normalize-schema.js +86 -79
- package/src/generators/move/lib/update-imports.js +1 -1
- package/src/generators/move/lib/update-jest-config.js +5 -3
- package/src/generators/move/lib/update-project-root-files.js +2 -2
- package/src/generators/move/move.js +4 -1
- package/src/generators/move/schema.json +1 -1
- package/src/generators/new/files-readme/README.md.template +49 -23
- package/src/generators/new/files-root-app/package.json__tmpl__ +3 -0
- package/src/generators/new/generate-preset.js +16 -0
- package/src/generators/new/generate-workspace-files.js +36 -23
- package/src/generators/new/new.d.ts +3 -0
- package/src/generators/new/new.js +9 -7
- package/src/generators/new/schema.json +15 -1
- package/src/generators/npm-package/schema.json +1 -1
- package/src/generators/preset/preset.js +84 -0
- package/src/generators/preset/schema.d.ts +3 -0
- package/src/generators/preset/schema.json +17 -3
- package/src/generators/remove/lib/update-jest-config.js +18 -6
- package/src/generators/remove/schema.json +1 -1
- package/src/generators/run-commands/schema.json +1 -1
- package/src/generators/utils/jest-config.d.ts +2 -0
- package/src/generators/utils/jest-config.js +13 -0
- package/src/generators/utils/presets.d.ts +4 -0
- package/src/generators/utils/presets.js +5 -1
- package/src/utils/output.js +1 -1
- package/src/utils/versions.d.ts +2 -2
- package/src/utils/versions.js +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.maybeMigrateEslintConfigIfRootProject = exports.maybeExtractJestConfigBase = exports.maybeExtractTsConfigBase = void 0;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
5
|
function maybeExtractTsConfigBase(tree) {
|
|
6
6
|
let extractTsConfigBase;
|
|
@@ -26,11 +26,7 @@ async function maybeExtractJestConfigBase(tree) {
|
|
|
26
26
|
await jestInitGenerator(tree, {});
|
|
27
27
|
}
|
|
28
28
|
exports.maybeExtractJestConfigBase = maybeExtractJestConfigBase;
|
|
29
|
-
function
|
|
30
|
-
if (rootProject.root !== '.')
|
|
31
|
-
return;
|
|
32
|
-
if (tree.exists('.eslintrc.base.json'))
|
|
33
|
-
return;
|
|
29
|
+
function maybeMigrateEslintConfigIfRootProject(tree, rootProject) {
|
|
34
30
|
let migrateConfigToMonorepoStyle;
|
|
35
31
|
try {
|
|
36
32
|
migrateConfigToMonorepoStyle = require('@nx/' +
|
|
@@ -39,11 +35,9 @@ function maybeExtractEslintConfigIfRootProject(tree, rootProject) {
|
|
|
39
35
|
catch {
|
|
40
36
|
// eslint not installed
|
|
41
37
|
}
|
|
42
|
-
|
|
43
|
-
// If other libs/apps exist, then this migration is already done by `@nx/eslint:lint-rootProject` generator.
|
|
44
|
-
migrateConfigToMonorepoStyle?.([rootProject], tree, tree.exists((0, devkit_1.joinPathFragments)(rootProject.root, 'jest.config.ts')) ||
|
|
38
|
+
migrateConfigToMonorepoStyle?.(Array.from((0, devkit_1.getProjects)(tree).values()), tree, tree.exists((0, devkit_1.joinPathFragments)(rootProject.root, 'jest.config.ts')) ||
|
|
45
39
|
tree.exists((0, devkit_1.joinPathFragments)(rootProject.root, 'jest.config.js'))
|
|
46
40
|
? 'jest'
|
|
47
41
|
: 'none');
|
|
48
42
|
}
|
|
49
|
-
exports.
|
|
43
|
+
exports.maybeMigrateEslintConfigIfRootProject = maybeMigrateEslintConfigIfRootProject;
|
|
@@ -22,15 +22,15 @@ function moveProjectFiles(tree, schema, project) {
|
|
|
22
22
|
'.babelrc',
|
|
23
23
|
'.eslintrc.json',
|
|
24
24
|
'eslint.config.js',
|
|
25
|
-
/^jest\.config\.(app|lib)\.[jt]s$/,
|
|
25
|
+
/^jest\.config\.((app|lib)\.)?[jt]s$/,
|
|
26
26
|
'vite.config.ts',
|
|
27
27
|
/^webpack.*\.js$/,
|
|
28
28
|
'index.html', // Vite
|
|
29
29
|
];
|
|
30
30
|
const knownRootProjectFolders = [
|
|
31
|
-
'src',
|
|
32
|
-
'app',
|
|
33
|
-
'pages',
|
|
31
|
+
'src', // Most apps/libs
|
|
32
|
+
'app', // Remix, Next.js
|
|
33
|
+
'pages', // Next.js
|
|
34
34
|
'public', // Vite, Remix, Next.js
|
|
35
35
|
];
|
|
36
36
|
const isKnownRootProjectFile = (file) => {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { ProjectConfiguration, Tree } from '@nx/devkit';
|
|
1
|
+
import { type ProjectConfiguration, type Tree } from '@nx/devkit';
|
|
2
2
|
import type { NormalizedSchema, Schema } from '../schema';
|
|
3
3
|
export declare function normalizeSchema(tree: Tree, schema: Schema, projectConfiguration: ProjectConfiguration): Promise<NormalizedSchema>;
|
|
@@ -17,10 +17,16 @@ async function normalizeSchema(tree, schema, projectConfiguration) {
|
|
|
17
17
|
}
|
|
18
18
|
exports.normalizeSchema = normalizeSchema;
|
|
19
19
|
async function determineProjectNameAndRootOptions(tree, options, projectConfiguration) {
|
|
20
|
+
if (!options.projectNameAndRootFormat &&
|
|
21
|
+
(process.env.NX_INTERACTIVE !== 'true' || !isTTY())) {
|
|
22
|
+
options.projectNameAndRootFormat = 'derived';
|
|
23
|
+
}
|
|
20
24
|
validateName(options.newProjectName, options.projectNameAndRootFormat, projectConfiguration);
|
|
21
25
|
const formats = getProjectNameAndRootFormats(tree, options, projectConfiguration);
|
|
22
|
-
const format = options.projectNameAndRootFormat ??
|
|
23
|
-
|
|
26
|
+
const format = options.projectNameAndRootFormat ?? (await determineFormat(formats));
|
|
27
|
+
if (format === 'derived') {
|
|
28
|
+
logDeprecationMessage(formats, options);
|
|
29
|
+
}
|
|
24
30
|
return formats[format];
|
|
25
31
|
}
|
|
26
32
|
function validateName(name, projectNameAndRootFormat, projectConfiguration) {
|
|
@@ -55,65 +61,47 @@ function validateName(name, projectNameAndRootFormat, projectConfiguration) {
|
|
|
55
61
|
}
|
|
56
62
|
}
|
|
57
63
|
}
|
|
58
|
-
function getProjectNameAndRootFormats(tree,
|
|
59
|
-
let destination = (0, utils_1.normalizePathSlashes)(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
function getProjectNameAndRootFormats(tree, options, projectConfiguration) {
|
|
65
|
+
let destination = (0, utils_1.normalizePathSlashes)(options.destination);
|
|
66
|
+
if (options.newProjectName &&
|
|
67
|
+
options.newProjectName.includes('/') &&
|
|
68
|
+
!options.newProjectName.startsWith('@')) {
|
|
69
|
+
throw new Error(`You can't specify a new project name with a directory path (${options.newProjectName}). ` +
|
|
70
|
+
`Please provide a valid name without path segments and the full destination with the "--destination" option.`);
|
|
71
|
+
}
|
|
72
|
+
const asProvidedOptions = getAsProvidedOptions(tree, { ...options, destination }, projectConfiguration);
|
|
73
|
+
if (options.projectNameAndRootFormat === 'as-provided') {
|
|
66
74
|
return {
|
|
67
|
-
'as-provided':
|
|
68
|
-
|
|
69
|
-
importPath: schema.importPath ??
|
|
70
|
-
// keep the existing import path if the name didn't change
|
|
71
|
-
(normalizedNewProjectName &&
|
|
72
|
-
schema.projectName !== normalizedNewProjectName
|
|
73
|
-
? asProvidedProjectName
|
|
74
|
-
: undefined),
|
|
75
|
-
newProjectName: asProvidedProjectName,
|
|
76
|
-
},
|
|
75
|
+
'as-provided': asProvidedOptions,
|
|
76
|
+
derived: undefined,
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
schema.importPath ??
|
|
95
|
-
(0, utils_1.normalizePathSlashes)((0, get_import_path_1.getImportPath)(tree, destination));
|
|
79
|
+
if (asProvidedOptions.newProjectName.startsWith('@')) {
|
|
80
|
+
if (!options.projectNameAndRootFormat) {
|
|
81
|
+
devkit_1.output.warn({
|
|
82
|
+
title: `The provided new project name "${asProvidedOptions.newProjectName}" is a scoped project name and this is not supported by the move generator when using the "derived" format.`,
|
|
83
|
+
bodyLines: [
|
|
84
|
+
`The generator will try to move the project using the "as-provided" format with the new name "${asProvidedOptions.newProjectName}" located at "${asProvidedOptions.destination}".`,
|
|
85
|
+
],
|
|
86
|
+
});
|
|
87
|
+
return {
|
|
88
|
+
'as-provided': asProvidedOptions,
|
|
89
|
+
derived: undefined,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
throw new Error(`The provided new project name "${options.newProjectName}" is a scoped project name and this is not supported by the move generator when using the "derived" format. ` +
|
|
93
|
+
`Please provide a name without "@" or use the "as-provided" format.`);
|
|
96
94
|
}
|
|
95
|
+
const derivedOptions = getDerivedOptions(tree, { ...options, destination }, projectConfiguration);
|
|
97
96
|
return {
|
|
98
|
-
'as-provided':
|
|
99
|
-
|
|
100
|
-
newProjectName: asProvidedProjectName,
|
|
101
|
-
importPath: asProvidedImportPath,
|
|
102
|
-
},
|
|
103
|
-
derived: {
|
|
104
|
-
destination: derivedDestination,
|
|
105
|
-
newProjectName: derivedProjectName,
|
|
106
|
-
importPath: derivedImportPath,
|
|
107
|
-
},
|
|
97
|
+
'as-provided': asProvidedOptions,
|
|
98
|
+
derived: derivedOptions,
|
|
108
99
|
};
|
|
109
100
|
}
|
|
110
|
-
async function determineFormat(
|
|
101
|
+
async function determineFormat(formats) {
|
|
111
102
|
if (!formats.derived) {
|
|
112
103
|
return 'as-provided';
|
|
113
104
|
}
|
|
114
|
-
if (process.env.NX_INTERACTIVE !== 'true' || !isTTY()) {
|
|
115
|
-
return 'derived';
|
|
116
|
-
}
|
|
117
105
|
const asProvidedDescription = `As provided:
|
|
118
106
|
Name: ${formats['as-provided'].newProjectName}
|
|
119
107
|
Destination: ${formats['as-provided'].destination}`;
|
|
@@ -136,40 +124,59 @@ async function determineFormat(tree, formats, schema) {
|
|
|
136
124
|
name: derivedSelectedValue,
|
|
137
125
|
},
|
|
138
126
|
],
|
|
139
|
-
initial:
|
|
127
|
+
initial: 0,
|
|
140
128
|
}).then(({ format }) => format === asProvidedSelectedValue ? 'as-provided' : 'derived');
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
function logDeprecationMessage(formats, options) {
|
|
141
132
|
const callingGenerator = process.env.NX_ANGULAR_MOVE_INVOKED === 'true'
|
|
142
133
|
? '@nx/angular:move'
|
|
143
134
|
: '@nx/workspace:move';
|
|
144
|
-
|
|
145
|
-
In Nx
|
|
146
|
-
Please provide the exact new project name and destination in the future
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
nxJson.generators[callingGenerator] ??= {};
|
|
158
|
-
nxJson.generators[callingGenerator].projectNameAndRootFormat = result;
|
|
159
|
-
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
devkit_1.logger.warn(deprecationWarning);
|
|
163
|
-
}
|
|
135
|
+
devkit_1.logger.warn((0, devkit_1.stripIndents) `
|
|
136
|
+
In Nx 19, the project name and destination will no longer be derived.
|
|
137
|
+
Please provide the exact new project name and destination in the future.
|
|
138
|
+
Example: nx g ${callingGenerator} --projectName ${options.projectName} --destination ${formats['derived'].destination}` +
|
|
139
|
+
(options.projectName !== formats['derived'].newProjectName
|
|
140
|
+
? ` --newProjectName ${formats['derived'].newProjectName}`
|
|
141
|
+
: ''));
|
|
142
|
+
}
|
|
143
|
+
function getAsProvidedOptions(tree, options, projectConfiguration) {
|
|
144
|
+
const newProjectName = options.newProjectName ?? options.projectName;
|
|
145
|
+
const destination = options.destination;
|
|
146
|
+
if (projectConfiguration.projectType !== 'library') {
|
|
147
|
+
return { destination, newProjectName };
|
|
164
148
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
? ` --newProjectName ${formats[result].newProjectName}`
|
|
169
|
-
: '');
|
|
170
|
-
devkit_1.logger.warn(deprecationWarning + '\n' + example);
|
|
149
|
+
let importPath = options.importPath;
|
|
150
|
+
if (importPath) {
|
|
151
|
+
return { destination, newProjectName, importPath };
|
|
171
152
|
}
|
|
172
|
-
|
|
153
|
+
if (options.newProjectName?.startsWith('@')) {
|
|
154
|
+
// keep the existing import path if the name didn't change
|
|
155
|
+
importPath =
|
|
156
|
+
options.newProjectName && options.projectName !== options.newProjectName
|
|
157
|
+
? newProjectName
|
|
158
|
+
: undefined;
|
|
159
|
+
}
|
|
160
|
+
else if (options.newProjectName) {
|
|
161
|
+
const npmScope = (0, get_import_path_1.getNpmScope)(tree);
|
|
162
|
+
importPath = npmScope
|
|
163
|
+
? `${npmScope === '@' ? '' : '@'}${npmScope}/${newProjectName}`
|
|
164
|
+
: newProjectName;
|
|
165
|
+
}
|
|
166
|
+
return { destination, newProjectName, importPath };
|
|
167
|
+
}
|
|
168
|
+
function getDerivedOptions(tree, options, projectConfiguration) {
|
|
169
|
+
const newProjectName = options.newProjectName
|
|
170
|
+
? (0, devkit_1.names)(options.newProjectName).fileName
|
|
171
|
+
: (0, utils_1.getNewProjectName)(options.destination);
|
|
172
|
+
const destination = (0, utils_1.getDestination)(tree, options, projectConfiguration);
|
|
173
|
+
let importPath;
|
|
174
|
+
if (projectConfiguration.projectType === 'library') {
|
|
175
|
+
importPath =
|
|
176
|
+
options.importPath ??
|
|
177
|
+
(0, utils_1.normalizePathSlashes)((0, get_import_path_1.getImportPath)(tree, options.destination));
|
|
178
|
+
}
|
|
179
|
+
return { destination, newProjectName, importPath };
|
|
173
180
|
}
|
|
174
181
|
function isTTY() {
|
|
175
182
|
return !!process.stdout.isTTY && process.env['CI'] !== 'true';
|
|
@@ -124,7 +124,7 @@ function updateImportDeclarations(sourceFile, from, to) {
|
|
|
124
124
|
]);
|
|
125
125
|
const changes = [];
|
|
126
126
|
for (const { moduleSpecifier } of importDecls) {
|
|
127
|
-
if (tsModule.isStringLiteral(moduleSpecifier)) {
|
|
127
|
+
if (moduleSpecifier && tsModule.isStringLiteral(moduleSpecifier)) {
|
|
128
128
|
changes.push(...updateModuleSpecifier(moduleSpecifier, from, to));
|
|
129
129
|
}
|
|
130
130
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.updateJestConfig = void 0;
|
|
4
4
|
const path = require("path");
|
|
5
|
+
const jest_config_1 = require("../../utils/jest-config");
|
|
5
6
|
/**
|
|
6
7
|
* Updates the project name and coverage folder in the jest.config.js if it exists
|
|
7
8
|
*
|
|
@@ -34,13 +35,14 @@ function updateJestConfig(tree, schema, project) {
|
|
|
34
35
|
tree.write(jestConfigPath, newContent);
|
|
35
36
|
}
|
|
36
37
|
// update root jest.config.ts
|
|
37
|
-
const rootJestConfigPath =
|
|
38
|
-
if (!tree.exists(rootJestConfigPath)) {
|
|
38
|
+
const rootJestConfigPath = (0, jest_config_1.findRootJestConfig)(tree);
|
|
39
|
+
if (!rootJestConfigPath || !tree.exists(rootJestConfigPath)) {
|
|
39
40
|
return;
|
|
40
41
|
}
|
|
41
42
|
const findProject = `'<rootDir>/${project.root}'`;
|
|
42
43
|
const oldRootJestConfigContent = tree.read(rootJestConfigPath, 'utf-8');
|
|
43
|
-
const usingJestProjects = oldRootJestConfigContent.includes('getJestProjects()')
|
|
44
|
+
const usingJestProjects = oldRootJestConfigContent.includes('getJestProjects()') ||
|
|
45
|
+
oldRootJestConfigContent.includes('getJestProjectsAsync()');
|
|
44
46
|
const newRootJestConfigContent = oldRootJestConfigContent.replace(findProject, usingJestProjects ? `` : `'<rootDir>/${schema.relativeToRootDestination}'`);
|
|
45
47
|
tree.write(rootJestConfigPath, newRootJestConfigContent);
|
|
46
48
|
}
|
|
@@ -57,7 +57,7 @@ function updateFilesForNonRootProjects(tree, schema, project) {
|
|
|
57
57
|
const newRelativeRoot = path
|
|
58
58
|
.relative(path.join(devkit_1.workspaceRoot, schema.relativeToRootDestination), devkit_1.workspaceRoot)
|
|
59
59
|
.split(path.sep)
|
|
60
|
-
.join('/');
|
|
60
|
+
.join('/') + '/';
|
|
61
61
|
const oldRelativeRoot = path
|
|
62
62
|
.relative(path.join(devkit_1.workspaceRoot, project.root), devkit_1.workspaceRoot)
|
|
63
63
|
.split(path.sep)
|
|
@@ -67,7 +67,7 @@ function updateFilesForNonRootProjects(tree, schema, project) {
|
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
69
|
const dots = /\./g;
|
|
70
|
-
const regex = new RegExp(`(?<!\\.\\.\\/)${oldRelativeRoot.replace(dots, '\\.')}(
|
|
70
|
+
const regex = new RegExp(`(?<!\\.\\.\\/)${oldRelativeRoot.replace(dots, '\\.')}\/(?!\\.\\.\\/)`, 'g');
|
|
71
71
|
for (const file of tree.children(schema.relativeToRootDestination)) {
|
|
72
72
|
const ext = (0, path_1.extname)(file);
|
|
73
73
|
if (!allowedExt.includes(ext)) {
|
|
@@ -33,7 +33,6 @@ async function moveGeneratorInternal(tree, rawSchema) {
|
|
|
33
33
|
if (projectConfig.root === '.') {
|
|
34
34
|
(0, extract_base_configs_1.maybeExtractTsConfigBase)(tree);
|
|
35
35
|
await (0, extract_base_configs_1.maybeExtractJestConfigBase)(tree);
|
|
36
|
-
(0, extract_base_configs_1.maybeExtractEslintConfigIfRootProject)(tree, projectConfig);
|
|
37
36
|
// Reload config since it has been updated after extracting base configs
|
|
38
37
|
projectConfig = (0, devkit_1.readProjectConfiguration)(tree, rawSchema.projectName);
|
|
39
38
|
}
|
|
@@ -51,6 +50,10 @@ async function moveGeneratorInternal(tree, rawSchema) {
|
|
|
51
50
|
(0, update_build_targets_1.updateBuildTargets)(tree, schema);
|
|
52
51
|
(0, update_default_project_1.updateDefaultProject)(tree, schema);
|
|
53
52
|
(0, update_implicit_dependencies_1.updateImplicitDependencies)(tree, schema);
|
|
53
|
+
if (projectConfig.root === '.') {
|
|
54
|
+
// we want to migrate eslint config once the root project files are moved
|
|
55
|
+
(0, extract_base_configs_1.maybeMigrateEslintConfigIfRootProject)(tree, projectConfig);
|
|
56
|
+
}
|
|
54
57
|
await (0, run_angular_plugin_1.runAngularPlugin)(tree, schema);
|
|
55
58
|
if (!schema.skipFormat) {
|
|
56
59
|
await (0, devkit_1.formatFiles)(tree);
|
|
@@ -2,60 +2,86 @@
|
|
|
2
2
|
|
|
3
3
|
<a alt="Nx logo" href="https://nx.dev" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-logo.png" width="45"></a>
|
|
4
4
|
|
|
5
|
-
✨ **This workspace has been generated by [Nx,
|
|
5
|
+
✨ **This workspace has been generated by [Nx, Smart Monorepos · Fast CI.](https://nx.dev)** ✨
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
## Start the app
|
|
7
|
+
## Integrate with editors
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
Enhance your Nx experience by installing [Nx Console](https://nx.dev/nx-console) for your favorite editor. Nx Console
|
|
10
|
+
provides an interactive UI to view your projects, run tasks, generate code, and more! Available for VSCode, IntelliJ and
|
|
11
|
+
comes with a LSP for Vim users.
|
|
12
|
+
<% if (!!appName) {
|
|
13
|
+
if (isJsStandalone) { %>
|
|
14
|
+
## Build the library
|
|
15
|
+
|
|
16
|
+
Run `npx nx build` to build the library. The build artifacts are stored in the output directory (i.e. `dist/`), ready to be published.
|
|
17
|
+
<% } else { %>
|
|
18
|
+
## Start the application
|
|
19
|
+
|
|
20
|
+
Run `npx nx <%= serveCommand %> <%= appName %>` to start the development server. Happy coding!
|
|
12
21
|
|
|
13
|
-
##
|
|
22
|
+
## Build for production
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
Run `npx nx build <%= appName %>` to build the application. The build artifacts are stored in the output directory (e.g. `dist/` or `build/`), ready to be deployed.
|
|
25
|
+
<% } } else { %>
|
|
26
|
+
## Nx plugins and code generators
|
|
16
27
|
|
|
17
|
-
|
|
28
|
+
Add Nx plugins to leverage their code generators and automated, inferred tasks.
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
# Add plugin
|
|
32
|
+
npx nx add @nx/react
|
|
33
|
+
|
|
34
|
+
# Use code generator
|
|
35
|
+
npx nx generate @nx/react:app demo
|
|
36
|
+
|
|
37
|
+
# Run development server
|
|
38
|
+
npx nx serve demo
|
|
39
|
+
|
|
40
|
+
# View project details
|
|
41
|
+
npx nx show project demo --web
|
|
42
|
+
```
|
|
18
43
|
|
|
19
|
-
|
|
44
|
+
Run `npx nx list` to get a list of available plugins and whether they have generators. Then run `npx nx list <plugin-name>` to see what generators are available.
|
|
20
45
|
|
|
46
|
+
Learn more about [code generators](https://nx.dev/features/generate-code) and [inferred tasks](https://nx.dev/concepts/inferred-tasks) in the docs.
|
|
47
|
+
<% } %>
|
|
21
48
|
## Running tasks
|
|
22
49
|
|
|
23
50
|
To execute tasks with Nx use the following syntax:
|
|
24
51
|
|
|
25
52
|
```
|
|
26
|
-
nx <target> <project> <...options>
|
|
53
|
+
npx nx <target> <project> <...options>
|
|
27
54
|
```
|
|
28
55
|
|
|
29
56
|
You can also run multiple targets:
|
|
30
57
|
|
|
31
58
|
```
|
|
32
|
-
nx run-many -t <target1> <target2>
|
|
59
|
+
npx nx run-many -t <target1> <target2>
|
|
33
60
|
```
|
|
34
61
|
|
|
35
62
|
..or add `-p` to filter specific projects
|
|
36
63
|
|
|
37
64
|
```
|
|
38
|
-
nx run-many -t <target1> <target2> -p <proj1> <proj2>
|
|
65
|
+
npx nx run-many -t <target1> <target2> -p <proj1> <proj2>
|
|
39
66
|
```
|
|
40
67
|
|
|
41
|
-
Targets can be defined in the `package.json` or `projects.json`. Learn more [in the docs](https://nx.dev/
|
|
42
|
-
|
|
43
|
-
## Want better Editor Integration?
|
|
44
|
-
|
|
45
|
-
Have a look at the [Nx Console extensions](https://nx.dev/nx-console). It provides autocomplete support, a UI for exploring and running tasks & generators, and more! Available for VSCode, IntelliJ and comes with a LSP for Vim users.
|
|
46
|
-
|
|
47
|
-
## Ready to deploy?
|
|
48
|
-
|
|
49
|
-
Just run `nx build demoapp` to build the application. The build artifacts will be stored in the `dist/` directory, ready to be deployed.
|
|
68
|
+
Targets can be defined in the `package.json` or `projects.json`. Learn more [in the docs](https://nx.dev/features/run-tasks).
|
|
50
69
|
|
|
51
70
|
## Set up CI!
|
|
52
71
|
|
|
53
72
|
Nx comes with local caching already built-in (check your `nx.json`). On CI you might want to go a step further.
|
|
54
73
|
|
|
55
|
-
- [Set up remote caching](https://nx.dev/
|
|
56
|
-
- [Set up task distribution across multiple machines](https://nx.dev/
|
|
74
|
+
- [Set up remote caching](https://nx.dev/features/share-your-cache)
|
|
75
|
+
- [Set up task distribution across multiple machines](https://nx.dev/nx-cloud/features/distribute-task-execution)
|
|
57
76
|
- [Learn more how to setup CI](https://nx.dev/recipes/ci)
|
|
58
77
|
|
|
78
|
+
## Explore the project graph
|
|
79
|
+
|
|
80
|
+
Run `npx nx graph` to show the graph of the workspace.
|
|
81
|
+
It will show tasks that you can run with Nx.
|
|
82
|
+
|
|
83
|
+
- [Learn more about Exploring the Project Graph](https://nx.dev/core-features/explore-graph)
|
|
84
|
+
|
|
59
85
|
## Connect with us!
|
|
60
86
|
|
|
61
87
|
- [Join the community](https://nx.dev/community)
|
|
@@ -56,6 +56,7 @@ function generatePreset(host, opts) {
|
|
|
56
56
|
opts.docker ? `--docker=${opts.docker}` : null,
|
|
57
57
|
opts.js ? `--js` : null,
|
|
58
58
|
opts.nextAppDir ? '--nextAppDir=true' : '--nextAppDir=false',
|
|
59
|
+
opts.nextSrcDir ? '--nextSrcDir=true' : '--nextSrcDir=false',
|
|
59
60
|
opts.packageManager ? `--packageManager=${opts.packageManager}` : null,
|
|
60
61
|
opts.standaloneApi !== undefined
|
|
61
62
|
? `--standaloneApi=${opts.standaloneApi}`
|
|
@@ -65,6 +66,8 @@ function generatePreset(host, opts) {
|
|
|
65
66
|
opts.e2eTestRunner !== undefined
|
|
66
67
|
? `--e2eTestRunner=${opts.e2eTestRunner}`
|
|
67
68
|
: null,
|
|
69
|
+
opts.ssr ? `--ssr` : null,
|
|
70
|
+
opts.prefix !== undefined ? `--prefix=${opts.prefix}` : null,
|
|
68
71
|
].filter((e) => !!e);
|
|
69
72
|
}
|
|
70
73
|
}
|
|
@@ -95,6 +98,9 @@ function getPresetDependencies({ preset, presetVersion, bundler, e2eTestRunner,
|
|
|
95
98
|
case presets_1.Preset.NextJs:
|
|
96
99
|
case presets_1.Preset.NextJsStandalone:
|
|
97
100
|
return { dependencies: { '@nx/next': versions_1.nxVersion }, dev: {} };
|
|
101
|
+
case presets_1.Preset.RemixStandalone:
|
|
102
|
+
case presets_1.Preset.RemixMonorepo:
|
|
103
|
+
return { dependencies: { '@nx/remix': versions_1.nxVersion }, dev: {} };
|
|
98
104
|
case presets_1.Preset.VueMonorepo:
|
|
99
105
|
case presets_1.Preset.VueStandalone:
|
|
100
106
|
return {
|
|
@@ -106,6 +112,16 @@ function getPresetDependencies({ preset, presetVersion, bundler, e2eTestRunner,
|
|
|
106
112
|
'@nx/vite': versions_1.nxVersion,
|
|
107
113
|
},
|
|
108
114
|
};
|
|
115
|
+
case presets_1.Preset.Nuxt:
|
|
116
|
+
case presets_1.Preset.NuxtStandalone:
|
|
117
|
+
return {
|
|
118
|
+
dependencies: {},
|
|
119
|
+
dev: {
|
|
120
|
+
'@nx/nuxt': versions_1.nxVersion,
|
|
121
|
+
'@nx/cypress': e2eTestRunner === 'cypress' ? versions_1.nxVersion : undefined,
|
|
122
|
+
'@nx/playwright': e2eTestRunner === 'playwright' ? versions_1.nxVersion : undefined,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
109
125
|
case presets_1.Preset.ReactMonorepo:
|
|
110
126
|
case presets_1.Preset.ReactStandalone:
|
|
111
127
|
return {
|
|
@@ -45,27 +45,21 @@ function setPresetProperty(tree, options) {
|
|
|
45
45
|
function createNxJson(tree, { directory, defaultBase, preset }) {
|
|
46
46
|
const nxJson = {
|
|
47
47
|
$schema: './node_modules/nx/schemas/nx-schema.json',
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
cache: true,
|
|
61
|
-
},
|
|
62
|
-
e2e: {
|
|
63
|
-
cache: true,
|
|
64
|
-
},
|
|
65
|
-
},
|
|
48
|
+
defaultBase,
|
|
49
|
+
targetDefaults: process.env.NX_ADD_PLUGINS === 'false'
|
|
50
|
+
? {
|
|
51
|
+
build: {
|
|
52
|
+
cache: true,
|
|
53
|
+
dependsOn: ['^build'],
|
|
54
|
+
},
|
|
55
|
+
lint: {
|
|
56
|
+
cache: true,
|
|
57
|
+
},
|
|
58
|
+
}
|
|
59
|
+
: undefined,
|
|
66
60
|
};
|
|
67
61
|
if (defaultBase === 'main') {
|
|
68
|
-
delete nxJson.
|
|
62
|
+
delete nxJson.defaultBase;
|
|
69
63
|
}
|
|
70
64
|
if (preset !== presets_1.Preset.NPM) {
|
|
71
65
|
nxJson.namedInputs = {
|
|
@@ -73,7 +67,10 @@ function createNxJson(tree, { directory, defaultBase, preset }) {
|
|
|
73
67
|
production: ['default'],
|
|
74
68
|
sharedGlobals: [],
|
|
75
69
|
};
|
|
76
|
-
|
|
70
|
+
if (process.env.NX_ADD_PLUGINS === 'false') {
|
|
71
|
+
nxJson.targetDefaults.build.inputs = ['production', '^production'];
|
|
72
|
+
nxJson.useInferencePlugins = false;
|
|
73
|
+
}
|
|
77
74
|
}
|
|
78
75
|
(0, devkit_1.writeJson)(tree, (0, path_1.join)(directory, 'nx.json'), nxJson);
|
|
79
76
|
}
|
|
@@ -82,8 +79,10 @@ function createFiles(tree, options) {
|
|
|
82
79
|
const filesDirName = options.preset === presets_1.Preset.AngularStandalone ||
|
|
83
80
|
options.preset === presets_1.Preset.ReactStandalone ||
|
|
84
81
|
options.preset === presets_1.Preset.VueStandalone ||
|
|
82
|
+
options.preset === presets_1.Preset.NuxtStandalone ||
|
|
85
83
|
options.preset === presets_1.Preset.NodeStandalone ||
|
|
86
84
|
options.preset === presets_1.Preset.NextJsStandalone ||
|
|
85
|
+
options.preset === presets_1.Preset.RemixStandalone ||
|
|
87
86
|
options.preset === presets_1.Preset.TsStandalone
|
|
88
87
|
? './files-root-app'
|
|
89
88
|
: options.preset === presets_1.Preset.NPM
|
|
@@ -104,8 +103,11 @@ function createReadme(tree, { name, appName, directory, preset }) {
|
|
|
104
103
|
const formattedNames = (0, devkit_1.names)(name);
|
|
105
104
|
(0, devkit_1.generateFiles)(tree, (0, path_1.join)(__dirname, './files-readme'), directory, {
|
|
106
105
|
formattedNames,
|
|
107
|
-
|
|
106
|
+
isJsStandalone: preset === presets_1.Preset.TsStandalone,
|
|
108
107
|
appName,
|
|
108
|
+
serveCommand: preset === presets_1.Preset.NextJs || preset === presets_1.Preset.NextJsStandalone
|
|
109
|
+
? 'dev'
|
|
110
|
+
: 'serve',
|
|
109
111
|
name,
|
|
110
112
|
});
|
|
111
113
|
}
|
|
@@ -121,8 +123,8 @@ function addNpmScripts(tree, options) {
|
|
|
121
123
|
if (options.preset === presets_1.Preset.AngularStandalone ||
|
|
122
124
|
options.preset === presets_1.Preset.ReactStandalone ||
|
|
123
125
|
options.preset === presets_1.Preset.VueStandalone ||
|
|
124
|
-
options.preset === presets_1.Preset.
|
|
125
|
-
options.preset === presets_1.Preset.
|
|
126
|
+
options.preset === presets_1.Preset.NuxtStandalone ||
|
|
127
|
+
options.preset === presets_1.Preset.NodeStandalone) {
|
|
126
128
|
(0, devkit_1.updateJson)(tree, (0, path_1.join)(options.directory, 'package.json'), (json) => {
|
|
127
129
|
Object.assign(json.scripts, {
|
|
128
130
|
start: 'nx serve',
|
|
@@ -132,6 +134,17 @@ function addNpmScripts(tree, options) {
|
|
|
132
134
|
return json;
|
|
133
135
|
});
|
|
134
136
|
}
|
|
137
|
+
if (options.preset === presets_1.Preset.NextJsStandalone) {
|
|
138
|
+
(0, devkit_1.updateJson)(tree, (0, path_1.join)(options.directory, 'package.json'), (json) => {
|
|
139
|
+
Object.assign(json.scripts, {
|
|
140
|
+
dev: 'nx dev',
|
|
141
|
+
build: 'nx build',
|
|
142
|
+
start: 'nx start',
|
|
143
|
+
test: 'nx test',
|
|
144
|
+
});
|
|
145
|
+
return json;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
135
148
|
if (options.preset === presets_1.Preset.TsStandalone) {
|
|
136
149
|
(0, devkit_1.updateJson)(tree, (0, path_1.join)(options.directory, 'package.json'), (json) => {
|
|
137
150
|
Object.assign(json.scripts, {
|
|
@@ -12,12 +12,15 @@ interface Schema {
|
|
|
12
12
|
docker?: boolean;
|
|
13
13
|
js?: boolean;
|
|
14
14
|
nextAppDir?: boolean;
|
|
15
|
+
nextSrcDir?: boolean;
|
|
15
16
|
linter?: Linter;
|
|
16
17
|
bundler?: 'vite' | 'webpack';
|
|
17
18
|
standaloneApi?: boolean;
|
|
18
19
|
routing?: boolean;
|
|
19
20
|
packageManager?: PackageManager;
|
|
20
21
|
e2eTestRunner?: 'cypress' | 'playwright' | 'detox' | 'jest' | 'none';
|
|
22
|
+
ssr?: boolean;
|
|
23
|
+
prefix?: string;
|
|
21
24
|
}
|
|
22
25
|
export interface NormalizedSchema extends Schema {
|
|
23
26
|
presetVersion?: string;
|