@nx/react 18.0.0-beta.1 → 18.0.0-beta.2
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/generators.json +1 -1
- package/package.json +6 -7
- package/plugins/component-testing/index.js +32 -9
- package/plugins/nx-react-webpack-plugin/lib/apply-react-config.js +0 -6
- package/src/generators/application/application.js +5 -0
- package/src/generators/application/files/nx-welcome/src/app/nx-welcome.tsx +19 -0
- package/src/generators/application/lib/add-e2e.js +1 -0
- package/src/generators/application/lib/add-project.js +1 -1
- package/src/generators/application/lib/normalize-options.js +1 -0
- package/src/generators/application/schema.d.ts +2 -0
- package/src/generators/cypress-component-configuration/cypress-component-configuration.d.ts +2 -1
- package/src/generators/cypress-component-configuration/cypress-component-configuration.js +14 -4
- package/src/generators/cypress-component-configuration/lib/add-files.js +1 -6
- package/src/generators/cypress-component-configuration/schema.d.ts +1 -0
- package/src/generators/host/files/module-federation-ts/webpack.config.prod.ts__tmpl__ +2 -1
- package/src/generators/host/files/module-federation-ts/webpack.config.ts__tmpl__ +2 -2
- package/src/generators/host/host.js +2 -0
- package/src/generators/host/schema.d.ts +2 -0
- package/src/generators/library/lib/add-linting.js +1 -0
- package/src/generators/library/lib/normalize-options.js +2 -1
- package/src/generators/library/library.js +3 -0
- package/src/generators/library/schema.d.ts +1 -0
- package/src/generators/remote/remote.js +2 -0
- package/src/generators/setup-ssr/setup-ssr.js +16 -4
- package/src/generators/stories/stories.js +15 -3
- package/src/generators/storybook-configuration/configuration.d.ts +1 -0
- package/src/generators/storybook-configuration/configuration.js +14 -4
- package/src/generators/storybook-configuration/schema.d.ts +1 -0
- package/src/module-federation/with-module-federation-ssr.js +3 -0
- package/src/module-federation/with-module-federation.js +3 -0
- package/src/utils/ct-utils.d.ts +6 -1
- package/src/utils/ct-utils.js +30 -9
package/generators.json
CHANGED
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"aliases": ["slice"]
|
|
38
38
|
},
|
|
39
39
|
"storybook-configuration": {
|
|
40
|
-
"factory": "./src/generators/storybook-configuration/configuration#
|
|
40
|
+
"factory": "./src/generators/storybook-configuration/configuration#storybookConfigurationGeneratorInternal",
|
|
41
41
|
"schema": "./src/generators/storybook-configuration/schema.json",
|
|
42
42
|
"description": "Set up storybook for a React app or library.",
|
|
43
43
|
"hidden": false
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/react",
|
|
3
|
-
"version": "18.0.0-beta.
|
|
3
|
+
"version": "18.0.0-beta.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The React plugin for Nx contains executors and generators for managing React applications and libraries within an Nx workspace. It provides:\n\n\n- Integration with libraries such as Jest, Cypress, and Storybook.\n\n- Generators for applications, libraries, components, hooks, and more.\n\n- Library build support for publishing packages to npm or other registries.\n\n- Utilities for automatic workspace refactoring.",
|
|
6
6
|
"repository": {
|
|
@@ -34,14 +34,13 @@
|
|
|
34
34
|
"@phenomnomnominal/tsquery": "~5.0.1",
|
|
35
35
|
"@svgr/webpack": "^8.0.1",
|
|
36
36
|
"chalk": "^4.1.0",
|
|
37
|
-
"file-loader": "^6.2.0",
|
|
38
37
|
"minimatch": "9.0.3",
|
|
39
38
|
"tslib": "^2.3.0",
|
|
40
|
-
"@nx/devkit": "18.0.0-beta.
|
|
41
|
-
"@nx/js": "18.0.0-beta.
|
|
42
|
-
"@nx/eslint": "18.0.0-beta.
|
|
43
|
-
"@nx/web": "18.0.0-beta.
|
|
44
|
-
"@nrwl/react": "18.0.0-beta.
|
|
39
|
+
"@nx/devkit": "18.0.0-beta.2",
|
|
40
|
+
"@nx/js": "18.0.0-beta.2",
|
|
41
|
+
"@nx/eslint": "18.0.0-beta.2",
|
|
42
|
+
"@nx/web": "18.0.0-beta.2",
|
|
43
|
+
"@nrwl/react": "18.0.0-beta.2"
|
|
45
44
|
},
|
|
46
45
|
"publishConfig": {
|
|
47
46
|
"access": "public"
|
|
@@ -25,12 +25,17 @@ const path_1 = require("path");
|
|
|
25
25
|
* @param options override options
|
|
26
26
|
*/
|
|
27
27
|
function nxComponentTestingPreset(pathToConfig, options) {
|
|
28
|
-
const normalizedProjectRootPath = ['.ts', '.js'].some((ext) => pathToConfig.endsWith(ext))
|
|
29
|
-
? pathToConfig
|
|
30
|
-
: (0, path_1.dirname)(pathToConfig);
|
|
31
28
|
const basePresetSettings = (0, cypress_preset_1.nxBaseCypressPreset)(pathToConfig, {
|
|
32
29
|
testingType: 'component',
|
|
33
30
|
});
|
|
31
|
+
if (global.NX_GRAPH_CREATION || global.NX_CYPRESS_INIT_GENERATOR_RUNNING) {
|
|
32
|
+
// this is only used by plugins, so we don't need the component testing
|
|
33
|
+
// options, cast to any to avoid type errors
|
|
34
|
+
return basePresetSettings;
|
|
35
|
+
}
|
|
36
|
+
const normalizedProjectRootPath = ['.ts', '.js'].some((ext) => pathToConfig.endsWith(ext))
|
|
37
|
+
? pathToConfig
|
|
38
|
+
: (0, path_1.dirname)(pathToConfig);
|
|
34
39
|
if (options?.bundler === 'vite') {
|
|
35
40
|
return {
|
|
36
41
|
...basePresetSettings,
|
|
@@ -66,18 +71,24 @@ function nxComponentTestingPreset(pathToConfig, options) {
|
|
|
66
71
|
const ctTargetName = options?.ctTargetName || 'component-test';
|
|
67
72
|
const ctConfigurationName = process.env.NX_CYPRESS_TARGET_CONFIGURATION;
|
|
68
73
|
const ctExecutorContext = (0, ct_helpers_1.createExecutorContext)(graph, ctTargets, ctProjectName, ctTargetName, ctConfigurationName);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
let buildTarget = options?.buildTarget;
|
|
75
|
+
if (!buildTarget) {
|
|
76
|
+
const ctExecutorOptions = (0, devkit_1.readTargetOptions)({
|
|
77
|
+
project: ctProjectName,
|
|
78
|
+
target: ctTargetName,
|
|
79
|
+
configuration: ctConfigurationName,
|
|
80
|
+
}, ctExecutorContext);
|
|
81
|
+
buildTarget = ctExecutorOptions.devServerTarget;
|
|
82
|
+
}
|
|
75
83
|
if (!buildTarget) {
|
|
76
84
|
throw new Error(`Unable to find the 'devServerTarget' executor option in the '${ctTargetName}' target of the '${ctProjectName}' project`);
|
|
77
85
|
}
|
|
78
86
|
webpackConfig = buildTargetWebpack(ctExecutorContext, buildTarget, ctProjectName);
|
|
79
87
|
}
|
|
80
88
|
catch (e) {
|
|
89
|
+
if (e instanceof InvalidExecutorError) {
|
|
90
|
+
throw e;
|
|
91
|
+
}
|
|
81
92
|
devkit_1.logger.warn((0, devkit_1.stripIndents) `Unable to build a webpack config with the project graph.
|
|
82
93
|
Falling back to default webpack config.`);
|
|
83
94
|
devkit_1.logger.warn(e);
|
|
@@ -137,6 +148,11 @@ function buildTargetWebpack(ctx, buildTarget, componentTestingProjectName) {
|
|
|
137
148
|
Has component config? ${!!ctProjectConfig}
|
|
138
149
|
`);
|
|
139
150
|
}
|
|
151
|
+
if (buildableProjectConfig.targets[parsed.target].executor !==
|
|
152
|
+
'@nx/webpack:webpack') {
|
|
153
|
+
throw new InvalidExecutorError(`The '${parsed.target}' target of the '${parsed.project}' project is not using the '@nx/webpack:webpack' executor. ` +
|
|
154
|
+
`Please make sure to use '@nx/webpack:webpack' executor in that target to use Cypress Component Testing.`);
|
|
155
|
+
}
|
|
140
156
|
const context = (0, ct_helpers_1.createExecutorContext)(graph, buildableProjectConfig.targets, parsed.project, parsed.target, parsed.target);
|
|
141
157
|
const { normalizeOptions, } = require('@nx/webpack/src/executors/webpack/lib/normalize-options');
|
|
142
158
|
const { resolveUserDefinedWebpackConfig, } = require('@nx/webpack/src/utils/webpack/resolve-user-defined-webpack-config');
|
|
@@ -197,3 +213,10 @@ function findTsConfig(projectRoot) {
|
|
|
197
213
|
}
|
|
198
214
|
}
|
|
199
215
|
}
|
|
216
|
+
class InvalidExecutorError extends Error {
|
|
217
|
+
constructor(message) {
|
|
218
|
+
super(message);
|
|
219
|
+
this.message = message;
|
|
220
|
+
this.name = 'InvalidExecutorError';
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -36,6 +36,7 @@ async function addLinting(host, options) {
|
|
|
36
36
|
skipFormat: true,
|
|
37
37
|
rootProject: options.rootProject,
|
|
38
38
|
skipPackageJson: options.skipPackageJson,
|
|
39
|
+
addPlugin: options.addPlugin,
|
|
39
40
|
});
|
|
40
41
|
tasks.push(lintTask);
|
|
41
42
|
if ((0, eslint_file_1.isEslintConfigSupported)(host)) {
|
|
@@ -51,6 +52,7 @@ async function addLinting(host, options) {
|
|
|
51
52
|
}
|
|
52
53
|
async function applicationGenerator(host, schema) {
|
|
53
54
|
return await applicationGeneratorInternal(host, {
|
|
55
|
+
addPlugin: false,
|
|
54
56
|
projectNameAndRootFormat: 'derived',
|
|
55
57
|
...schema,
|
|
56
58
|
});
|
|
@@ -76,6 +78,7 @@ async function applicationGeneratorInternal(host, schema) {
|
|
|
76
78
|
const webpackInitTask = await webpackInitGenerator(host, {
|
|
77
79
|
skipPackageJson: options.skipPackageJson,
|
|
78
80
|
skipFormat: true,
|
|
81
|
+
addPlugin: options.addPlugin,
|
|
79
82
|
});
|
|
80
83
|
tasks.push(webpackInitTask);
|
|
81
84
|
if (!options.skipPackageJson) {
|
|
@@ -103,6 +106,7 @@ async function applicationGeneratorInternal(host, schema) {
|
|
|
103
106
|
inSourceTests: options.inSourceTests,
|
|
104
107
|
compiler: options.compiler,
|
|
105
108
|
skipFormat: true,
|
|
109
|
+
addPlugin: options.addPlugin,
|
|
106
110
|
});
|
|
107
111
|
tasks.push(viteTask);
|
|
108
112
|
createOrEditViteConfig(host, {
|
|
@@ -143,6 +147,7 @@ async function applicationGeneratorInternal(host, schema) {
|
|
|
143
147
|
project: options.projectName,
|
|
144
148
|
inSourceTests: options.inSourceTests,
|
|
145
149
|
skipFormat: true,
|
|
150
|
+
addPlugin: options.addPlugin,
|
|
146
151
|
});
|
|
147
152
|
tasks.push(vitestTask);
|
|
148
153
|
createOrEditViteConfig(host, {
|
|
@@ -795,6 +795,25 @@ export function NxWelcome({ title }: { title: string }) {
|
|
|
795
795
|
nx g @nx/react:component ui/src/lib/button
|
|
796
796
|
</pre>
|
|
797
797
|
</details>
|
|
798
|
+
<details>
|
|
799
|
+
<summary>
|
|
800
|
+
<svg
|
|
801
|
+
fill="none"
|
|
802
|
+
stroke="currentColor"
|
|
803
|
+
viewBox="0 0 24 24"
|
|
804
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
805
|
+
>
|
|
806
|
+
<path
|
|
807
|
+
strokeLinecap="round"
|
|
808
|
+
strokeLinejoin="round"
|
|
809
|
+
strokeWidth="2"
|
|
810
|
+
d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
|
811
|
+
/>
|
|
812
|
+
</svg>
|
|
813
|
+
View project details
|
|
814
|
+
</summary>
|
|
815
|
+
<pre>nx show project {title} --web</pre>
|
|
816
|
+
</details>
|
|
798
817
|
<details>
|
|
799
818
|
<summary>
|
|
800
819
|
<svg
|
|
@@ -68,6 +68,7 @@ async function addE2e(tree, options) {
|
|
|
68
68
|
webServerCommand: `${(0, devkit_1.getPackageManagerCommand)().exec} nx serve ${options.name}`,
|
|
69
69
|
webServerAddress: 'http://localhost:4200',
|
|
70
70
|
rootProject: options.rootProject,
|
|
71
|
+
addPlugin: options.addPlugin,
|
|
71
72
|
});
|
|
72
73
|
}
|
|
73
74
|
case 'none':
|
|
@@ -12,7 +12,7 @@ function addProject(host, options) {
|
|
|
12
12
|
tags: options.parsedTags,
|
|
13
13
|
};
|
|
14
14
|
if (options.bundler === 'webpack') {
|
|
15
|
-
if (!(0, has_webpack_plugin_1.hasWebpackPlugin)(host)) {
|
|
15
|
+
if (!(0, has_webpack_plugin_1.hasWebpackPlugin)(host) || !options.addPlugin) {
|
|
16
16
|
project.targets = {
|
|
17
17
|
build: createBuildTarget(options),
|
|
18
18
|
serve: createServeTarget(options),
|
|
@@ -26,6 +26,7 @@ async function normalizeOptions(host, options, callingGenerator = '@nx/react:app
|
|
|
26
26
|
rootProject: options.rootProject,
|
|
27
27
|
callingGenerator,
|
|
28
28
|
});
|
|
29
|
+
options.addPlugin ??= process.env.NX_ADD_PLUGINS !== 'false';
|
|
29
30
|
options.rootProject = appProjectRoot === '.';
|
|
30
31
|
options.projectNameAndRootFormat = projectNameAndRootFormat;
|
|
31
32
|
const e2eProjectName = options.rootProject ? 'e2e' : `${appProjectName}-e2e`;
|
|
@@ -28,6 +28,7 @@ export interface Schema {
|
|
|
28
28
|
rootProject?: boolean;
|
|
29
29
|
bundler?: 'webpack' | 'vite' | 'rspack';
|
|
30
30
|
minimal?: boolean;
|
|
31
|
+
addPlugin?: boolean;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export interface NormalizedSchema<T extends Schema = Schema> extends T {
|
|
@@ -40,4 +41,5 @@ export interface NormalizedSchema<T extends Schema = Schema> extends T {
|
|
|
40
41
|
styledModule: null | SupportedStyles;
|
|
41
42
|
hasStyles: boolean;
|
|
42
43
|
unitTestRunner: 'jest' | 'vitest' | 'none';
|
|
44
|
+
addPlugin?: boolean;
|
|
43
45
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { Tree } from '@nx/devkit';
|
|
2
2
|
import { CypressComponentConfigurationSchema } from './schema.d';
|
|
3
|
+
export declare function cypressComponentConfigGenerator(tree: Tree, options: CypressComponentConfigurationSchema): Promise<import("@nx/devkit").GeneratorCallback>;
|
|
3
4
|
/**
|
|
4
5
|
* This is for using cypresses own Component testing, if you want to use test
|
|
5
6
|
* storybook components then use componentCypressGenerator instead.
|
|
6
7
|
*
|
|
7
8
|
*/
|
|
8
|
-
export declare function
|
|
9
|
+
export declare function cypressComponentConfigGeneratorInternal(tree: Tree, options: CypressComponentConfigurationSchema): Promise<import("@nx/devkit").GeneratorCallback>;
|
|
9
10
|
export default cypressComponentConfigGenerator;
|
|
@@ -1,26 +1,36 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.cypressComponentConfigGenerator = void 0;
|
|
3
|
+
exports.cypressComponentConfigGeneratorInternal = exports.cypressComponentConfigGenerator = void 0;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
5
|
const versions_1 = require("../../utils/versions");
|
|
6
6
|
const add_files_1 = require("./lib/add-files");
|
|
7
7
|
const ct_utils_1 = require("../../utils/ct-utils");
|
|
8
|
+
function cypressComponentConfigGenerator(tree, options) {
|
|
9
|
+
return cypressComponentConfigGeneratorInternal(tree, {
|
|
10
|
+
addPlugin: false,
|
|
11
|
+
...options,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
exports.cypressComponentConfigGenerator = cypressComponentConfigGenerator;
|
|
8
15
|
/**
|
|
9
16
|
* This is for using cypresses own Component testing, if you want to use test
|
|
10
17
|
* storybook components then use componentCypressGenerator instead.
|
|
11
18
|
*
|
|
12
19
|
*/
|
|
13
|
-
async function
|
|
20
|
+
async function cypressComponentConfigGeneratorInternal(tree, options) {
|
|
14
21
|
const { componentConfigurationGenerator: baseCyCtConfig } = (0, devkit_1.ensurePackage)('@nx/cypress', versions_1.nxVersion);
|
|
22
|
+
options.addPlugin ??= process.env.NX_ADD_PLUGINS !== 'false';
|
|
15
23
|
const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
|
|
16
24
|
const installTask = await baseCyCtConfig(tree, {
|
|
17
25
|
project: options.project,
|
|
18
26
|
skipFormat: true,
|
|
19
27
|
jsx: true,
|
|
28
|
+
addPlugin: options.addPlugin,
|
|
20
29
|
});
|
|
21
|
-
const found = await (0, ct_utils_1.
|
|
30
|
+
const found = await (0, ct_utils_1.configureCypressCT)(tree, {
|
|
22
31
|
project: options.project,
|
|
23
32
|
buildTarget: options.buildTarget,
|
|
33
|
+
bundler: options.bundler,
|
|
24
34
|
validExecutorNames: new Set([
|
|
25
35
|
'@nx/webpack:webpack',
|
|
26
36
|
'@nx/vite:build',
|
|
@@ -34,5 +44,5 @@ async function cypressComponentConfigGenerator(tree, options) {
|
|
|
34
44
|
}
|
|
35
45
|
return installTask;
|
|
36
46
|
}
|
|
37
|
-
exports.
|
|
47
|
+
exports.cypressComponentConfigGeneratorInternal = cypressComponentConfigGeneratorInternal;
|
|
38
48
|
exports.default = cypressComponentConfigGenerator;
|
|
@@ -10,9 +10,7 @@ async function addFiles(tree, projectConfig, options, found) {
|
|
|
10
10
|
// when importing react
|
|
11
11
|
const { addMountDefinition, addDefaultCTConfig } = await Promise.resolve().then(() => require('@nx/cypress/src/utils/config'));
|
|
12
12
|
// Specifically undefined to allow Remix workaround of passing an empty string
|
|
13
|
-
const actualBundler =
|
|
14
|
-
? options.bundler
|
|
15
|
-
: await (0, ct_utils_1.getBundlerFromTarget)(found, tree);
|
|
13
|
+
const actualBundler = await (0, ct_utils_1.getActualBundler)(tree, options, found);
|
|
16
14
|
if (options.bundler && options.bundler !== actualBundler) {
|
|
17
15
|
devkit_1.logger.warn(`You have specified ${options.bundler} as the bundler but this project is configured to use ${actualBundler}.
|
|
18
16
|
This may cause errors. If you are seeing errors, try removing the --bundler option.`);
|
|
@@ -21,9 +19,6 @@ async function addFiles(tree, projectConfig, options, found) {
|
|
|
21
19
|
const commandFile = (0, devkit_1.joinPathFragments)(projectConfig.root, 'cypress', 'support', 'component.ts');
|
|
22
20
|
const updatedCommandFile = await addMountDefinition(tree.read(commandFile, 'utf-8'));
|
|
23
21
|
tree.write(commandFile, `import { mount } from 'cypress/react18';\n${updatedCommandFile}`);
|
|
24
|
-
const cyFile = (0, devkit_1.joinPathFragments)(projectConfig.root, 'cypress.config.ts');
|
|
25
|
-
const updatedCyConfig = await addDefaultCTConfig(tree.read(cyFile, 'utf-8'), { bundler: bundlerToUse });
|
|
26
|
-
tree.write(cyFile, `import { nxComponentTestingPreset } from '@nx/react/plugins/component-testing';\n${updatedCyConfig}`);
|
|
27
22
|
if (options.bundler === 'webpack' ||
|
|
28
23
|
(!options.bundler && actualBundler === 'webpack')) {
|
|
29
24
|
(0, devkit_1.addDependenciesToPackageJson)(tree, {}, { '@nx/webpack': versions_1.nxVersion });
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { composePlugins, withNx } from '@nx/webpack';
|
|
2
2
|
import { withReact } from '@nx/react';
|
|
3
3
|
import { withModuleFederation } from '@nx/react/module-federation';
|
|
4
|
+
import { ModuleFederationConfig } from '@nx/webpack';
|
|
4
5
|
|
|
5
6
|
import baseConfig from './module-federation.config';
|
|
6
7
|
|
|
7
|
-
const prodConfig = {
|
|
8
|
+
const prodConfig: ModuleFederationConfig = {
|
|
8
9
|
...baseConfig,
|
|
9
10
|
/*
|
|
10
11
|
* Remote overrides for production.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {composePlugins, withNx} from '@nx/webpack';
|
|
1
|
+
import {composePlugins, withNx, ModuleFederationConfig} from '@nx/webpack';
|
|
2
2
|
import {withReact} from '@nx/react';
|
|
3
3
|
import {withModuleFederation} from '@nx/react/module-federation';
|
|
4
4
|
|
|
5
5
|
import baseConfig from './module-federation.config';
|
|
6
6
|
|
|
7
|
-
const config = {
|
|
7
|
+
const config: ModuleFederationConfig = {
|
|
8
8
|
...baseConfig,
|
|
9
9
|
};
|
|
10
10
|
|
|
@@ -25,6 +25,8 @@ async function hostGeneratorInternal(host, schema) {
|
|
|
25
25
|
...(await (0, normalize_options_1.normalizeOptions)(host, schema, '@nx/react:host')),
|
|
26
26
|
typescriptConfiguration: schema.typescriptConfiguration ?? true,
|
|
27
27
|
dynamic: schema.dynamic ?? false,
|
|
28
|
+
// TODO(colum): remove when MF works with Crystal
|
|
29
|
+
addPlugin: false,
|
|
28
30
|
};
|
|
29
31
|
const initTask = await (0, application_1.default)(host, {
|
|
30
32
|
...options,
|
|
@@ -26,10 +26,12 @@ export interface Schema {
|
|
|
26
26
|
minimal?: boolean;
|
|
27
27
|
typescriptConfiguration?: boolean;
|
|
28
28
|
dynamic?: boolean;
|
|
29
|
+
addPlugin?: boolean;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
export interface NormalizedSchema extends Schema {
|
|
32
33
|
appProjectRoot: string;
|
|
33
34
|
e2eProjectName: string;
|
|
34
35
|
projectName: string;
|
|
36
|
+
addPlugin?: boolean;
|
|
35
37
|
}
|
|
@@ -18,6 +18,7 @@ async function addLinting(host, options) {
|
|
|
18
18
|
skipFormat: true,
|
|
19
19
|
skipPackageJson: options.skipPackageJson,
|
|
20
20
|
setParserOptionsProject: options.setParserOptionsProject,
|
|
21
|
+
addPlugin: options.addPlugin,
|
|
21
22
|
});
|
|
22
23
|
if ((0, eslint_file_1.isEslintConfigSupported)(host)) {
|
|
23
24
|
(0, eslint_file_1.addExtendsToLintConfig)(host, options.projectRoot, 'plugin:@nx/react');
|
|
@@ -13,6 +13,7 @@ async function normalizeOptions(host, options) {
|
|
|
13
13
|
projectNameAndRootFormat: options.projectNameAndRootFormat,
|
|
14
14
|
callingGenerator: '@nx/react:library',
|
|
15
15
|
});
|
|
16
|
+
options.addPlugin ??= process.env.NX_ADD_PLUGINS !== 'false';
|
|
16
17
|
const fileName = options.simpleName
|
|
17
18
|
? projectNames.projectSimpleName
|
|
18
19
|
: projectNames.projectFileName;
|
|
@@ -50,7 +51,7 @@ async function normalizeOptions(host, options) {
|
|
|
50
51
|
throw new Error(`appProject expected type of "application" but got "${appProjectConfig.projectType}"`);
|
|
51
52
|
}
|
|
52
53
|
normalized.appMain =
|
|
53
|
-
appProjectConfig.targets.build
|
|
54
|
+
appProjectConfig.targets.build?.options?.main ??
|
|
54
55
|
findMainEntry(host, appProjectConfig.root);
|
|
55
56
|
normalized.appSourceRoot = (0, devkit_1.normalizePath)(appProjectConfig.sourceRoot);
|
|
56
57
|
// TODO(jack): We should use appEntryFile instead of appProject so users can directly set it rather than us inferring it.
|
|
@@ -20,6 +20,7 @@ const path_1 = require("path");
|
|
|
20
20
|
const log_show_project_command_1 = require("@nx/devkit/src/utils/log-show-project-command");
|
|
21
21
|
async function libraryGenerator(host, schema) {
|
|
22
22
|
return await libraryGeneratorInternal(host, {
|
|
23
|
+
addPlugin: false,
|
|
23
24
|
projectNameAndRootFormat: 'derived',
|
|
24
25
|
...schema,
|
|
25
26
|
});
|
|
@@ -67,6 +68,7 @@ async function libraryGeneratorInternal(host, schema) {
|
|
|
67
68
|
compiler: options.compiler,
|
|
68
69
|
skipFormat: true,
|
|
69
70
|
testEnvironment: 'jsdom',
|
|
71
|
+
addPlugin: options.addPlugin,
|
|
70
72
|
});
|
|
71
73
|
tasks.push(viteTask);
|
|
72
74
|
createOrEditViteConfig(host, {
|
|
@@ -121,6 +123,7 @@ async function libraryGeneratorInternal(host, schema) {
|
|
|
121
123
|
inSourceTests: options.inSourceTests,
|
|
122
124
|
skipFormat: true,
|
|
123
125
|
testEnvironment: 'jsdom',
|
|
126
|
+
addPlugin: options.addPlugin,
|
|
124
127
|
});
|
|
125
128
|
tasks.push(vitestTask);
|
|
126
129
|
createOrEditViteConfig(host, {
|
|
@@ -47,6 +47,8 @@ async function remoteGeneratorInternal(host, schema) {
|
|
|
47
47
|
...(await (0, normalize_options_1.normalizeOptions)(host, schema, '@nx/react:remote')),
|
|
48
48
|
typescriptConfiguration: schema.typescriptConfiguration ?? false,
|
|
49
49
|
dynamic: schema.dynamic ?? false,
|
|
50
|
+
// TODO(colum): remove when MF works with Crystal
|
|
51
|
+
addPlugin: false,
|
|
50
52
|
};
|
|
51
53
|
const initAppTask = await (0, application_1.default)(host, {
|
|
52
54
|
...options,
|
|
@@ -18,7 +18,14 @@ function readEntryFile(host, path) {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
async function setupSsrGenerator(tree, options) {
|
|
21
|
-
|
|
21
|
+
let projectGraph;
|
|
22
|
+
try {
|
|
23
|
+
projectGraph = (0, devkit_1.readCachedProjectGraph)();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
projectGraph = await (0, devkit_1.createProjectGraphAsync)();
|
|
27
|
+
}
|
|
28
|
+
const projectConfig = projectGraph.nodes[options.project].data;
|
|
22
29
|
const projectRoot = projectConfig.root;
|
|
23
30
|
const appImportCandidates = [
|
|
24
31
|
options.appComponentImportPath ?? 'app/app',
|
|
@@ -42,11 +49,15 @@ async function setupSsrGenerator(tree, options) {
|
|
|
42
49
|
if (projectConfig.targets.server) {
|
|
43
50
|
throw new Error(`Project ${options.project} already has a server target.`);
|
|
44
51
|
}
|
|
45
|
-
const originalOutputPath = projectConfig.targets.build?.options?.outputPath
|
|
52
|
+
const originalOutputPath = projectConfig.targets.build?.options?.outputPath ??
|
|
53
|
+
projectConfig.targets.build?.outputs[0];
|
|
46
54
|
if (!originalOutputPath) {
|
|
47
55
|
throw new Error(`Project ${options.project} does not contain a outputPath for the build target.`);
|
|
48
56
|
}
|
|
49
|
-
|
|
57
|
+
// TODO(colum): We need to figure out how to handle this for Crystal
|
|
58
|
+
if (projectConfig.targets.build.options?.outputPath) {
|
|
59
|
+
projectConfig.targets.build.options.outputPath = (0, devkit_1.joinPathFragments)(originalOutputPath, 'browser');
|
|
60
|
+
}
|
|
50
61
|
projectConfig.targets = {
|
|
51
62
|
...projectConfig.targets,
|
|
52
63
|
server: {
|
|
@@ -136,7 +147,8 @@ async function setupSsrGenerator(tree, options) {
|
|
|
136
147
|
? `"${options.extraInclude.join('", "')}",`
|
|
137
148
|
: '',
|
|
138
149
|
appComponentImport: appComponentInfo.importPath,
|
|
139
|
-
browserBuildOutputPath: projectConfig.targets.build
|
|
150
|
+
browserBuildOutputPath: projectConfig.targets.build?.options?.outputPath ??
|
|
151
|
+
projectConfig.targets.build?.outputs[0],
|
|
140
152
|
});
|
|
141
153
|
// Add <StaticRouter> to server main if needed.
|
|
142
154
|
// TODO: need to read main.server.tsx not main.tsx.
|
|
@@ -11,11 +11,10 @@ const ensure_typescript_1 = require("@nx/js/src/utils/typescript/ensure-typescri
|
|
|
11
11
|
const versions_1 = require("../../utils/versions");
|
|
12
12
|
let tsModule;
|
|
13
13
|
async function projectRootPath(tree, config) {
|
|
14
|
-
const { findStorybookAndBuildTargetsAndCompiler } = await Promise.resolve().then(() => require('@nx/storybook/src/utils/utilities'));
|
|
15
14
|
let projectDir;
|
|
16
15
|
if (config.projectType === 'application') {
|
|
17
|
-
const
|
|
18
|
-
if (
|
|
16
|
+
const isNextJs = await isNextJsProject(tree, config);
|
|
17
|
+
if (isNextJs) {
|
|
19
18
|
// Next.js apps
|
|
20
19
|
projectDir = 'components';
|
|
21
20
|
}
|
|
@@ -115,4 +114,17 @@ async function storiesGenerator(host, schema) {
|
|
|
115
114
|
return (0, devkit_1.runTasksInSerial)(...tasks);
|
|
116
115
|
}
|
|
117
116
|
exports.storiesGenerator = storiesGenerator;
|
|
117
|
+
async function isNextJsProject(tree, config) {
|
|
118
|
+
const { findStorybookAndBuildTargetsAndCompiler } = await Promise.resolve().then(() => require('@nx/storybook/src/utils/utilities'));
|
|
119
|
+
const { nextBuildTarget } = findStorybookAndBuildTargetsAndCompiler(config.targets);
|
|
120
|
+
if (nextBuildTarget) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
for (const configFile of ['next.config.js', 'next.config.ts']) {
|
|
124
|
+
if (tree.exists((0, path_1.join)(config.root, configFile))) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
118
130
|
exports.default = storiesGenerator;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { StorybookConfigureSchema } from './schema';
|
|
2
2
|
import { Tree } from '@nx/devkit';
|
|
3
3
|
export declare function storybookConfigurationGenerator(host: Tree, schema: StorybookConfigureSchema): Promise<import("@nx/devkit").GeneratorCallback>;
|
|
4
|
+
export declare function storybookConfigurationGeneratorInternal(host: Tree, schema: StorybookConfigureSchema): Promise<import("@nx/devkit").GeneratorCallback>;
|
|
4
5
|
export default storybookConfigurationGenerator;
|
|
5
6
|
export declare function findWebpackConfig(tree: Tree, projectRoot: string): string | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.findWebpackConfig = exports.storybookConfigurationGenerator = void 0;
|
|
3
|
+
exports.findWebpackConfig = exports.storybookConfigurationGeneratorInternal = exports.storybookConfigurationGenerator = void 0;
|
|
4
4
|
const stories_1 = require("../stories/stories");
|
|
5
5
|
const devkit_1 = require("@nx/devkit");
|
|
6
6
|
const versions_1 = require("../../utils/versions");
|
|
@@ -20,13 +20,22 @@ async function generateStories(host, schema) {
|
|
|
20
20
|
interactionTests: schema.interactionTests ?? true,
|
|
21
21
|
});
|
|
22
22
|
}
|
|
23
|
-
|
|
23
|
+
function storybookConfigurationGenerator(host, schema) {
|
|
24
|
+
return storybookConfigurationGeneratorInternal(host, {
|
|
25
|
+
addPlugin: false,
|
|
26
|
+
...schema,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
exports.storybookConfigurationGenerator = storybookConfigurationGenerator;
|
|
30
|
+
async function storybookConfigurationGeneratorInternal(host, schema) {
|
|
31
|
+
schema.addPlugin ??= process.env.NX_ADD_PLUGINS !== 'false';
|
|
24
32
|
const { configurationGenerator } = (0, devkit_1.ensurePackage)('@nx/storybook', versions_1.nxVersion);
|
|
25
33
|
let uiFramework = '@storybook/react-vite';
|
|
26
34
|
const projectConfig = (0, devkit_1.readProjectConfiguration)(host, schema.project);
|
|
27
35
|
if (findWebpackConfig(host, projectConfig.root) ||
|
|
28
36
|
projectConfig.targets['build']?.executor === '@nx/rollup:rollup' ||
|
|
29
|
-
projectConfig.targets['build']?.executor === '@nrwl/rollup:rollup'
|
|
37
|
+
projectConfig.targets['build']?.executor === '@nrwl/rollup:rollup' ||
|
|
38
|
+
projectConfig.targets['build']?.executor === '@nx/expo:build') {
|
|
30
39
|
uiFramework = '@storybook/react-webpack5';
|
|
31
40
|
}
|
|
32
41
|
const installTask = await configurationGenerator(host, {
|
|
@@ -40,6 +49,7 @@ async function storybookConfigurationGenerator(host, schema) {
|
|
|
40
49
|
configureStaticServe: schema.configureStaticServe,
|
|
41
50
|
uiFramework: uiFramework, // cannot import UiFramework type dynamically
|
|
42
51
|
skipFormat: true,
|
|
52
|
+
addPlugin: schema.addPlugin,
|
|
43
53
|
});
|
|
44
54
|
if (schema.generateStories) {
|
|
45
55
|
await generateStories(host, schema);
|
|
@@ -47,7 +57,7 @@ async function storybookConfigurationGenerator(host, schema) {
|
|
|
47
57
|
await (0, devkit_1.formatFiles)(host);
|
|
48
58
|
return installTask;
|
|
49
59
|
}
|
|
50
|
-
exports.
|
|
60
|
+
exports.storybookConfigurationGeneratorInternal = storybookConfigurationGeneratorInternal;
|
|
51
61
|
exports.default = storybookConfigurationGenerator;
|
|
52
62
|
function findWebpackConfig(tree, projectRoot) {
|
|
53
63
|
const allowsExt = ['js', 'mjs', 'ts', 'cjs', 'mts', 'cts'];
|
|
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.withModuleFederationForSSR = void 0;
|
|
4
4
|
const utils_1 = require("./utils");
|
|
5
5
|
async function withModuleFederationForSSR(options) {
|
|
6
|
+
if (global.NX_GRAPH_CREATION) {
|
|
7
|
+
return (config) => config;
|
|
8
|
+
}
|
|
6
9
|
const { sharedLibraries, sharedDependencies, mappedRemotes } = await (0, utils_1.getModuleFederationConfig)(options, {
|
|
7
10
|
isServer: true,
|
|
8
11
|
});
|
|
@@ -9,6 +9,9 @@ const isVarOrWindow = (libType) => libType === 'var' || libType === 'window';
|
|
|
9
9
|
* @return {Promise<AsyncNxComposableWebpackPlugin>}
|
|
10
10
|
*/
|
|
11
11
|
async function withModuleFederation(options) {
|
|
12
|
+
if (global.NX_GRAPH_CREATION) {
|
|
13
|
+
return (config) => config;
|
|
14
|
+
}
|
|
12
15
|
const { sharedDependencies, sharedLibraries, mappedRemotes } = await (0, utils_1.getModuleFederationConfig)(options);
|
|
13
16
|
const isGlobal = isVarOrWindow(options.library?.type);
|
|
14
17
|
return (config, ctx) => {
|
package/src/utils/ct-utils.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import { Tree } from '@nx/devkit';
|
|
2
2
|
import { type FoundTarget } from '@nx/cypress/src/utils/find-target-options';
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function configureCypressCT(tree: Tree, options: {
|
|
4
4
|
project: string;
|
|
5
5
|
buildTarget: string;
|
|
6
|
+
bundler: 'vite' | 'webpack';
|
|
6
7
|
validExecutorNames: Set<string>;
|
|
7
8
|
}): Promise<FoundTarget>;
|
|
8
9
|
export declare function getBundlerFromTarget(found: FoundTarget, tree: Tree): Promise<'vite' | 'webpack'>;
|
|
10
|
+
export declare function getActualBundler(tree: Tree, options: {
|
|
11
|
+
buildTarget?: string;
|
|
12
|
+
bundler?: 'vite' | 'webpack';
|
|
13
|
+
}, found: FoundTarget): Promise<"vite" | "webpack">;
|
|
9
14
|
export declare function isComponent(tree: Tree, filePath: string): boolean;
|
package/src/utils/ct-utils.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isComponent = exports.getBundlerFromTarget = exports.
|
|
3
|
+
exports.isComponent = exports.getActualBundler = exports.getBundlerFromTarget = exports.configureCypressCT = void 0;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
5
|
const ensure_typescript_1 = require("@nx/js/src/utils/typescript/ensure-typescript");
|
|
6
6
|
const ast_utils_1 = require("./ast-utils");
|
|
7
7
|
let tsModule;
|
|
8
8
|
const allowedFileExt = new RegExp(/\.[jt]sx?/);
|
|
9
9
|
const isSpecFile = new RegExp(/(spec|test)\./);
|
|
10
|
-
async function
|
|
10
|
+
async function configureCypressCT(tree, options) {
|
|
11
11
|
let found = { target: options.buildTarget, config: undefined };
|
|
12
12
|
// Specifically undefined as a workaround for Remix to pass an empty string as the buildTarget
|
|
13
13
|
if (options.buildTarget === undefined) {
|
|
@@ -19,16 +19,29 @@ async function addCTTargetWithBuildTarget(tree, options) {
|
|
|
19
19
|
});
|
|
20
20
|
assertValidConfig(found?.config);
|
|
21
21
|
}
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
devServerTarget: found.target,
|
|
26
|
-
skipServe: true,
|
|
22
|
+
const { addDefaultCTConfig, getProjectCypressConfigPath } = await Promise.resolve().then(() => require('@nx/cypress/src/utils/config'));
|
|
23
|
+
const ctConfigOptions = {
|
|
24
|
+
bundler: options.bundler ?? (await getActualBundler(tree, options, found)),
|
|
27
25
|
};
|
|
28
|
-
(0, devkit_1.
|
|
26
|
+
const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
|
|
27
|
+
if (projectConfig.targets?.['component-test']?.executor ===
|
|
28
|
+
'@nx/cypress:cypress') {
|
|
29
|
+
projectConfig.targets['component-test'].options = {
|
|
30
|
+
...projectConfig.targets['component-test'].options,
|
|
31
|
+
devServerTarget: found.target,
|
|
32
|
+
skipServe: true,
|
|
33
|
+
};
|
|
34
|
+
(0, devkit_1.updateProjectConfiguration)(tree, options.project, projectConfig);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
ctConfigOptions.buildTarget = found.target;
|
|
38
|
+
}
|
|
39
|
+
const cypressConfigFilePath = getProjectCypressConfigPath(tree, projectConfig.root);
|
|
40
|
+
const updatedCyConfig = await addDefaultCTConfig(tree.read(cypressConfigFilePath, 'utf-8'), ctConfigOptions);
|
|
41
|
+
tree.write(cypressConfigFilePath, `import { nxComponentTestingPreset } from '@nx/react/plugins/component-testing';\n${updatedCyConfig}`);
|
|
29
42
|
return found;
|
|
30
43
|
}
|
|
31
|
-
exports.
|
|
44
|
+
exports.configureCypressCT = configureCypressCT;
|
|
32
45
|
function assertValidConfig(config) {
|
|
33
46
|
if (!config) {
|
|
34
47
|
throw new Error('Unable to find a valid build configuration. Try passing in a target for an app. --build-target=<project>:<target>[:<configuration>]');
|
|
@@ -49,6 +62,14 @@ async function getBundlerFromTarget(found, tree) {
|
|
|
49
62
|
: 'webpack';
|
|
50
63
|
}
|
|
51
64
|
exports.getBundlerFromTarget = getBundlerFromTarget;
|
|
65
|
+
async function getActualBundler(tree, options, found) {
|
|
66
|
+
// Specifically undefined to allow Remix workaround of passing an empty string
|
|
67
|
+
const actualBundler = options.buildTarget !== undefined && options.bundler
|
|
68
|
+
? options.bundler
|
|
69
|
+
: await getBundlerFromTarget(found, tree);
|
|
70
|
+
return actualBundler;
|
|
71
|
+
}
|
|
72
|
+
exports.getActualBundler = getActualBundler;
|
|
52
73
|
function isComponent(tree, filePath) {
|
|
53
74
|
if (!tsModule) {
|
|
54
75
|
tsModule = (0, ensure_typescript_1.ensureTypescript)();
|