diff --git a/.changeset/chatty-papers-obey.md b/.changeset/chatty-papers-obey.md new file mode 100644 index 00000000000..a845151cc84 --- /dev/null +++ b/.changeset/chatty-papers-obey.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/packages/ui/package.json b/packages/ui/package.json index 67c33043292..549ad764c6e 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -48,6 +48,7 @@ "build": "pnpm build:umd && pnpm build:esm", "build:analyze": "rspack build --config rspack.config.js --env production --analyze", "build:esm": "tsdown", + "build:rsdoctor": "RSDOCTOR=true rspack build --config rspack.config.js --env production", "build:umd": "rspack build --config rspack.config.js --env production", "bundlewatch": "FORCE_COLOR=1 bundlewatch --config bundlewatch.config.json", "bundlewatch:fix": "node bundlewatch-fix.mjs", @@ -84,6 +85,7 @@ }, "devDependencies": { "@floating-ui/react-dom": "^2.1.6", + "@rsdoctor/rspack-plugin": "^1.0.5", "@rspack/cli": "^1.6.0", "@rspack/core": "^1.6.0", "@rspack/plugin-react-refresh": "^1.5.2", diff --git a/packages/ui/rspack.config.js b/packages/ui/rspack.config.js index a949df20466..493f690e36e 100644 --- a/packages/ui/rspack.config.js +++ b/packages/ui/rspack.config.js @@ -7,6 +7,8 @@ import { merge } from 'webpack-merge'; import ReactRefreshPlugin from '@rspack/plugin-react-refresh'; import { svgLoader, typescriptLoaderProd, typescriptLoaderDev } from '../../scripts/rspack-common.js'; +const isRsdoctorEnabled = !!process.env.RSDOCTOR; + const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -56,19 +58,12 @@ const common = ({ mode, variant }) => { optimization: { splitChunks: { cacheGroups: { - /** - * Sign up is shared between the SignUp component and the SignIn component. - */ - signUp: { - minChunks: 1, - name: 'signup', - test: module => !!(module.resource && module.resource.includes('/components/SignUp')), - }, common: { minChunks: 1, name: 'ui-common', priority: -20, - test: module => !!(module.resource && !module.resource.includes('/components')), + test: module => + !!(module instanceof rspack.NormalModule && module.resource && !module.resource.includes('/components')), }, defaultVendors: { minChunks: 1, @@ -139,14 +134,34 @@ const commonForProdBrowser = () => { /** * Production configuration - builds UMD browser variant only * @param {'development'|'production'} mode - * @returns {import('@rspack/core').Configuration} + * @returns {Promise} */ -const prodConfig = mode => { +const prodConfig = async mode => { + /** @type {import('@rspack/core').Configuration['plugins']} */ + const plugins = []; + + if (isRsdoctorEnabled) { + const { RsdoctorRspackPlugin } = await import('@rsdoctor/rspack-plugin'); + plugins.push( + new RsdoctorRspackPlugin({ + supports: { + generateTileGraph: true, + }, + linter: { + rules: { + 'ecma-version-check': 'off', + }, + }, + }), + ); + } + // Browser bundle with chunks (UMD) const uiBrowser = merge( entryForVariant(variants.uiBrowser), common({ mode, variant: variants.uiBrowser }), commonForProdBrowser(), + { plugins }, ); return uiBrowser; @@ -186,7 +201,14 @@ const devConfig = (mode, env) => { port, hot: true, liveReload: false, - client: { webSocketURL: `auto://${devUrl.host}/ws` }, + client: { + overlay: { + errors: true, + warnings: true, + runtimeErrors: false, + }, + webSocketURL: `auto://${devUrl.host}/ws`, + }, }, cache: false, experiments: { @@ -197,7 +219,7 @@ const devConfig = (mode, env) => { }); }; -export default env => { +export default async env => { const mode = env.production ? 'production' : 'development'; return isProduction(mode) ? prodConfig(mode) : devConfig(mode, env); }; diff --git a/packages/ui/src/Components.tsx b/packages/ui/src/Components.tsx index 719187bfadd..5286c56191f 100644 --- a/packages/ui/src/Components.tsx +++ b/packages/ui/src/Components.tsx @@ -448,158 +448,6 @@ const Components = (props: ComponentsProps) => { props.onComponentsMounted(); }, []); - const mountedOneTapModal = ( - - ); - - const mountedSignInModal = ( - componentsControls.closeModal('signIn')} - onExternalNavigate={() => componentsControls.closeModal('signIn')} - startPath={buildVirtualRouterUrl({ base: '/sign-in', path: urlStateParam?.path })} - componentName={'SignInModal'} - > - - - - - ); - - const mountedSignUpModal = ( - componentsControls.closeModal('signUp')} - onExternalNavigate={() => componentsControls.closeModal('signUp')} - startPath={buildVirtualRouterUrl({ base: '/sign-up', path: urlStateParam?.path })} - componentName={'SignUpModal'} - > - - - - - ); - - const mountedUserProfileModal = ( - componentsControls.closeModal('userProfile')} - onExternalNavigate={() => componentsControls.closeModal('userProfile')} - startPath={buildVirtualRouterUrl({ - base: '/user', - path: userProfileModal?.__experimental_startPath || urlStateParam?.path, - })} - componentName={'UserProfileModal'} - modalContainerSx={{ alignItems: 'center' }} - modalContentSx={t => ({ height: `min(${t.sizes.$176}, calc(100% - ${t.sizes.$12}))`, margin: 0 })} - > - - - ); - - const mountedUserVerificationModal = ( - componentsControls.closeModal('userVerification')} - onExternalNavigate={() => componentsControls.closeModal('userVerification')} - startPath={buildVirtualRouterUrl({ base: '/user-verification', path: urlStateParam?.path })} - componentName={'UserVerificationModal'} - modalContainerSx={{ alignItems: 'center' }} - > - - - ); - - const mountedOrganizationProfileModal = ( - componentsControls.closeModal('organizationProfile')} - onExternalNavigate={() => componentsControls.closeModal('organizationProfile')} - startPath={buildVirtualRouterUrl({ - base: '/organizationProfile', - path: organizationProfileModal?.__experimental_startPath || urlStateParam?.path, - })} - componentName={'OrganizationProfileModal'} - modalContainerSx={{ alignItems: 'center' }} - modalContentSx={t => ({ height: `min(${t.sizes.$176}, calc(100% - ${t.sizes.$12}))`, margin: 0 })} - > - - - ); - - const mountedCreateOrganizationModal = ( - componentsControls.closeModal('createOrganization')} - onExternalNavigate={() => componentsControls.closeModal('createOrganization')} - startPath={buildVirtualRouterUrl({ base: '/createOrganization', path: urlStateParam?.path })} - componentName={'CreateOrganizationModal'} - modalContainerSx={{ alignItems: 'center' }} - modalContentSx={t => ({ height: `min(${t.sizes.$120}, calc(100% - ${t.sizes.$12}))`, margin: 0 })} - > - - - ); - - const mountedWaitlistModal = ( - componentsControls.closeModal('waitlist')} - onExternalNavigate={() => componentsControls.closeModal('waitlist')} - startPath={buildVirtualRouterUrl({ base: '/waitlist', path: urlStateParam?.path })} - componentName={'WaitlistModal'} - > - - - - ); - - const mountedBlankCaptchaModal = ( - /** - * Captcha modal should not close on `Clerk.navigate()`, hence we are not passing `onExternalNavigate`. - */ - componentsControls.closeModal('blankCaptcha')} - startPath={buildVirtualRouterUrl({ base: '/blank-captcha', path: urlStateParam?.path })} - componentName={'BlankCaptchaModal'} - canCloseModal={false} - modalId={'cl-modal-captcha-wrapper'} - modalStyle={{ visibility: 'hidden', pointerEvents: 'none' }} - > - - - ); - return ( { ); })} - {googleOneTapModal && mountedOneTapModal} - {signInModal && mountedSignInModal} - {signUpModal && mountedSignUpModal} - {userProfileModal && mountedUserProfileModal} - {userVerificationModal && mountedUserVerificationModal} - {organizationProfileModal && mountedOrganizationProfileModal} - {createOrganizationModal && mountedCreateOrganizationModal} - {waitlistModal && mountedWaitlistModal} - {blankCaptchaModal && mountedBlankCaptchaModal} + {googleOneTapModal && ( + + )} + + {signInModal && ( + componentsControls.closeModal('signIn')} + onExternalNavigate={() => componentsControls.closeModal('signIn')} + startPath={buildVirtualRouterUrl({ base: '/sign-in', path: urlStateParam?.path })} + componentName={'SignInModal'} + > + + + + + )} + + {signUpModal && ( + componentsControls.closeModal('signUp')} + onExternalNavigate={() => componentsControls.closeModal('signUp')} + startPath={buildVirtualRouterUrl({ base: '/sign-up', path: urlStateParam?.path })} + componentName={'SignUpModal'} + > + + + + + )} + + {userProfileModal && ( + componentsControls.closeModal('userProfile')} + onExternalNavigate={() => componentsControls.closeModal('userProfile')} + startPath={buildVirtualRouterUrl({ + base: '/user', + path: userProfileModal?.__experimental_startPath || urlStateParam?.path, + })} + componentName={'UserProfileModal'} + modalContainerSx={{ alignItems: 'center' }} + modalContentSx={t => ({ height: `min(${t.sizes.$176}, calc(100% - ${t.sizes.$12}))`, margin: 0 })} + > + + + )} + + {userVerificationModal && ( + componentsControls.closeModal('userVerification')} + onExternalNavigate={() => componentsControls.closeModal('userVerification')} + startPath={buildVirtualRouterUrl({ base: '/user-verification', path: urlStateParam?.path })} + componentName={'UserVerificationModal'} + modalContainerSx={{ alignItems: 'center' }} + > + + + )} + + {organizationProfileModal && ( + componentsControls.closeModal('organizationProfile')} + onExternalNavigate={() => componentsControls.closeModal('organizationProfile')} + startPath={buildVirtualRouterUrl({ + base: '/organizationProfile', + path: organizationProfileModal?.__experimental_startPath || urlStateParam?.path, + })} + componentName={'OrganizationProfileModal'} + modalContainerSx={{ alignItems: 'center' }} + modalContentSx={t => ({ height: `min(${t.sizes.$176}, calc(100% - ${t.sizes.$12}))`, margin: 0 })} + > + + + )} + + {createOrganizationModal && ( + componentsControls.closeModal('createOrganization')} + onExternalNavigate={() => componentsControls.closeModal('createOrganization')} + startPath={buildVirtualRouterUrl({ base: '/createOrganization', path: urlStateParam?.path })} + componentName={'CreateOrganizationModal'} + modalContainerSx={{ alignItems: 'center' }} + modalContentSx={t => ({ height: `min(${t.sizes.$120}, calc(100% - ${t.sizes.$12}))`, margin: 0 })} + > + + + )} + + {waitlistModal && ( + componentsControls.closeModal('waitlist')} + onExternalNavigate={() => componentsControls.closeModal('waitlist')} + startPath={buildVirtualRouterUrl({ base: '/waitlist', path: urlStateParam?.path })} + componentName={'WaitlistModal'} + > + + + + )} + + {blankCaptchaModal && ( + componentsControls.closeModal('blankCaptcha')} + startPath={buildVirtualRouterUrl({ base: '/blank-captcha', path: urlStateParam?.path })} + componentName={'BlankCaptchaModal'} + canCloseModal={false} + modalId={'cl-modal-captcha-wrapper'} + modalStyle={{ visibility: 'hidden', pointerEvents: 'none' }} + > + + + )} =13.7} @@ -7527,6 +7578,11 @@ packages: engines: {node: '>=4'} hasBin: true + envinfo@7.19.0: + resolution: {integrity: sha512-DoSM9VyG6O3vqBf+p3Gjgr/Q52HYBBtO3v+4koAxt1MnWr+zEnxE+nke/yXS4lt2P4SYCHQ4V3f1i88LQVOpAw==} + engines: {node: '>=4'} + hasBin: true + environment@1.1.0: resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} engines: {node: '>=18'} @@ -7581,6 +7637,9 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} + es-toolkit@1.42.0: + resolution: {integrity: sha512-SLHIyY7VfDJBM8clz4+T2oquwTQxEzu263AyhVK4jREOAwJ+8eebaa4wM3nlvnAqhDrMm2EsA6hWHaQsMPQ1nA==} + esbuild-plugin-file-path-extensions@2.1.4: resolution: {integrity: sha512-lNjylaAsJMprYg28zjUyBivP3y0ms9b7RJZ5tdhDUFLa3sCbqZw4wDnbFUSmnyZYWhCYDPxxp7KkXM2TXGw3PQ==} engines: {node: '>=v14.0.0', npm: '>=7.0.0'} @@ -13089,6 +13148,10 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} + tapable@2.2.3: + resolution: {integrity: sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==} + engines: {node: '>=6'} + tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} @@ -18812,8 +18875,18 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.53.1': optional: true + '@rsbuild/plugin-check-syntax@1.5.0': + dependencies: + acorn: 8.15.0 + browserslist-to-es-version: 1.2.0 + htmlparser2: 10.0.0 + picocolors: 1.1.1 + source-map: 0.7.6 + '@rsdoctor/client@0.4.13': {} + '@rsdoctor/client@1.3.13': {} + '@rsdoctor/core@0.4.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12))': dependencies: '@rsdoctor/graph': 0.4.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) @@ -18837,6 +18910,28 @@ snapshots: - utf-8-validate - webpack + '@rsdoctor/core@1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12))': + dependencies: + '@rsbuild/plugin-check-syntax': 1.5.0 + '@rsdoctor/graph': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + '@rsdoctor/sdk': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + '@rsdoctor/types': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + '@rsdoctor/utils': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + browserslist-load-config: 1.0.1 + enhanced-resolve: 5.12.0 + es-toolkit: 1.42.0 + filesize: 10.1.6 + fs-extra: 11.3.2 + semver: 7.7.3 + source-map: 0.7.6 + transitivePeerDependencies: + - '@rsbuild/core' + - '@rspack/core' + - bufferutil + - supports-color + - utf-8-validate + - webpack + '@rsdoctor/graph@0.4.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12))': dependencies: '@rsdoctor/types': 0.4.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) @@ -18851,6 +18946,17 @@ snapshots: - utf-8-validate - webpack + '@rsdoctor/graph@1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12))': + dependencies: + '@rsdoctor/types': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + '@rsdoctor/utils': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + es-toolkit: 1.42.0 + path-browserify: 1.0.1 + source-map: 0.7.6 + transitivePeerDependencies: + - '@rspack/core' + - webpack + '@rsdoctor/rspack-plugin@0.4.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12))': dependencies: '@rsdoctor/core': 0.4.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) @@ -18867,6 +18973,22 @@ snapshots: - utf-8-validate - webpack + '@rsdoctor/rspack-plugin@1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12))': + dependencies: + '@rsdoctor/core': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + '@rsdoctor/graph': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + '@rsdoctor/sdk': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + '@rsdoctor/types': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + '@rsdoctor/utils': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + optionalDependencies: + '@rspack/core': 1.6.1(@swc/helpers@0.5.17) + transitivePeerDependencies: + - '@rsbuild/core' + - bufferutil + - supports-color + - utf-8-validate + - webpack + '@rsdoctor/sdk@0.4.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12))': dependencies: '@rsdoctor/client': 0.4.13 @@ -18892,6 +19014,22 @@ snapshots: - utf-8-validate - webpack + '@rsdoctor/sdk@1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12))': + dependencies: + '@rsdoctor/client': 1.3.13 + '@rsdoctor/graph': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + '@rsdoctor/types': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + '@rsdoctor/utils': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + safer-buffer: 2.1.2 + socket.io: 4.8.1 + tapable: 2.2.3 + transitivePeerDependencies: + - '@rspack/core' + - bufferutil + - supports-color + - utf-8-validate + - webpack + '@rsdoctor/types@0.4.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12))': dependencies: '@types/connect': 3.4.38 @@ -18902,6 +19040,16 @@ snapshots: optionalDependencies: '@rspack/core': 1.6.1(@swc/helpers@0.5.17) + '@rsdoctor/types@1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12))': + dependencies: + '@types/connect': 3.4.38 + '@types/estree': 1.0.5 + '@types/tapable': 2.2.7 + source-map: 0.7.6 + optionalDependencies: + '@rspack/core': 1.6.1(@swc/helpers@0.5.17) + webpack: 5.102.1(esbuild@0.25.12) + '@rsdoctor/utils@0.4.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12))': dependencies: '@babel/code-frame': 7.25.7 @@ -18926,6 +19074,27 @@ snapshots: - supports-color - webpack + '@rsdoctor/utils@1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12))': + dependencies: + '@babel/code-frame': 7.26.2 + '@rsdoctor/types': 1.3.13(@rspack/core@1.6.1(@swc/helpers@0.5.17))(webpack@5.102.1(esbuild@0.25.12)) + '@types/estree': 1.0.5 + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) + acorn-walk: 8.3.4 + deep-eql: 4.1.4 + envinfo: 7.19.0 + fs-extra: 11.3.2 + get-port: 5.1.1 + json-stream-stringify: 3.0.1 + lines-and-columns: 2.0.4 + picocolors: 1.1.1 + rslog: 1.3.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - '@rspack/core' + - webpack + '@rspack/binding-darwin-arm64@1.6.1': optional: true @@ -21490,6 +21659,12 @@ snapshots: dependencies: pako: 0.2.9 + browserslist-load-config@1.0.1: {} + + browserslist-to-es-version@1.2.0: + dependencies: + browserslist: 4.27.0 + browserslist@4.27.0: dependencies: baseline-browser-mapping: 2.8.25 @@ -22822,6 +22997,8 @@ snapshots: envinfo@7.14.0: {} + envinfo@7.19.0: {} + environment@1.1.0: {} error-ex@1.3.4: @@ -22951,6 +23128,8 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 + es-toolkit@1.42.0: {} + esbuild-plugin-file-path-extensions@2.1.4: {} esbuild@0.25.12: @@ -29961,6 +30140,8 @@ snapshots: tapable@2.2.1: {} + tapable@2.2.3: {} + tapable@2.3.0: {} tar-stream@3.1.7: