From f04f316271645304c19ad01c6145792cebb9f926 Mon Sep 17 00:00:00 2001 From: Jack Hsu Date: Wed, 19 Apr 2023 14:00:24 -0400 Subject: [PATCH] feat(react): add rspack experimental support (#16252) --- docs/generated/cli/create-nx-workspace.md | 2 +- .../nx/documents/create-nx-workspace.md | 2 +- .../react/generators/application.json | 2 +- .../packages/workspace/generators/preset.json | 2 +- .../bin/create-nx-workspace.ts | 6 ++++- .../bin/types/bundler-list.ts | 2 +- .../src/generators/application/application.ts | 25 ++++++++++++++++-- .../src/app/__fileName__.spec.tsx__tmpl__ | 10 +++++++ .../files/base-rspack/src/assets/.gitkeep | 0 .../files/base-rspack/src/favicon.ico | Bin 0 -> 15086 bytes .../files/base-rspack/src/index.html | 14 ++++++++++ .../files/base-rspack/src/main.tsx__tmpl__ | 10 +++++++ .../base-rspack/tsconfig.app.json__tmpl__ | 14 ++++++++++ .../generators/application/lib/add-cypress.ts | 2 +- .../generators/application/lib/add-project.ts | 2 +- .../lib/create-application-files.ts | 21 +++++++-------- .../src/generators/application/schema.d.ts | 2 +- .../src/generators/application/schema.json | 2 +- packages/react/src/utils/versions.ts | 3 +++ .../src/generators/preset/schema.d.ts | 2 +- .../src/generators/preset/schema.json | 2 +- 21 files changed, 100 insertions(+), 25 deletions(-) create mode 100644 packages/react/src/generators/application/files/base-rspack/src/app/__fileName__.spec.tsx__tmpl__ create mode 100644 packages/react/src/generators/application/files/base-rspack/src/assets/.gitkeep create mode 100644 packages/react/src/generators/application/files/base-rspack/src/favicon.ico create mode 100644 packages/react/src/generators/application/files/base-rspack/src/index.html create mode 100644 packages/react/src/generators/application/files/base-rspack/src/main.tsx__tmpl__ create mode 100644 packages/react/src/generators/application/files/base-rspack/tsconfig.app.json__tmpl__ diff --git a/docs/generated/cli/create-nx-workspace.md b/docs/generated/cli/create-nx-workspace.md index 2e1ee043afefb..53794079ee85a 100644 --- a/docs/generated/cli/create-nx-workspace.md +++ b/docs/generated/cli/create-nx-workspace.md @@ -35,7 +35,7 @@ The name of the application when a preset with pregenerated app is selected Type: `string` -Choices: [webpack, vite] +Choices: [webpack, vite, rspack] Bundler to be used to build the application diff --git a/docs/generated/packages/nx/documents/create-nx-workspace.md b/docs/generated/packages/nx/documents/create-nx-workspace.md index 2e1ee043afefb..53794079ee85a 100644 --- a/docs/generated/packages/nx/documents/create-nx-workspace.md +++ b/docs/generated/packages/nx/documents/create-nx-workspace.md @@ -35,7 +35,7 @@ The name of the application when a preset with pregenerated app is selected Type: `string` -Choices: [webpack, vite] +Choices: [webpack, vite, rspack] Bundler to be used to build the application diff --git a/docs/generated/packages/react/generators/application.json b/docs/generated/packages/react/generators/application.json index b3c1dcd22e714..db85a3656237d 100644 --- a/docs/generated/packages/react/generators/application.json +++ b/docs/generated/packages/react/generators/application.json @@ -174,7 +174,7 @@ "bundler": { "description": "The bundler to use.", "type": "string", - "enum": ["vite", "webpack"], + "enum": ["vite", "webpack", "rspack"], "x-prompt": "Which bundler do you want to use to build the application?", "default": "webpack", "x-priority": "important" diff --git a/docs/generated/packages/workspace/generators/preset.json b/docs/generated/packages/workspace/generators/preset.json index c9165e99375c2..4d561ddd7323b 100644 --- a/docs/generated/packages/workspace/generators/preset.json +++ b/docs/generated/packages/workspace/generators/preset.json @@ -73,7 +73,7 @@ "bundler": { "description": "The bundler to use for building the application.", "type": "string", - "enum": ["webpack", "vite"], + "enum": ["webpack", "vite", "rspack"], "default": "vite" }, "docker": { diff --git a/packages/create-nx-workspace/bin/create-nx-workspace.ts b/packages/create-nx-workspace/bin/create-nx-workspace.ts index f80e5ef82dbc5..6c9abb9437d34 100644 --- a/packages/create-nx-workspace/bin/create-nx-workspace.ts +++ b/packages/create-nx-workspace/bin/create-nx-workspace.ts @@ -712,6 +712,10 @@ async function determineBundler( name: 'webpack', message: 'Webpack [ https://webpack.js.org/ ]', }, + { + name: 'rspack', + message: 'Rspack [ https://www.rspack.dev/ ]', + }, ]; if (!parsedArgs.bundler) { @@ -745,5 +749,5 @@ async function determineBundler( process.exit(1); } - return Promise.resolve(parsedArgs.bundler); + return parsedArgs.bundler; } diff --git a/packages/create-nx-workspace/bin/types/bundler-list.ts b/packages/create-nx-workspace/bin/types/bundler-list.ts index 6fd3bceee9308..6e241bd33974c 100644 --- a/packages/create-nx-workspace/bin/types/bundler-list.ts +++ b/packages/create-nx-workspace/bin/types/bundler-list.ts @@ -1,4 +1,4 @@ // Bundler to be used to build the application -export const bundlerList = ['webpack', 'vite']; +export const bundlerList = ['webpack', 'vite', 'rspack']; export type Bundler = typeof bundlerList[number]; diff --git a/packages/react/src/generators/application/application.ts b/packages/react/src/generators/application/application.ts index 95fbe55064205..7025b47e6a423 100644 --- a/packages/react/src/generators/application/application.ts +++ b/packages/react/src/generators/application/application.ts @@ -6,7 +6,7 @@ import { NormalizedSchema, Schema } from './schema'; import { createApplicationFiles } from './lib/create-application-files'; import { updateSpecConfig } from './lib/update-jest-config'; import { normalizeOptions } from './lib/normalize-options'; -import { addProject } from './lib/add-project'; +import { addProject, maybeJs } from './lib/add-project'; import { addCypress } from './lib/add-cypress'; import { addJest } from './lib/add-jest'; import { addRouting } from './lib/add-routing'; @@ -27,7 +27,11 @@ import { import reactInitGenerator from '../init/init'; import { Linter, lintProjectGenerator } from '@nx/linter'; import { mapLintPattern } from '@nx/linter/src/generators/lint-project/lint-project'; -import { nxVersion, swcLoaderVersion } from '../../utils/versions'; +import { + nxRspackVersion, + nxVersion, + swcLoaderVersion, +} from '../../utils/versions'; import { installCommonDependencies } from './lib/install-common-dependencies'; import { extractTsConfigBase } from '../../utils/create-ts-config'; import { addSwcDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies'; @@ -135,6 +139,23 @@ export async function applicationGenerator( skipFormat: true, }); tasks.push(webpackInitTask); + } else if (options.bundler === 'rspack') { + const { configurationGenerator } = ensurePackage( + '@nrwl/rspack', + nxRspackVersion + ); + const rspackTask = await configurationGenerator(host, { + project: options.projectName, + main: joinPathFragments( + options.appProjectRoot, + maybeJs(options, `src/main.tsx`) + ), + tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'), + target: 'web', + newProject: true, + uiFramework: 'react', + }); + tasks.push(rspackTask); } if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') { diff --git a/packages/react/src/generators/application/files/base-rspack/src/app/__fileName__.spec.tsx__tmpl__ b/packages/react/src/generators/application/files/base-rspack/src/app/__fileName__.spec.tsx__tmpl__ new file mode 100644 index 0000000000000..a156be880642a --- /dev/null +++ b/packages/react/src/generators/application/files/base-rspack/src/app/__fileName__.spec.tsx__tmpl__ @@ -0,0 +1,10 @@ +import { render } from '@testing-library/react'; +<% if (routing) { %> +import { BrowserRouter } from 'react-router-dom'; +<% } %> + +import App from './<%= fileName %>'; + +describe('App', () => { + <%- appTests %> +}); diff --git a/packages/react/src/generators/application/files/base-rspack/src/assets/.gitkeep b/packages/react/src/generators/application/files/base-rspack/src/assets/.gitkeep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/packages/react/src/generators/application/files/base-rspack/src/favicon.ico b/packages/react/src/generators/application/files/base-rspack/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..317ebcb2336e0833a22dddf0ab287849f26fda57 GIT binary patch literal 15086 zcmeI332;U^%p|z7g|#(P)qFEA@4f!_@qOK2 z_lJl}!lhL!VT_U|uN7%8B2iKH??xhDa;*`g{yjTFWHvXn;2s{4R7kH|pKGdy(7z!K zgftM+Ku7~24TLlh(!g)gz|foI94G^t2^IO$uvX$3(OR0<_5L2sB)lMAMy|+`xodJ{ z_Uh_1m)~h?a;2W{dmhM;u!YGo=)OdmId_B<%^V^{ovI@y`7^g1_V9G}*f# zNzAtvou}I!W1#{M^@ROc(BZ! z+F!!_aR&Px3_reO(EW+TwlW~tv*2zr?iP7(d~a~yA|@*a89IUke+c472NXM0wiX{- zl`UrZC^1XYyf%1u)-Y)jj9;MZ!SLfd2Hl?o|80Su%Z?To_=^g_Jt0oa#CT*tjx>BI z16wec&AOWNK<#i0Qd=1O$fymLRoUR*%;h@*@v7}wApDl^w*h}!sYq%kw+DKDY)@&A z@9$ULEB3qkR#85`lb8#WZw=@})#kQig9oqy^I$dj&k4jU&^2(M3q{n1AKeGUKPFbr z1^<)aH;VsG@J|B&l>UtU#Ejv3GIqERzYgL@UOAWtW<{p#zy`WyJgpCy8$c_e%wYJL zyGHRRx38)HyjU3y{-4z6)pzb>&Q1pR)B&u01F-|&Gx4EZWK$nkUkOI|(D4UHOXg_- zw{OBf!oWQUn)Pe(=f=nt=zkmdjpO^o8ZZ9o_|4tW1ni+Un9iCW47*-ut$KQOww!;u z`0q)$s6IZO!~9$e_P9X!hqLxu`fpcL|2f^I5d4*a@Dq28;@2271v_N+5HqYZ>x;&O z05*7JT)mUe&%S0@UD)@&8SmQrMtsDfZT;fkdA!r(S=}Oz>iP)w=W508=Rc#nNn7ym z1;42c|8($ALY8#a({%1#IXbWn9-Y|0eDY$_L&j{63?{?AH{);EzcqfydD$@-B`Y3<%IIj7S7rK_N}je^=dEk%JQ4c z!tBdTPE3Tse;oYF>cnrapWq*o)m47X1`~6@(!Y29#>-#8zm&LXrXa(3=7Z)ElaQqj z-#0JJy3Fi(C#Rx(`=VXtJ63E2_bZGCz+QRa{W0e2(m3sI?LOcUBx)~^YCqZ{XEPX)C>G>U4tfqeH8L(3|pQR*zbL1 zT9e~4Tb5p9_G}$y4t`i*4t_Mr9QYvL9C&Ah*}t`q*}S+VYh0M6GxTTSXI)hMpMpIq zD1ImYqJLzbj0}~EpE-aH#VCH_udYEW#`P2zYmi&xSPs_{n6tBj=MY|-XrA;SGA_>y zGtU$?HXm$gYj*!N)_nQ59%lQdXtQZS3*#PC-{iB_sm+ytD*7j`D*k(P&IH2GHT}Eh z5697eQECVIGQAUe#eU2I!yI&%0CP#>%6MWV z@zS!p@+Y1i1b^QuuEF*13CuB zu69dve5k7&Wgb+^s|UB08Dr3u`h@yM0NTj4h7MnHo-4@xmyr7(*4$rpPwsCDZ@2be zRz9V^GnV;;?^Lk%ynzq&K(Aix`mWmW`^152Hoy$CTYVehpD-S1-W^#k#{0^L`V6CN+E z!w+xte;2vu4AmVNEFUOBmrBL>6MK@!O2*N|2=d|Y;oN&A&qv=qKn73lDD zI(+oJAdgv>Yr}8(&@ZuAZE%XUXmX(U!N+Z_sjL<1vjy1R+1IeHt`79fnYdOL{$ci7 z%3f0A*;Zt@ED&Gjm|OFTYBDe%bbo*xXAQsFz+Q`fVBH!N2)kaxN8P$c>sp~QXnv>b zwq=W3&Mtmih7xkR$YA)1Yi?avHNR6C99!u6fh=cL|KQ&PwF!n@ud^n(HNIImHD!h87!i*t?G|p0o+eelJ?B@A64_9%SBhNaJ64EvKgD&%LjLCYnNfc; znj?%*p@*?dq#NqcQFmmX($wms@CSAr9#>hUR^=I+=0B)vvGX%T&#h$kmX*s=^M2E!@N9#m?LhMvz}YB+kd zG~mbP|D(;{s_#;hsKK9lbVK&Lo734x7SIFJ9V_}2$@q?zm^7?*XH94w5Qae{7zOMUF z^?%F%)c1Y)Q?Iy?I>knw*8gYW#ok|2gdS=YYZLiD=CW|Nj;n^x!=S#iJ#`~Ld79+xXpVmUK^B(xO_vO!btA9y7w3L3-0j-y4 z?M-V{%z;JI`bk7yFDcP}OcCd*{Q9S5$iGA7*E1@tfkyjAi!;wP^O71cZ^Ep)qrQ)N z#wqw0_HS;T7x3y|`P==i3hEwK%|>fZ)c&@kgKO1~5<5xBSk?iZV?KI6&i72H6S9A* z=U(*e)EqEs?Oc04)V-~K5AUmh|62H4*`UAtItO$O(q5?6jj+K^oD!04r=6#dsxp?~}{`?&sXn#q2 zGuY~7>O2=!u@@Kfu7q=W*4egu@qPMRM>(eyYyaIE<|j%d=iWNdGsx%c!902v#ngNg z@#U-O_4xN$s_9?(`{>{>7~-6FgWpBpqXb`Ydc3OFL#&I}Irse9F_8R@4zSS*Y*o*B zXL?6*Aw!AfkNCgcr#*yj&p3ZDe2y>v$>FUdKIy_2N~}6AbHc7gA3`6$g@1o|dE>vz z4pl(j9;kyMsjaw}lO?(?Xg%4k!5%^t#@5n=WVc&JRa+XT$~#@rldvN3S1rEpU$;XgxVny7mki3 z-Hh|jUCHrUXuLr!)`w>wgO0N%KTB-1di>cj(x3Bav`7v z3G7EIbU$z>`Nad7Rk_&OT-W{;qg)-GXV-aJT#(ozdmnA~Rq3GQ_3mby(>q6Ocb-RgTUhTN)))x>m&eD;$J5Bg zo&DhY36Yg=J=$Z>t}RJ>o|@hAcwWzN#r(WJ52^g$lh^!63@hh+dR$&_dEGu&^CR*< z!oFqSqO@>xZ*nC2oiOd0eS*F^IL~W-rsrO`J`ej{=ou_q^_(<$&-3f^J z&L^MSYWIe{&pYq&9eGaArA~*kA + + + + <%= className %> + + + + + + +
+ + diff --git a/packages/react/src/generators/application/files/base-rspack/src/main.tsx__tmpl__ b/packages/react/src/generators/application/files/base-rspack/src/main.tsx__tmpl__ new file mode 100644 index 0000000000000..d5a60a7b0dd14 --- /dev/null +++ b/packages/react/src/generators/application/files/base-rspack/src/main.tsx__tmpl__ @@ -0,0 +1,10 @@ +<% if (strict) { %>import { StrictMode } from 'react';<% } %> +import * as ReactDOM from 'react-dom/client'; +<% if (routing) { %>import { BrowserRouter } from 'react-router-dom';<% } %> + +import App from './app/<%= fileName %>'; + +const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement); +root.render( +<% if (strict) { %><% } %><% if (routing) { %><% } %><% if (routing) { %><% } %><% if (strict) { %><% } %> +); diff --git a/packages/react/src/generators/application/files/base-rspack/tsconfig.app.json__tmpl__ b/packages/react/src/generators/application/files/base-rspack/tsconfig.app.json__tmpl__ new file mode 100644 index 0000000000000..95917f8cff001 --- /dev/null +++ b/packages/react/src/generators/application/files/base-rspack/tsconfig.app.json__tmpl__ @@ -0,0 +1,14 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "<%= offsetFromRoot %>dist/out-tsc", + "types": ["node"] + }, + "files": [ + <% if (style === 'styled-jsx') { %>"<%= offsetFromRoot %>node_modules/@nx/react/typings/styled-jsx.d.ts",<% } %> + "<%= offsetFromRoot %>node_modules/@nx/react/typings/cssmodule.d.ts", + "<%= offsetFromRoot %>node_modules/@nx/react/typings/image.d.ts" + ], + "exclude": ["jest.config.ts","src/**/*.spec.ts", "src/**/*.test.ts", "src/**/*.spec.tsx", "src/**/*.test.tsx", "src/**/*.spec.js", "src/**/*.test.js", "src/**/*.spec.jsx", "src/**/*.test.jsx"], + "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"] +} diff --git a/packages/react/src/generators/application/lib/add-cypress.ts b/packages/react/src/generators/application/lib/add-cypress.ts index 2886adb0e480b..cb65f18050c6e 100644 --- a/packages/react/src/generators/application/lib/add-cypress.ts +++ b/packages/react/src/generators/application/lib/add-cypress.ts @@ -22,7 +22,7 @@ export async function addCypress(host: Tree, options: NormalizedSchema) { name: options.e2eProjectName, directory: options.directory, project: options.projectName, - bundler: options.bundler, + bundler: options.bundler === 'rspack' ? 'webpack' : options.bundler, skipFormat: true, }); } diff --git a/packages/react/src/generators/application/lib/add-project.ts b/packages/react/src/generators/application/lib/add-project.ts index 72c18a5f97720..5a2075995e779 100644 --- a/packages/react/src/generators/application/lib/add-project.ts +++ b/packages/react/src/generators/application/lib/add-project.ts @@ -27,7 +27,7 @@ export function addProject(host, options: NormalizedSchema) { }); } -function maybeJs(options: NormalizedSchema, path: string): string { +export function maybeJs(options: NormalizedSchema, path: string): string { return options.js && (path.endsWith('.ts') || path.endsWith('.tsx')) ? path.replace(/\.tsx?$/, '.js') : path; diff --git a/packages/react/src/generators/application/lib/create-application-files.ts b/packages/react/src/generators/application/lib/create-application-files.ts index 473b9947886fb..7245c3d9625a3 100644 --- a/packages/react/src/generators/application/lib/create-application-files.ts +++ b/packages/react/src/generators/application/lib/create-application-files.ts @@ -34,17 +34,16 @@ export function createApplicationFiles(host: Tree, options: NormalizedSchema) { inSourceVitestTests: getInSourceVitestTestsTemplate(appTests), }; - generateFiles( - host, - join( - __dirname, - options.bundler === 'vite' - ? '../files/base-vite' - : '../files/base-webpack' - ), - options.appProjectRoot, - templateVariables - ); + let fileDirectory: string; + if (options.bundler === 'vite') { + fileDirectory = join(__dirname, '../files/base-vite'); + } else if (options.bundler === 'webpack') { + fileDirectory = join(__dirname, '../files/base-webpack'); + } else if (options.bundler === 'rspack') { + fileDirectory = join(__dirname, '../files/base-rspack'); + } + + generateFiles(host, fileDirectory, options.appProjectRoot, templateVariables); if ( options.unitTestRunner === 'none' || diff --git a/packages/react/src/generators/application/schema.d.ts b/packages/react/src/generators/application/schema.d.ts index 42398cde01b3a..bc4f9877e3f34 100644 --- a/packages/react/src/generators/application/schema.d.ts +++ b/packages/react/src/generators/application/schema.d.ts @@ -28,7 +28,7 @@ export interface Schema { devServerPort?: number; skipPackageJson?: boolean; rootProject?: boolean; - bundler?: 'webpack' | 'vite'; + bundler?: 'webpack' | 'vite' | 'rspack'; minimal?: boolean; } diff --git a/packages/react/src/generators/application/schema.json b/packages/react/src/generators/application/schema.json index 73e6e573b8624..fec7f8af8b74e 100644 --- a/packages/react/src/generators/application/schema.json +++ b/packages/react/src/generators/application/schema.json @@ -180,7 +180,7 @@ "bundler": { "description": "The bundler to use.", "type": "string", - "enum": ["vite", "webpack"], + "enum": ["vite", "webpack", "rspack"], "x-prompt": "Which bundler do you want to use to build the application?", "default": "webpack", "x-priority": "important" diff --git a/packages/react/src/utils/versions.ts b/packages/react/src/utils/versions.ts index 62e5744688004..e531d5fe39174 100755 --- a/packages/react/src/utils/versions.ts +++ b/packages/react/src/utils/versions.ts @@ -1,5 +1,8 @@ export const nxVersion = require('../../package.json').version; +// Always pull the latest version until we merge rspack plugin into the repo. +export const nxRspackVersion = '*'; + export const reactVersion = '18.2.0'; export const reactDomVersion = '18.2.0'; export const reactIsVersion = '18.2.0'; diff --git a/packages/workspace/src/generators/preset/schema.d.ts b/packages/workspace/src/generators/preset/schema.d.ts index aa6f25925edd2..f16f4fdad09b8 100644 --- a/packages/workspace/src/generators/preset/schema.d.ts +++ b/packages/workspace/src/generators/preset/schema.d.ts @@ -10,7 +10,7 @@ export interface Schema { standaloneConfig?: boolean; framework?: string; packageManager?: PackageManager; - bundler?: 'vite' | 'webpack'; + bundler?: 'vite' | 'webpack' | 'rspack'; docker?: boolean; routing?: boolean; standaloneApi?: boolean; diff --git a/packages/workspace/src/generators/preset/schema.json b/packages/workspace/src/generators/preset/schema.json index 3731fb5981963..423a18fb8a900 100644 --- a/packages/workspace/src/generators/preset/schema.json +++ b/packages/workspace/src/generators/preset/schema.json @@ -76,7 +76,7 @@ "bundler": { "description": "The bundler to use for building the application.", "type": "string", - "enum": ["webpack", "vite"], + "enum": ["webpack", "vite", "rspack"], "default": "vite" }, "docker": {