diff --git a/.changeset/legacy-browser-variant.md b/.changeset/legacy-browser-variant.md new file mode 100644 index 00000000000..f8cb9dfc6f0 --- /dev/null +++ b/.changeset/legacy-browser-variant.md @@ -0,0 +1,5 @@ +--- +"@clerk/ui": minor +--- + +Add legacy browser variant build support for older browsers diff --git a/packages/clerk-js/package.json b/packages/clerk-js/package.json index bf81e95b410..a0798d3e640 100644 --- a/packages/clerk-js/package.json +++ b/packages/clerk-js/package.json @@ -66,14 +66,14 @@ "@solana/wallet-adapter-react": "catalog:module-manager", "@solana/wallet-standard": "catalog:module-manager", "@stripe/stripe-js": "5.6.0", - "@swc/helpers": "^0.5.17", + "@swc/helpers": "catalog:repo", "@tanstack/query-core": "5.87.4", "@wallet-standard/core": "catalog:module-manager", "@zxcvbn-ts/core": "catalog:module-manager", "@zxcvbn-ts/language-common": "catalog:module-manager", "alien-signals": "2.0.6", "browser-tabs-lock": "1.3.0", - "core-js": "3.41.0", + "core-js": "catalog:repo", "crypto-js": "^4.2.0", "dequal": "2.0.3" }, diff --git a/packages/ui/bundlewatch.config.json b/packages/ui/bundlewatch.config.json index bf35863bb61..6aa64ab7a8a 100644 --- a/packages/ui/bundlewatch.config.json +++ b/packages/ui/bundlewatch.config.json @@ -1,9 +1,10 @@ { "files": [ { "path": "./dist/ui.browser.js", "maxSize": "19.5KB" }, + { "path": "./dist/ui.legacy.browser.js", "maxSize": "54KB" }, { "path": "./dist/framework*.js", "maxSize": "44KB" }, - { "path": "./dist/vendors*.js", "maxSize": "69KB" }, - { "path": "./dist/ui-common*.js", "maxSize": "123KB" }, + { "path": "./dist/vendors*.js", "maxSize": "73KB" }, + { "path": "./dist/ui-common*.js", "maxSize": "128KB" }, { "path": "./dist/signin*.js", "maxSize": "16KB" }, { "path": "./dist/signup*.js", "maxSize": "11KB" }, { "path": "./dist/userprofile*.js", "maxSize": "16KB" }, @@ -31,6 +32,6 @@ { "path": "./dist/op-plans-page*.js", "maxSize": "3KB" }, { "path": "./dist/statement-page*.js", "maxSize": "5KB" }, { "path": "./dist/payment-attempt-page*.js", "maxSize": "4KB" }, - { "path": "./dist/web3-solana-wallet-buttons*.js", "maxSize": "78KB" } + { "path": "./dist/web3-solana-wallet-buttons*.js", "maxSize": "79KB" } ] } diff --git a/packages/ui/package.json b/packages/ui/package.json index 6b98e94d94b..d65256cf3e8 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -78,7 +78,9 @@ "@solana/wallet-adapter-base": "catalog:module-manager", "@solana/wallet-adapter-react": "catalog:module-manager", "@solana/wallet-standard": "catalog:module-manager", + "@swc/helpers": "catalog:repo", "copy-to-clipboard": "3.3.3", + "core-js": "catalog:repo", "csstype": "3.1.3", "dequal": "2.0.3", "input-otp": "1.4.2", @@ -106,5 +108,6 @@ }, "publishConfig": { "access": "public" - } + }, + "browserslistLegacy": "Chrome > 73, Firefox > 66, Safari > 12, iOS > 12, Edge > 18, Opera > 58" } diff --git a/packages/ui/rspack.config.js b/packages/ui/rspack.config.js index 0102cfa6987..a725da7c340 100644 --- a/packages/ui/rspack.config.js +++ b/packages/ui/rspack.config.js @@ -3,10 +3,13 @@ import rspack from '@rspack/core'; import packageJSON from './package.json' with { type: 'json' }; import path from 'path'; import { fileURLToPath } from 'url'; +import { createRequire } from 'module'; import { merge } from 'webpack-merge'; import ReactRefreshPlugin from '@rspack/plugin-react-refresh'; import { svgLoader, typescriptLoaderProd, typescriptLoaderDev } from '../../scripts/rspack-common.js'; +const require = createRequire(import.meta.url); + const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -15,10 +18,12 @@ const isDevelopment = mode => !isProduction(mode); const variants = { uiBrowser: 'ui.browser', + uiLegacyBrowser: 'ui.legacy.browser', }; const variantToSourceFile = { [variants.uiBrowser]: './src/index.browser.ts', + [variants.uiLegacyBrowser]: './src/index.legacy.browser.ts', }; /** @@ -126,9 +131,12 @@ const entryForVariant = variant => { /** * Common production configuration for chunked browser builds + * @param {object} [options] + * @param {string} [options.targets] - Browserslist targets + * @param {boolean} [options.useCoreJs] - Whether to use core-js polyfills * @returns {import('@rspack/core').Configuration} */ -const commonForProdBrowser = () => { +const commonForProdBrowser = ({ targets = 'last 2 years', useCoreJs = false } = {}) => { return { devtool: false, output: { @@ -138,7 +146,7 @@ const commonForProdBrowser = () => { globalObject: 'globalThis', }, module: { - rules: [svgLoader(), ...typescriptLoaderProd({ targets: 'last 2 years' })], + rules: [svgLoader(), ...typescriptLoaderProd({ targets, useCoreJs })], }, optimization: { minimize: true, @@ -157,13 +165,22 @@ const commonForProdBrowser = () => { }), ], }, + ...(useCoreJs + ? { + resolve: { + alias: { + 'core-js': path.dirname(require.resolve('core-js/package.json')), + }, + }, + } + : {}), }; }; /** - * Production configuration - builds UMD browser variant only + * Production configuration - builds UMD browser variants * @param {'development'|'production'} mode - * @returns {import('@rspack/core').Configuration} + * @returns {import('@rspack/core').Configuration[]} */ const prodConfig = mode => { // Browser bundle with chunks (UMD) @@ -173,7 +190,14 @@ const prodConfig = mode => { commonForProdBrowser(), ); - return uiBrowser; + // Legacy browser bundle with chunks (UMD) for Safari 12 support + const uiLegacyBrowser = merge( + entryForVariant(variants.uiLegacyBrowser), + common({ mode, variant: variants.uiLegacyBrowser }), + commonForProdBrowser({ targets: packageJSON.browserslistLegacy, useCoreJs: true }), + ); + + return [uiBrowser, uiLegacyBrowser]; }; /** diff --git a/packages/ui/src/index.legacy.browser.ts b/packages/ui/src/index.legacy.browser.ts new file mode 100644 index 00000000000..15e5aa11f00 --- /dev/null +++ b/packages/ui/src/index.legacy.browser.ts @@ -0,0 +1,15 @@ +// It's crucial this is the first import, +// otherwise chunk loading will not work +// eslint-disable-next-line +import './utils/setWebpackChunkPublicPath'; + +import { ClerkUi } from './ClerkUi'; + +if (!window.__internal_ClerkUiCtor) { + window.__internal_ClerkUiCtor = ClerkUi; +} + +// Hot module replacement for development +if (module.hot) { + module.hot.accept(); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 428a20b31a9..4755c33c29d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,12 @@ catalogs: specifier: 18.3.7 version: 18.3.7 repo: + '@swc/helpers': + specifier: 0.5.17 + version: 0.5.17 + core-js: + specifier: 3.47.0 + version: 3.47.0 tsdown: specifier: 0.15.7 version: 0.15.7 @@ -472,7 +478,7 @@ importers: specifier: 5.6.0 version: 5.6.0 '@swc/helpers': - specifier: ^0.5.17 + specifier: catalog:repo version: 0.5.17 '@tanstack/query-core': specifier: 5.87.4 @@ -493,8 +499,8 @@ importers: specifier: 1.3.0 version: 1.3.0 core-js: - specifier: 3.41.0 - version: 3.41.0 + specifier: catalog:repo + version: 3.47.0 crypto-js: specifier: ^4.2.0 version: 4.2.0 @@ -948,9 +954,15 @@ importers: '@solana/wallet-standard': specifier: catalog:module-manager version: 1.1.4(@solana/wallet-adapter-base@0.9.27(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)))(@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10))(bs58@6.0.0)(react@18.3.1) + '@swc/helpers': + specifier: catalog:repo + version: 0.5.17 copy-to-clipboard: specifier: 3.3.3 version: 3.3.3 + core-js: + specifier: catalog:repo + version: 3.47.0 csstype: specifier: 3.1.3 version: 3.1.3 @@ -7170,8 +7182,8 @@ packages: core-js-compat@3.46.0: resolution: {integrity: sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==} - core-js@3.41.0: - resolution: {integrity: sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA==} + core-js@3.47.0: + resolution: {integrity: sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==} core-util-is@1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} @@ -11205,7 +11217,6 @@ packages: next@15.2.8: resolution: {integrity: sha512-pe2trLKZTdaCuvNER0S9Wp+SP2APf7SfFmyUP9/w1SFA2UqmW0u+IsxCKkiky3n6um7mryaQIlgiDnKrf1ZwIw==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} - deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details. hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 @@ -23259,7 +23270,7 @@ snapshots: dependencies: browserslist: 4.27.0 - core-js@3.41.0: {} + core-js@3.47.0: {} core-util-is@1.0.2: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 8e3e27f7ebc..bf4d9ac6f6e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,13 +11,15 @@ catalogs: react: 18.3.1 react-dom: 18.3.1 repo: - tslib: 2.8.1 + '@swc/helpers': 0.5.17 + core-js: 3.47.0 + rolldown: 1.0.0-beta.47 tsdown: 0.15.7 + tslib: 2.8.1 tsup: 8.5.0 typescript: 5.8.3 - zx: 8.8.5 - rolldown: 1.0.0-beta.47 vue: 3.5.24 + zx: 8.8.5 module-manager: '@base-org/account': 2.0.1 '@coinbase/wallet-sdk': 4.3.0