@nx/react 20.6.0-beta.0 → 20.6.0-beta.1
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 +6 -6
- package/router-plugin.d.ts +1 -0
- package/router-plugin.js +5 -0
- package/src/generators/application/application.js +42 -4
- package/src/generators/application/files/react-router-ssr/common/app/app-nav.tsx__tmpl__ +15 -0
- package/src/generators/application/files/react-router-ssr/common/app/entry.client.tsx__tmpl__ +18 -0
- package/src/generators/application/files/react-router-ssr/common/app/entry.server.tsx__tmpl__ +74 -0
- package/src/generators/application/files/react-router-ssr/common/app/root.tsx__tmpl__ +51 -0
- package/src/generators/application/files/react-router-ssr/common/app/routes/about.tsx__tmpl__ +7 -0
- package/src/generators/application/files/react-router-ssr/common/app/routes.tsx__tmpl__ +6 -0
- package/src/generators/application/files/react-router-ssr/common/public/favicon.ico +0 -0
- package/src/generators/application/files/react-router-ssr/common/react-router.config.ts__tmpl__ +5 -0
- package/src/generators/application/files/react-router-ssr/common/tests/routes/_index.spec.tsx__tmpl__ +16 -0
- package/src/generators/application/files/react-router-ssr/common/tsconfig.app.json__tmpl__ +23 -0
- package/src/generators/application/files/react-router-ssr/common/tsconfig.json__tmpl__ +27 -0
- package/src/generators/application/files/react-router-ssr/non-root/.gitignore__tmpl__ +5 -0
- package/src/generators/application/files/react-router-ssr/non-root/package.json__tmpl__ +24 -0
- package/src/generators/application/files/react-router-ssr/nx-welcome/claimed/app/nx-welcome.tsx__tmpl__ +866 -0
- package/src/generators/application/files/react-router-ssr/nx-welcome/not-configured/app/nx-welcome.tsx__tmpl__ +866 -0
- package/src/generators/application/files/react-router-ssr/nx-welcome/unclaimed/app/nx-welcome.tsx__tmpl__ +864 -0
- package/src/generators/application/files/react-router-ssr/ts-solution/package.json__tmpl__ +24 -0
- package/src/generators/application/files/react-router-ssr/ts-solution/tsconfig.app.json__tmpl__ +39 -0
- package/src/generators/application/lib/add-e2e.js +4 -2
- package/src/generators/application/lib/add-linting.d.ts +1 -0
- package/src/generators/application/lib/add-linting.js +38 -0
- package/src/generators/application/lib/add-project.js +12 -1
- package/src/generators/application/lib/add-routing.js +1 -1
- package/src/generators/application/lib/bundlers/add-vite.js +15 -6
- package/src/generators/application/lib/create-application-files.js +40 -3
- package/src/generators/application/lib/install-common-dependencies.js +13 -2
- package/src/generators/application/lib/normalize-options.js +3 -0
- package/src/generators/application/schema.d.ts +1 -0
- package/src/generators/application/schema.json +6 -1
- package/src/generators/init/init.js +23 -0
- package/src/generators/init/schema.d.ts +2 -0
- package/src/generators/library/library.js +3 -3
- package/src/plugins/router-plugin.d.ts +10 -0
- package/src/plugins/router-plugin.js +219 -0
- package/src/utils/ast-utils.d.ts +1 -1
- package/src/utils/ast-utils.js +2 -2
- package/src/utils/versions.d.ts +3 -1
- package/src/utils/versions.js +6 -3
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@nx/react",
|
3
|
-
"version": "20.6.0-beta.
|
3
|
+
"version": "20.6.0-beta.1",
|
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, Vitest, Playwright, 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": {
|
@@ -38,11 +38,11 @@
|
|
38
38
|
"minimatch": "9.0.3",
|
39
39
|
"picocolors": "^1.1.0",
|
40
40
|
"tslib": "^2.3.0",
|
41
|
-
"@nx/devkit": "20.6.0-beta.
|
42
|
-
"@nx/js": "20.6.0-beta.
|
43
|
-
"@nx/eslint": "20.6.0-beta.
|
44
|
-
"@nx/web": "20.6.0-beta.
|
45
|
-
"@nx/module-federation": "20.6.0-beta.
|
41
|
+
"@nx/devkit": "20.6.0-beta.1",
|
42
|
+
"@nx/js": "20.6.0-beta.1",
|
43
|
+
"@nx/eslint": "20.6.0-beta.1",
|
44
|
+
"@nx/web": "20.6.0-beta.1",
|
45
|
+
"@nx/module-federation": "20.6.0-beta.1",
|
46
46
|
"express": "^4.21.2",
|
47
47
|
"http-proxy-middleware": "^3.0.3",
|
48
48
|
"semver": "^7.6.3"
|
@@ -0,0 +1 @@
|
|
1
|
+
export { createNodesV2, ReactRouterPluginOptions, } from './src/plugins/router-plugin';
|
package/router-plugin.js
ADDED
@@ -0,0 +1,5 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.createNodesV2 = void 0;
|
4
|
+
var router_plugin_1 = require("./src/plugins/router-plugin");
|
5
|
+
Object.defineProperty(exports, "createNodesV2", { enumerable: true, get: function () { return router_plugin_1.createNodesV2; } });
|
@@ -26,6 +26,7 @@ const add_rspack_1 = require("./lib/bundlers/add-rspack");
|
|
26
26
|
const add_rsbuild_1 = require("./lib/bundlers/add-rsbuild");
|
27
27
|
const add_vite_1 = require("./lib/bundlers/add-vite");
|
28
28
|
const sort_fields_1 = require("@nx/js/src/utils/package-json/sort-fields");
|
29
|
+
const prompt_1 = require("@nx/devkit/src/generators/prompt");
|
29
30
|
async function applicationGenerator(tree, schema) {
|
30
31
|
return await applicationGeneratorInternal(tree, {
|
31
32
|
addPlugin: false,
|
@@ -45,6 +46,25 @@ async function applicationGeneratorInternal(tree, schema) {
|
|
45
46
|
});
|
46
47
|
tasks.push(jsInitTask);
|
47
48
|
const options = await (0, normalize_options_1.normalizeOptions)(tree, schema);
|
49
|
+
options.useReactRouter = options.routing
|
50
|
+
? options.useReactRouter ??
|
51
|
+
(await (0, prompt_1.promptWhenInteractive)({
|
52
|
+
name: 'response',
|
53
|
+
message: 'Would you like to use react-router for server-side rendering?',
|
54
|
+
type: 'autocomplete',
|
55
|
+
choices: [
|
56
|
+
{
|
57
|
+
name: 'Yes',
|
58
|
+
message: 'I want to use react-router [ https://reactrouter.com/start/framework/routing ]',
|
59
|
+
},
|
60
|
+
{
|
61
|
+
name: 'No',
|
62
|
+
message: 'I do not want to use react-router for server-side rendering',
|
63
|
+
},
|
64
|
+
],
|
65
|
+
initial: 0,
|
66
|
+
}, { response: 'No' }).then((r) => r.response === 'Yes'))
|
67
|
+
: false;
|
48
68
|
(0, show_possible_warnings_1.showPossibleWarnings)(tree, options);
|
49
69
|
const initTask = await (0, init_1.default)(tree, {
|
50
70
|
...options,
|
@@ -113,16 +133,34 @@ async function applicationGeneratorInternal(tree, schema) {
|
|
113
133
|
}
|
114
134
|
// Handle tsconfig.spec.json for jest or vitest
|
115
135
|
(0, update_jest_config_1.updateSpecConfig)(tree, options);
|
116
|
-
const
|
117
|
-
tasks.push(
|
136
|
+
const commonDependencyTask = await (0, install_common_dependencies_1.installCommonDependencies)(tree, options);
|
137
|
+
tasks.push(commonDependencyTask);
|
118
138
|
const styledTask = (0, add_styled_dependencies_1.addStyledModuleDependencies)(tree, options);
|
119
139
|
tasks.push(styledTask);
|
120
|
-
|
121
|
-
|
140
|
+
if (!options.useReactRouter) {
|
141
|
+
const routingTask = (0, add_routing_1.addRouting)(tree, options);
|
142
|
+
tasks.push(routingTask);
|
143
|
+
}
|
122
144
|
(0, set_defaults_1.setDefaults)(tree, options);
|
123
145
|
if (options.bundler === 'rspack' && options.style === 'styled-jsx') {
|
124
146
|
(0, add_rspack_1.handleStyledJsxForRspack)(tasks, tree, options);
|
125
147
|
}
|
148
|
+
if (options.useReactRouter) {
|
149
|
+
(0, devkit_1.updateJson)(tree, (0, devkit_1.joinPathFragments)(options.appProjectRoot, 'tsconfig.json'), (json) => {
|
150
|
+
const types = new Set(json.compilerOptions?.types || []);
|
151
|
+
types.add('@react-router/node');
|
152
|
+
return {
|
153
|
+
...json,
|
154
|
+
compilerOptions: {
|
155
|
+
...json.compilerOptions,
|
156
|
+
jsx: 'react-jsx',
|
157
|
+
moduleResolution: 'bundler',
|
158
|
+
types: Array.from(types),
|
159
|
+
},
|
160
|
+
};
|
161
|
+
});
|
162
|
+
}
|
163
|
+
// Only for the new TS solution
|
126
164
|
(0, ts_solution_setup_1.updateTsconfigFiles)(tree, options.appProjectRoot, 'tsconfig.app.json', {
|
127
165
|
jsx: 'react-jsx',
|
128
166
|
module: 'esnext',
|
@@ -0,0 +1,18 @@
|
|
1
|
+
/**
|
2
|
+
* By default, React Router will handle hydrating your app on the client for you.
|
3
|
+
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx react-router reveal` ✨
|
4
|
+
* For more information, see https://reactrouter.com/explanation/special-files#entryclienttsx
|
5
|
+
*/
|
6
|
+
|
7
|
+
import { HydratedRouter } from 'react-router/dom';
|
8
|
+
import { startTransition, StrictMode } from "react";
|
9
|
+
import { hydrateRoot } from "react-dom/client";
|
10
|
+
|
11
|
+
startTransition(() => {
|
12
|
+
hydrateRoot(
|
13
|
+
document,
|
14
|
+
<StrictMode>
|
15
|
+
<HydratedRouter />
|
16
|
+
</StrictMode>
|
17
|
+
);
|
18
|
+
});
|
@@ -0,0 +1,74 @@
|
|
1
|
+
/**
|
2
|
+
* By default, React Router will handle generating the HTTP Response for you.
|
3
|
+
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
|
4
|
+
* For more information, see https://reactrouter.com/explanation/special-files#entryservertsx
|
5
|
+
*/
|
6
|
+
|
7
|
+
import { PassThrough } from "node:stream";
|
8
|
+
|
9
|
+
import type { AppLoadContext, EntryContext } from "react-router";
|
10
|
+
import { createReadableStreamFromReadable } from "@react-router/node";
|
11
|
+
import { ServerRouter } from "react-router";
|
12
|
+
import { isbot } from "isbot";
|
13
|
+
import type { RenderToPipeableStreamOptions } from "react-dom/server";
|
14
|
+
import { renderToPipeableStream } from "react-dom/server";
|
15
|
+
|
16
|
+
export const streamTimeout = 5_000;
|
17
|
+
|
18
|
+
export default function handleRequest(
|
19
|
+
request: Request,
|
20
|
+
responseStatusCode: number,
|
21
|
+
responseHeaders: Headers,
|
22
|
+
routerContext: EntryContext,
|
23
|
+
loadContext: AppLoadContext
|
24
|
+
) {
|
25
|
+
return new Promise((resolve, reject) => {
|
26
|
+
let shellRendered = false;
|
27
|
+
const userAgent = request.headers.get("user-agent");
|
28
|
+
|
29
|
+
// Ensure requests from bots and SPA Mode renders wait for all content to load before responding
|
30
|
+
// https://react.dev/reference/react-dom/server/renderToPipeableStream#waiting-for-all-content-to-load-for-crawlers-and-static-generation
|
31
|
+
const readyOption: keyof RenderToPipeableStreamOptions =
|
32
|
+
(userAgent && isbot(userAgent)) || routerContext.isSpaMode
|
33
|
+
? "onAllReady"
|
34
|
+
: "onShellReady";
|
35
|
+
|
36
|
+
const { pipe, abort } = renderToPipeableStream(
|
37
|
+
<ServerRouter context={routerContext} url={request.url} />,
|
38
|
+
{
|
39
|
+
[readyOption]() {
|
40
|
+
shellRendered = true;
|
41
|
+
const body = new PassThrough();
|
42
|
+
const stream = createReadableStreamFromReadable(body);
|
43
|
+
|
44
|
+
responseHeaders.set("Content-Type", "text/html");
|
45
|
+
|
46
|
+
resolve(
|
47
|
+
new Response(stream, {
|
48
|
+
headers: responseHeaders,
|
49
|
+
status: responseStatusCode,
|
50
|
+
})
|
51
|
+
);
|
52
|
+
|
53
|
+
pipe(body);
|
54
|
+
},
|
55
|
+
onShellError(error: unknown) {
|
56
|
+
reject(error);
|
57
|
+
},
|
58
|
+
onError(error: unknown) {
|
59
|
+
responseStatusCode = 500;
|
60
|
+
// Log streaming rendering errors from inside the shell. Don't log
|
61
|
+
// errors encountered during initial shell rendering since they'll
|
62
|
+
// reject and get logged in handleDocumentRequest.
|
63
|
+
if (shellRendered) {
|
64
|
+
console.error(error);
|
65
|
+
}
|
66
|
+
},
|
67
|
+
}
|
68
|
+
);
|
69
|
+
|
70
|
+
// Abort the rendering stream after the `streamTimeout` so it has time to
|
71
|
+
// flush down the rejected boundaries
|
72
|
+
setTimeout(abort, streamTimeout + 1000);
|
73
|
+
});
|
74
|
+
}
|
@@ -0,0 +1,51 @@
|
|
1
|
+
import {
|
2
|
+
Links,
|
3
|
+
Meta,
|
4
|
+
Outlet,
|
5
|
+
Scripts,
|
6
|
+
ScrollRestoration,
|
7
|
+
type MetaFunction,
|
8
|
+
type LinksFunction
|
9
|
+
} from "react-router";
|
10
|
+
|
11
|
+
import { AppNav } from './app-nav'
|
12
|
+
|
13
|
+
export const meta: MetaFunction = () => ([{
|
14
|
+
title: "New Nx React Router App",
|
15
|
+
}]);
|
16
|
+
|
17
|
+
export const links: LinksFunction = () => [
|
18
|
+
{ rel: "preconnect", href: "https://fonts.googleapis.com" },
|
19
|
+
{
|
20
|
+
rel: "preconnect",
|
21
|
+
href: "https://fonts.gstatic.com",
|
22
|
+
crossOrigin: "anonymous",
|
23
|
+
},
|
24
|
+
{
|
25
|
+
rel: "stylesheet",
|
26
|
+
href: "https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap",
|
27
|
+
},
|
28
|
+
];
|
29
|
+
|
30
|
+
export function Layout({ children }: { children: React.ReactNode }) {
|
31
|
+
return (
|
32
|
+
<html lang="en">
|
33
|
+
<head>
|
34
|
+
<meta charSet="utf-8" />
|
35
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
36
|
+
<Meta />
|
37
|
+
<Links />
|
38
|
+
</head>
|
39
|
+
<body>
|
40
|
+
<AppNav />
|
41
|
+
{children}
|
42
|
+
<ScrollRestoration />
|
43
|
+
<Scripts />
|
44
|
+
</body>
|
45
|
+
</html>
|
46
|
+
);
|
47
|
+
}
|
48
|
+
|
49
|
+
export default function App() {
|
50
|
+
return <Outlet />;
|
51
|
+
}
|
Binary file
|
@@ -0,0 +1,16 @@
|
|
1
|
+
import { createRoutesStub } from 'react-router';
|
2
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
3
|
+
import App from '../../app/app';
|
4
|
+
|
5
|
+
test('renders loader data', async () => {
|
6
|
+
const ReactRouterStub = createRoutesStub([
|
7
|
+
{
|
8
|
+
path: '/',
|
9
|
+
Component: App,
|
10
|
+
},
|
11
|
+
]);
|
12
|
+
|
13
|
+
render(<ReactRouterStub />);
|
14
|
+
|
15
|
+
await waitFor(() => screen.findByText('Hello there,'));
|
16
|
+
});
|
@@ -0,0 +1,23 @@
|
|
1
|
+
{
|
2
|
+
"extends": "./tsconfig.json",
|
3
|
+
"include": [
|
4
|
+
"app/**/*.ts",
|
5
|
+
"app/**/*.tsx",
|
6
|
+
"app/**/*.js",
|
7
|
+
"app/**/*.jsx",
|
8
|
+
"**/.server/**/*.ts",
|
9
|
+
"**/.server/**/*.tsx",
|
10
|
+
"**/.client/**/*.ts",
|
11
|
+
"**/.client/**/*.tsx"
|
12
|
+
],
|
13
|
+
"exclude": [
|
14
|
+
"tests/**/*.spec.ts",
|
15
|
+
"tests/**/*.test.ts",
|
16
|
+
"tests/**/*.spec.tsx",
|
17
|
+
"tests/**/*.test.tsx",
|
18
|
+
"tests/**/*.spec.js",
|
19
|
+
"tests/**/*.test.js",
|
20
|
+
"tests/**/*.spec.jsx",
|
21
|
+
"tests/**/*.test.jsx"
|
22
|
+
]
|
23
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
{
|
2
|
+
"extends": "<%= offsetFromRoot %>tsconfig.base.json",
|
3
|
+
"compilerOptions": {
|
4
|
+
"lib": ["DOM", "DOM.Iterable", "ES2019"],
|
5
|
+
"types": ["@react-router/node", "vite/client"],
|
6
|
+
"isolatedModules": true,
|
7
|
+
"esModuleInterop": true,
|
8
|
+
"jsx": "react-jsx",
|
9
|
+
"module": "ESNext",
|
10
|
+
"moduleResolution": "Bundler",
|
11
|
+
"resolveJsonModule": true,
|
12
|
+
"target": "ES2022",
|
13
|
+
"strict": true,
|
14
|
+
"allowJs": true,
|
15
|
+
"skipLibCheck": true,
|
16
|
+
"forceConsistentCasingInFileNames": true,
|
17
|
+
// Vite takes care of building everything.
|
18
|
+
"noEmit": true
|
19
|
+
},
|
20
|
+
"include": [],
|
21
|
+
"files": [],
|
22
|
+
"references": [
|
23
|
+
{
|
24
|
+
"path": "./tsconfig.app.json"
|
25
|
+
}
|
26
|
+
]
|
27
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
{
|
2
|
+
"name": "<%= projectName %>",
|
3
|
+
"private": true,
|
4
|
+
"type": "module",
|
5
|
+
"scripts": {},
|
6
|
+
"dependencies": {
|
7
|
+
"@react-router/node": "<%= reactRouterVersion %>",
|
8
|
+
"@react-router/serve": "<%= reactRouterVersion %>",
|
9
|
+
"isbot": "<%= reactRouterIsBotVersion %>",
|
10
|
+
"react": "<%= reactVersion %>",
|
11
|
+
"react-dom": "<%= reactVersion %>",
|
12
|
+
"react-router": "<%= reactRouterVersion %>"
|
13
|
+
},
|
14
|
+
"devDependencies": {
|
15
|
+
"@react-router/dev": "<%= reactRouterVersion %>",
|
16
|
+
"@types/node": "<%= typesNodeVersion %>",
|
17
|
+
"@types/react": "<%= reactVersion %>",
|
18
|
+
"@types/react-dom": "<%= reactVersion %>"
|
19
|
+
},
|
20
|
+
"engines": {
|
21
|
+
"node": ">=20"
|
22
|
+
},
|
23
|
+
"sideEffects": false
|
24
|
+
}
|