@nx/react 21.0.0-canary.20250206-8bd0bcd → 21.0.0-canary.20250418-8619c1d

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.
Files changed (100) hide show
  1. package/package.json +6 -6
  2. package/plugins/nx-react-webpack-plugin/lib/apply-react-config.js +3 -1
  3. package/router-plugin.d.ts +1 -0
  4. package/router-plugin.js +5 -0
  5. package/src/generators/application/application.js +52 -15
  6. package/src/generators/application/files/react-router-ssr/common/app/app-nav.tsx__tmpl__ +14 -0
  7. package/src/generators/application/files/react-router-ssr/common/app/entry.client.tsx__tmpl__ +18 -0
  8. package/src/generators/application/files/react-router-ssr/common/app/entry.server.tsx__tmpl__ +74 -0
  9. package/src/generators/application/files/react-router-ssr/common/app/root.tsx__tmpl__ +51 -0
  10. package/src/generators/application/files/react-router-ssr/common/app/routes/about.tsx__tmpl__ +7 -0
  11. package/src/generators/application/files/react-router-ssr/common/app/routes.tsx__tmpl__ +6 -0
  12. package/src/generators/application/files/react-router-ssr/common/public/favicon.ico +0 -0
  13. package/src/generators/application/files/react-router-ssr/common/react-router.config.ts__tmpl__ +5 -0
  14. package/src/generators/application/files/react-router-ssr/common/tests/routes/_index.spec.tsx__tmpl__ +16 -0
  15. package/src/generators/application/files/react-router-ssr/common/tsconfig.app.json__tmpl__ +23 -0
  16. package/src/generators/application/files/react-router-ssr/common/tsconfig.json__tmpl__ +27 -0
  17. package/src/generators/application/files/react-router-ssr/non-root/.gitignore__tmpl__ +5 -0
  18. package/src/generators/application/files/react-router-ssr/non-root/package.json__tmpl__ +24 -0
  19. package/src/generators/application/files/react-router-ssr/nx-welcome/claimed/app/nx-welcome.tsx__tmpl__ +866 -0
  20. package/src/generators/application/files/react-router-ssr/nx-welcome/not-configured/app/nx-welcome.tsx__tmpl__ +866 -0
  21. package/src/generators/application/files/react-router-ssr/nx-welcome/unclaimed/app/nx-welcome.tsx__tmpl__ +864 -0
  22. package/src/generators/application/files/react-router-ssr/ts-solution/package.json__tmpl__ +24 -0
  23. package/src/generators/application/files/react-router-ssr/ts-solution/tsconfig.app.json__tmpl__ +39 -0
  24. package/src/generators/application/lib/add-e2e.js +38 -71
  25. package/src/generators/application/lib/add-jest.js +26 -2
  26. package/src/generators/application/lib/add-linting.d.ts +1 -0
  27. package/src/generators/application/lib/add-linting.js +38 -0
  28. package/src/generators/application/lib/add-project.js +31 -15
  29. package/src/generators/application/lib/add-routing.js +1 -1
  30. package/src/generators/application/lib/bundlers/add-rspack.d.ts +0 -1
  31. package/src/generators/application/lib/bundlers/add-rspack.js +0 -18
  32. package/src/generators/application/lib/bundlers/add-vite.js +15 -6
  33. package/src/generators/application/lib/create-application-files.d.ts +61 -0
  34. package/src/generators/application/lib/create-application-files.js +81 -39
  35. package/src/generators/application/lib/get-app-tests.js +3 -3
  36. package/src/generators/application/lib/install-common-dependencies.js +13 -2
  37. package/src/generators/application/lib/normalize-options.d.ts +0 -2
  38. package/src/generators/application/lib/normalize-options.js +14 -20
  39. package/src/generators/application/schema.d.ts +5 -1
  40. package/src/generators/application/schema.json +10 -1
  41. package/src/generators/component-test/component-test.js +1 -1
  42. package/src/generators/cypress-component-configuration/lib/add-files.d.ts +1 -1
  43. package/src/generators/cypress-component-configuration/lib/add-files.js +7 -4
  44. package/src/generators/host/files/rspack-module-federation/rspack.config.js__tmpl__ +37 -13
  45. package/src/generators/host/files/rspack-module-federation/rspack.config.prod.js__tmpl__ +60 -32
  46. package/src/generators/host/files/rspack-module-federation-ssr/module-federation.server.config.js__tmpl__ +6 -0
  47. package/src/generators/host/files/rspack-module-federation-ssr/rspack.config.js__tmpl__ +66 -0
  48. package/src/generators/host/files/rspack-module-federation-ssr/server.ts__tmpl__ +1 -1
  49. package/src/generators/host/files/rspack-module-federation-ssr/src/main.server.tsx__tmpl__ +49 -0
  50. package/src/generators/host/files/rspack-module-federation-ssr-ts/module-federation.server.config.ts__tmpl__ +6 -0
  51. package/src/generators/host/files/rspack-module-federation-ssr-ts/rspack.config.ts__tmpl__ +66 -0
  52. package/src/generators/host/files/rspack-module-federation-ssr-ts/server.ts__tmpl__ +1 -1
  53. package/src/generators/host/files/rspack-module-federation-ssr-ts/src/main.server.tsx__tmpl__ +49 -0
  54. package/src/generators/host/files/rspack-module-federation-ts/rspack.config.prod.ts__tmpl__ +37 -9
  55. package/src/generators/host/files/rspack-module-federation-ts/rspack.config.ts__tmpl__ +37 -14
  56. package/src/generators/host/host.js +21 -18
  57. package/src/generators/host/lib/add-module-federation-files.js +28 -12
  58. package/src/generators/host/lib/normalize-host-name.d.ts +2 -0
  59. package/src/generators/host/lib/normalize-host-name.js +12 -0
  60. package/src/generators/host/lib/setup-ssr-for-host.d.ts +3 -3
  61. package/src/generators/host/lib/setup-ssr-for-host.js +46 -22
  62. package/src/generators/init/init.js +23 -0
  63. package/src/generators/init/schema.d.ts +2 -0
  64. package/src/generators/library/lib/add-rollup-build-target.d.ts +3 -1
  65. package/src/generators/library/lib/add-rollup-build-target.js +6 -7
  66. package/src/generators/library/lib/create-files.js +2 -1
  67. package/src/generators/library/lib/normalize-options.js +8 -5
  68. package/src/generators/library/library.js +44 -30
  69. package/src/generators/library/schema.d.ts +2 -0
  70. package/src/generators/library/schema.json +8 -4
  71. package/src/generators/remote/files/rspack-module-federation/rspack.config.js__tmpl__ +40 -13
  72. package/src/generators/remote/files/rspack-module-federation-ssr/module-federation.server.config.js__tmpl__ +6 -0
  73. package/src/generators/remote/files/rspack-module-federation-ssr/rspack.config.js__tmpl__ +69 -0
  74. package/src/generators/remote/files/rspack-module-federation-ssr/server.ts__tmpl__ +2 -2
  75. package/src/generators/remote/files/rspack-module-federation-ssr/src/main.server.tsx__tmpl__ +45 -0
  76. package/src/generators/remote/files/rspack-module-federation-ssr-ts/module-federation.server.config.ts__tmpl__ +6 -0
  77. package/src/generators/remote/files/rspack-module-federation-ssr-ts/rspack.config.ts__tmpl__ +69 -0
  78. package/src/generators/remote/files/rspack-module-federation-ssr-ts/server.ts__tmpl__ +2 -2
  79. package/src/generators/remote/files/rspack-module-federation-ssr-ts/src/main.server.tsx__tmpl__ +45 -0
  80. package/src/generators/remote/files/rspack-module-federation-ts/rspack.config.ts__tmpl__ +40 -13
  81. package/src/generators/remote/lib/setup-ssr-for-remote.d.ts +1 -1
  82. package/src/generators/remote/lib/setup-ssr-for-remote.js +37 -15
  83. package/src/generators/remote/remote.js +46 -30
  84. package/src/plugins/router-plugin.d.ts +10 -0
  85. package/src/plugins/router-plugin.js +221 -0
  86. package/src/rules/update-module-federation-project.d.ts +2 -1
  87. package/src/rules/update-module-federation-project.js +28 -47
  88. package/src/utils/assertion.d.ts +2 -0
  89. package/src/utils/assertion.js +6 -0
  90. package/src/utils/ast-utils.d.ts +1 -1
  91. package/src/utils/ast-utils.js +2 -2
  92. package/src/utils/ct-utils.d.ts +1 -1
  93. package/src/utils/versions.d.ts +6 -4
  94. package/src/utils/versions.js +9 -6
  95. package/src/generators/host/files/rspack-module-federation-ssr/rspack.server.config.js__tmpl__ +0 -16
  96. package/src/generators/host/files/rspack-module-federation-ssr-ts/rspack.server.config.ts__tmpl__ +0 -16
  97. package/src/generators/remote/files/rspack-module-federation-ssr/rspack.server.config.js__tmpl__ +0 -16
  98. package/src/generators/remote/files/rspack-module-federation-ssr-ts/rspack.server.config.ts__tmpl__ +0 -16
  99. package/src/utils/format-file.d.ts +0 -1
  100. package/src/utils/format-file.js +0 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/react",
3
- "version": "21.0.0-canary.20250206-8bd0bcd",
3
+ "version": "21.0.0-canary.20250418-8619c1d",
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": "21.0.0-canary.20250206-8bd0bcd",
42
- "@nx/js": "21.0.0-canary.20250206-8bd0bcd",
43
- "@nx/eslint": "21.0.0-canary.20250206-8bd0bcd",
44
- "@nx/web": "21.0.0-canary.20250206-8bd0bcd",
45
- "@nx/module-federation": "21.0.0-canary.20250206-8bd0bcd",
41
+ "@nx/devkit": "21.0.0-canary.20250418-8619c1d",
42
+ "@nx/js": "21.0.0-canary.20250418-8619c1d",
43
+ "@nx/eslint": "21.0.0-canary.20250418-8619c1d",
44
+ "@nx/web": "21.0.0-canary.20250418-8619c1d",
45
+ "@nx/module-federation": "21.0.0-canary.20250418-8619c1d",
46
46
  "express": "^4.21.2",
47
47
  "http-proxy-middleware": "^3.0.3",
48
48
  "semver": "^7.6.3"
@@ -57,7 +57,9 @@ function applyReactConfig(options, config = {}) {
57
57
  };
58
58
  }
59
59
  function addHotReload(config) {
60
- if (config.mode === 'development' && config['devServer']?.hot) {
60
+ if (config.mode === 'development' &&
61
+ typeof config['devServer'] === 'object' &&
62
+ config['devServer']?.hot) {
61
63
  // add `react-refresh/babel` to babel loader plugin
62
64
  const babelLoader = config.module.rules.find((rule) => rule &&
63
65
  typeof rule !== 'string' &&
@@ -0,0 +1 @@
1
+ export { createNodesV2, ReactRouterPluginOptions, } from './src/plugins/router-plugin';
@@ -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,9 +26,11 @@ 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,
33
+ useProjectJson: true,
32
34
  ...schema,
33
35
  });
34
36
  }
@@ -44,11 +46,26 @@ async function applicationGeneratorInternal(tree, schema) {
44
46
  });
45
47
  tasks.push(jsInitTask);
46
48
  const options = await (0, normalize_options_1.normalizeOptions)(tree, schema);
47
- // If we are using the new TS solution
48
- // We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
49
- if (options.isUsingTsSolutionConfig) {
50
- (0, ts_solution_setup_1.addProjectToTsSolutionWorkspace)(tree, options.appProjectRoot);
51
- }
49
+ options.useReactRouter =
50
+ options.routing && options.bundler === 'vite'
51
+ ? options.useReactRouter ??
52
+ (await (0, prompt_1.promptWhenInteractive)({
53
+ name: 'response',
54
+ message: 'Would you like to use react-router for server-side rendering?',
55
+ type: 'autocomplete',
56
+ choices: [
57
+ {
58
+ name: 'Yes',
59
+ message: 'I want to use react-router [ https://reactrouter.com/start/framework/routing ]',
60
+ },
61
+ {
62
+ name: 'No',
63
+ message: 'I do not want to use react-router for server-side rendering',
64
+ },
65
+ ],
66
+ initial: 0,
67
+ }, { response: 'No' }).then((r) => r.response === 'Yes'))
68
+ : false;
52
69
  (0, show_possible_warnings_1.showPossibleWarnings)(tree, options);
53
70
  const initTask = await (0, init_1.default)(tree, {
54
71
  ...options,
@@ -83,18 +100,22 @@ async function applicationGeneratorInternal(tree, schema) {
83
100
  }
84
101
  await (0, create_application_files_1.createApplicationFiles)(tree, options);
85
102
  (0, add_project_1.addProject)(tree, options);
103
+ // If we are using the new TS solution
104
+ // We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
105
+ if (options.isUsingTsSolutionConfig) {
106
+ await (0, ts_solution_setup_1.addProjectToTsSolutionWorkspace)(tree, options.appProjectRoot);
107
+ }
86
108
  if (options.style === 'tailwind') {
87
109
  const twTask = await (0, setup_tailwind_1.setupTailwindGenerator)(tree, {
88
110
  project: options.projectName,
89
111
  });
90
112
  tasks.push(twTask);
91
113
  }
114
+ const lintTask = await (0, add_linting_1.addLinting)(tree, options);
115
+ tasks.push(lintTask);
92
116
  if (options.bundler === 'vite') {
93
117
  await (0, add_vite_1.setupViteConfiguration)(tree, options, tasks);
94
118
  }
95
- else if (options.bundler === 'rspack') {
96
- await (0, add_rspack_1.setupRspackConfiguration)(tree, options, tasks);
97
- }
98
119
  else if (options.bundler === 'rsbuild') {
99
120
  await (0, add_rsbuild_1.setupRsbuildConfiguration)(tree, options, tasks);
100
121
  }
@@ -105,8 +126,6 @@ async function applicationGeneratorInternal(tree, schema) {
105
126
  options.inSourceTests) {
106
127
  tree.delete((0, devkit_1.joinPathFragments)(options.appProjectRoot, `src/app/${options.fileName}.spec.tsx`));
107
128
  }
108
- const lintTask = await (0, add_linting_1.addLinting)(tree, options);
109
- tasks.push(lintTask);
110
129
  const e2eTask = await (0, add_e2e_1.addE2e)(tree, options);
111
130
  tasks.push(e2eTask);
112
131
  if (options.unitTestRunner === 'jest') {
@@ -115,23 +134,41 @@ async function applicationGeneratorInternal(tree, schema) {
115
134
  }
116
135
  // Handle tsconfig.spec.json for jest or vitest
117
136
  (0, update_jest_config_1.updateSpecConfig)(tree, options);
118
- const stylePreprocessorTask = await (0, install_common_dependencies_1.installCommonDependencies)(tree, options);
119
- tasks.push(stylePreprocessorTask);
137
+ const commonDependencyTask = await (0, install_common_dependencies_1.installCommonDependencies)(tree, options);
138
+ tasks.push(commonDependencyTask);
120
139
  const styledTask = (0, add_styled_dependencies_1.addStyledModuleDependencies)(tree, options);
121
140
  tasks.push(styledTask);
122
- const routingTask = (0, add_routing_1.addRouting)(tree, options);
123
- tasks.push(routingTask);
141
+ if (!options.useReactRouter) {
142
+ const routingTask = (0, add_routing_1.addRouting)(tree, options);
143
+ tasks.push(routingTask);
144
+ }
124
145
  (0, set_defaults_1.setDefaults)(tree, options);
125
146
  if (options.bundler === 'rspack' && options.style === 'styled-jsx') {
126
147
  (0, add_rspack_1.handleStyledJsxForRspack)(tasks, tree, options);
127
148
  }
149
+ if (options.useReactRouter) {
150
+ (0, devkit_1.updateJson)(tree, (0, devkit_1.joinPathFragments)(options.appProjectRoot, 'tsconfig.json'), (json) => {
151
+ const types = new Set(json.compilerOptions?.types || []);
152
+ types.add('@react-router/node');
153
+ return {
154
+ ...json,
155
+ compilerOptions: {
156
+ ...json.compilerOptions,
157
+ jsx: 'react-jsx',
158
+ moduleResolution: 'bundler',
159
+ types: Array.from(types),
160
+ },
161
+ };
162
+ });
163
+ }
164
+ // Only for the new TS solution
128
165
  (0, ts_solution_setup_1.updateTsconfigFiles)(tree, options.appProjectRoot, 'tsconfig.app.json', {
129
166
  jsx: 'react-jsx',
130
167
  module: 'esnext',
131
168
  moduleResolution: 'bundler',
132
169
  }, options.linter === 'eslint'
133
170
  ? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
134
- : undefined);
171
+ : undefined, options.useReactRouter ? 'app' : 'src');
135
172
  (0, sort_fields_1.sortPackageJsonFields)(tree, options.appProjectRoot);
136
173
  if (!options.skipFormat) {
137
174
  await (0, devkit_1.formatFiles)(tree);
@@ -0,0 +1,14 @@
1
+ import { NavLink } from "react-router";
2
+
3
+ export function AppNav() {
4
+ return (
5
+ <nav>
6
+ <NavLink to="/" end>
7
+ Home
8
+ </NavLink>
9
+ <NavLink to="/about" end>
10
+ About
11
+ </NavLink>
12
+ </nav>
13
+ );
14
+ }
@@ -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
+ }
@@ -0,0 +1,7 @@
1
+ export default function AboutComponent() {
2
+ return (
3
+ <div>
4
+ <h1>About!!!</h1>
5
+ </div>
6
+ );
7
+ }
@@ -0,0 +1,6 @@
1
+ import { type RouteConfig, index, route } from "@react-router/dev/routes";
2
+
3
+ export default [
4
+ index('<%- js ? `./${fileName}.jsx` : `./${fileName}.tsx` %>'),
5
+ route('about', './routes/about.tsx')
6
+ ] satisfies RouteConfig;
@@ -0,0 +1,5 @@
1
+ import type { Config } from "@react-router/dev/config";
2
+
3
+ export default {
4
+ ssr: true,
5
+ } satisfies Config;
@@ -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,5 @@
1
+ .cache
2
+ build
3
+ public/build
4
+ .env
5
+ .react-router
@@ -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
+ }