diff --git a/biome.json b/biome.json index 1848d1d2da4e..09a394426455 100644 --- a/biome.json +++ b/biome.json @@ -16,7 +16,8 @@ "packages/generator/sandpack-react/src/templates/**", "tests/integration/swc/fixtures/minify-css/src/bootstrap.css", "tests/integration/swc/fixtures/config-function/src/bootstrap.css", - "packages/runtime/plugin-runtime/static/**" + "packages/runtime/plugin-runtime/static/**", + "tests/integration/i18n/mf-consumer/@mf-types/**" ] }, "css": { @@ -113,7 +114,8 @@ "tests/integration/module/plugins/vue/**/*", "packages/module/plugin-module-node-polyfill/src/globals.js", "packages/runtime/plugin-runtime/static/**", - "packages/cli/flight-server-transform-plugin/tests/fixture/**/*" + "packages/cli/flight-server-transform-plugin/tests/fixture/**/*", + "**/@mf-types/**" ] } } diff --git a/packages/cli/builder/src/shared/parseCommonConfig.ts b/packages/cli/builder/src/shared/parseCommonConfig.ts index 288783de0b43..a399ef59d1aa 100644 --- a/packages/cli/builder/src/shared/parseCommonConfig.ts +++ b/packages/cli/builder/src/shared/parseCommonConfig.ts @@ -70,6 +70,7 @@ export async function parseCommonConfig( html: { outputStructure, appIcon, ...htmlConfig } = {}, source: { alias, globalVars, transformImport, ...sourceConfig } = {}, dev = {}, + server = {}, security: { checkSyntax, sri, ...securityConfig } = {}, tools: { devServer, @@ -188,7 +189,7 @@ export async function parseCommonConfig( const { rsbuildDev, rsbuildServer } = transformToRsbuildServerOptions( dev || {}, devServer || {}, - builderConfig.server, + server || {}, ); rsbuildConfig.server = removeUndefinedKey(rsbuildServer); diff --git a/packages/runtime/plugin-i18n/src/cli/index.ts b/packages/runtime/plugin-i18n/src/cli/index.ts index 48ab8bd64ea2..f88f4342ee0d 100644 --- a/packages/runtime/plugin-i18n/src/cli/index.ts +++ b/packages/runtime/plugin-i18n/src/cli/index.ts @@ -13,6 +13,15 @@ export interface I18nPluginOptions { localeDetection?: LocaleDetectionOptions; backend?: BackendOptions; transformRuntimeConfig?: TransformRuntimeConfigFn; + customPlugin?: { + runtime?: { + name?: string; + path?: string; + }; + server?: { + name?: string; + }; + }; [key: string]: any; } @@ -21,8 +30,13 @@ export const i18nPlugin = ( ): CliPlugin => ({ name: '@modern-js/plugin-i18n', setup: api => { - const { localeDetection, backend, transformRuntimeConfig, ...restOptions } = - options; + const { + localeDetection, + backend, + transformRuntimeConfig, + customPlugin, + ...restOptions + } = options; api._internalRuntimePlugins(({ entrypoint, plugins }) => { const localeDetectionOptions = localeDetection ? getLocaleDetectionOptions(entrypoint.entryName, localeDetection) @@ -50,8 +64,8 @@ export const i18nPlugin = ( }; plugins.push({ - name: 'i18n', - path: `@${metaName}/plugin-i18n/runtime`, + name: customPlugin?.runtime?.name || 'i18n', + path: customPlugin?.runtime?.path || `@${metaName}/plugin-i18n/runtime`, config, }); return { @@ -88,7 +102,7 @@ export const i18nPlugin = ( }); plugins.push({ - name: `@${metaName}/plugin-i18n/server`, + name: customPlugin?.server?.name || `@${metaName}/plugin-i18n/server`, options: { localeDetection, staticRoutePrefixes, diff --git a/packages/runtime/plugin-i18n/src/runtime/context.tsx b/packages/runtime/plugin-i18n/src/runtime/context.tsx index a4d33a27c7af..6f5ad961a12d 100644 --- a/packages/runtime/plugin-i18n/src/runtime/context.tsx +++ b/packages/runtime/plugin-i18n/src/runtime/context.tsx @@ -11,6 +11,7 @@ export interface ModernI18nContextValue { entryName?: string; languages?: string[]; localePathRedirect?: boolean; + ignoreRedirectRoutes?: string[] | ((pathname: string) => boolean); // Callback to update language in context updateLanguage?: (newLang: string) => void; } @@ -41,6 +42,44 @@ export interface UseModernI18nReturn { isLanguageSupported: (lang: string) => boolean; } +/** + * Check if the given pathname should ignore automatic locale redirect + */ +const shouldIgnoreRedirect = ( + pathname: string, + languages: string[], + ignoreRedirectRoutes?: string[] | ((pathname: string) => boolean), +): boolean => { + if (!ignoreRedirectRoutes) { + return false; + } + + // Remove language prefix if present (e.g., /en/api -> /api) + const segments = pathname.split('/').filter(Boolean); + let pathWithoutLang = pathname; + if (segments.length > 0 && languages.includes(segments[0])) { + // Remove language prefix + pathWithoutLang = `/${segments.slice(1).join('/')}`; + } + + // Normalize path (ensure it starts with /) + const normalizedPath = pathWithoutLang.startsWith('/') + ? pathWithoutLang + : `/${pathWithoutLang}`; + + if (typeof ignoreRedirectRoutes === 'function') { + return ignoreRedirectRoutes(normalizedPath); + } + + // Check if pathname matches any of the ignore patterns + return ignoreRedirectRoutes.some(pattern => { + // Support both exact match and prefix match + return ( + normalizedPath === pattern || normalizedPath.startsWith(`${pattern}/`) + ); + }); +}; + // Safe hook wrapper to handle cases where router context is not available const useRouterHooks = () => { try { @@ -91,6 +130,7 @@ export const useModernI18n = (): UseModernI18nReturn => { i18nInstance, languages, localePathRedirect, + ignoreRedirectRoutes, updateLanguage, } = context; @@ -143,33 +183,55 @@ export const useModernI18n = (): UseModernI18nReturn => { const entryPath = getEntryPath(); const relativePath = currentPath.replace(entryPath, ''); - // Build new path with updated language - const newPath = buildLocalizedUrl( - relativePath, - newLang, - languages || [], - ); - const newUrl = entryPath + newPath + location.search + location.hash; + // Check if this route should ignore automatic redirect + if ( + !shouldIgnoreRedirect( + relativePath, + languages || [], + ignoreRedirectRoutes, + ) + ) { + // Build new path with updated language + const newPath = buildLocalizedUrl( + relativePath, + newLang, + languages || [], + ); + const newUrl = + entryPath + newPath + location.search + location.hash; - // Navigate to new URL - navigate(newUrl, { replace: true }); + // Navigate to new URL + await navigate(newUrl, { replace: true }); + } } else if (localePathRedirect && isBrowser() && !hasRouter) { // Fallback: use window.history API when router is not available const currentPath = window.location.pathname; const entryPath = getEntryPath(); const relativePath = currentPath.replace(entryPath, ''); - // Build new path with updated language - const newPath = buildLocalizedUrl( - relativePath, - newLang, - languages || [], - ); - const newUrl = - entryPath + newPath + window.location.search + window.location.hash; - - // Use history API to navigate without page reload - window.history.pushState(null, '', newUrl); + // Check if this route should ignore automatic redirect + if ( + !shouldIgnoreRedirect( + relativePath, + languages || [], + ignoreRedirectRoutes, + ) + ) { + // Build new path with updated language + const newPath = buildLocalizedUrl( + relativePath, + newLang, + languages || [], + ); + const newUrl = + entryPath + + newPath + + window.location.search + + window.location.hash; + + // Use history API to navigate without page reload + window.history.pushState(null, '', newUrl); + } } // Update language state after URL update @@ -185,6 +247,7 @@ export const useModernI18n = (): UseModernI18nReturn => { i18nInstance, updateLanguage, localePathRedirect, + ignoreRedirectRoutes, languages, hasRouter, navigate, diff --git a/packages/runtime/plugin-i18n/src/runtime/index.tsx b/packages/runtime/plugin-i18n/src/runtime/index.tsx index 87edf838cd90..939017da1124 100644 --- a/packages/runtime/plugin-i18n/src/runtime/index.tsx +++ b/packages/runtime/plugin-i18n/src/runtime/index.tsx @@ -39,6 +39,7 @@ export interface I18nPluginOptions { i18nInstance?: I18nInstance; changeLanguage?: (lang: string) => void; initOptions?: I18nInitOptions; + [key: string]: any; } const getPathname = (context: TRuntimeContext) => { @@ -64,6 +65,7 @@ export const i18nPlugin = (options: I18nPluginOptions): RuntimePlugin => ({ languages = [], fallbackLanguage = 'en', detection, + ignoreRedirectRoutes, } = localeDetection || {}; const { enabled: backendEnabled = false } = backend || {}; let I18nextProvider: React.FunctionComponent | null; @@ -184,6 +186,7 @@ export const i18nPlugin = (options: I18nPluginOptions): RuntimePlugin => ({ entryName, languages, localePathRedirect, + ignoreRedirectRoutes, updateLanguage: setLang, }; diff --git a/packages/runtime/plugin-i18n/src/server/index.ts b/packages/runtime/plugin-i18n/src/server/index.ts index 05eaa875c0b8..266d6dd9965f 100644 --- a/packages/runtime/plugin-i18n/src/server/index.ts +++ b/packages/runtime/plugin-i18n/src/server/index.ts @@ -78,6 +78,42 @@ const convertToHonoLanguageDetectorOptions = ( }; }; +/** + * Check if the given pathname should ignore automatic locale redirect + */ +const shouldIgnoreRedirect = ( + pathname: string, + urlPath: string, + ignoreRedirectRoutes?: string[] | ((pathname: string) => boolean), +): boolean => { + if (!ignoreRedirectRoutes) { + return false; + } + + // Remove urlPath prefix to get remaining path for matching + const basePath = urlPath.replace('/*', ''); + const remainingPath = pathname.startsWith(basePath) + ? pathname.slice(basePath.length) + : pathname; + + // Normalize path (ensure it starts with /) + const normalizedPath = remainingPath.startsWith('/') + ? remainingPath + : `/${remainingPath}`; + + if (typeof ignoreRedirectRoutes === 'function') { + return ignoreRedirectRoutes(normalizedPath); + } + + // Check if pathname matches any of the ignore patterns + return ignoreRedirectRoutes.some(pattern => { + // Support both exact match and prefix match + return ( + normalizedPath === pattern || normalizedPath.startsWith(`${pattern}/`) + ); + }); +}; + /** * Check if the given pathname is a static resource request * This includes: @@ -206,6 +242,7 @@ export const i18nServerPlugin = (options: I18nPluginOptions): ServerPlugin => ({ languages = [], fallbackLanguage = 'en', detection, + ignoreRedirectRoutes, } = getLocaleDetectionOptions(entryName, options.localeDetection); const staticRoutePrefixes = options.staticRoutePrefixes; const originUrlPath = route.urlPath; @@ -262,6 +299,13 @@ export const i18nServerPlugin = (options: I18nPluginOptions): ServerPlugin => ({ return await next(); } + // Check if this route should ignore automatic redirect + if ( + shouldIgnoreRedirect(pathname, urlPath, ignoreRedirectRoutes) + ) { + return await next(); + } + const language = getLanguageFromPath(c.req, urlPath, languages); if (!language) { // Get detected language from languageDetector middleware diff --git a/packages/runtime/plugin-i18n/src/shared/type.ts b/packages/runtime/plugin-i18n/src/shared/type.ts index 0d2f9b977555..08128659af83 100644 --- a/packages/runtime/plugin-i18n/src/shared/type.ts +++ b/packages/runtime/plugin-i18n/src/shared/type.ts @@ -9,6 +9,7 @@ export interface BaseLocaleDetectionOptions { languages?: string[]; fallbackLanguage?: string; detection?: LanguageDetectorOptions; + ignoreRedirectRoutes?: string[] | ((pathname: string) => boolean); } export interface LocaleDetectionOptions extends BaseLocaleDetectionOptions { diff --git a/packages/runtime/plugin-runtime/src/router/runtime/plugin.tsx b/packages/runtime/plugin-runtime/src/router/runtime/plugin.tsx index 7a506ad0fa09..07be71095e24 100644 --- a/packages/runtime/plugin-runtime/src/router/runtime/plugin.tsx +++ b/packages/runtime/plugin-runtime/src/router/runtime/plugin.tsx @@ -147,8 +147,11 @@ export const routerPlugin = ( return match || '/'; }; + // Cache router instance in closure to avoid recreating on parent re-render + let cachedRouter: any = null; + const RouterWrapper = (props: any) => { - const { router, routes } = useRouterCreation( + const routerResult = useRouterCreation( { ...props, rscPayload: props?.rscPayload, @@ -162,6 +165,18 @@ export const routerPlugin = ( }, ); + // Only cache router instance, routes are always from routerResult + // rscPayload is stable after first render, so we only create router once + const router = useMemo(() => { + if (cachedRouter) { + return cachedRouter; + } + + cachedRouter = routerResult.router; + return cachedRouter; + }, []); + const { routes } = routerResult; + useEffect(() => { routesContainer.current = routes; }, [routes]); diff --git a/packages/server/server/src/dev.ts b/packages/server/server/src/dev.ts index 729dd4b92d88..b27147419350 100644 --- a/packages/server/server/src/dev.ts +++ b/packages/server/server/src/dev.ts @@ -110,7 +110,6 @@ export const devPlugin = ( middlewares.push({ name: 'mock-dev', - handler: mockMiddleware, }); diff --git a/packages/toolkit/utils/src/universal/constants.ts b/packages/toolkit/utils/src/universal/constants.ts index 43a98b35f179..e637137d15bd 100644 --- a/packages/toolkit/utils/src/universal/constants.ts +++ b/packages/toolkit/utils/src/universal/constants.ts @@ -8,11 +8,6 @@ export const ROUTE_MANIFEST = `_MODERNJS_ROUTE_MANIFEST`; */ export const ROUTE_MODULES = `_routeModules`; -/** - * hmr socket connect path - */ -export const HMR_SOCK_PATH = '/webpack-hmr'; - /** * html placeholder */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f05b633dcb45..0333f909105e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3796,6 +3796,108 @@ importers: specifier: workspace:* version: link:../../../../packages/cli/plugin-ssg + tests/integration/i18n/mf-app-provider: + dependencies: + '@modern-js/plugin-i18n': + specifier: workspace:* + version: link:../../../../packages/runtime/plugin-i18n + '@modern-js/runtime': + specifier: workspace:* + version: link:../../../../packages/runtime/plugin-runtime + '@module-federation/bridge-react': + specifier: 0.0.0-feat-modern-3-0-20251120074204 + version: 0.0.0-feat-modern-3-0-20251120074204(react-dom@19.2.0(react@19.2.0))(react-router-dom@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-router@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) + '@module-federation/modern-js': + specifier: 0.0.0-feat-modern-3-0-20251120074204 + version: 0.0.0-feat-modern-3-0-20251120074204(@rsbuild/core@1.6.7)(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react-router-dom@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-router@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5)) + i18next: + specifier: 25.6.2 + version: 25.6.2(typescript@5.6.3) + react: + specifier: ^19.2.0 + version: 19.2.0 + react-dom: + specifier: ^19.2.0 + version: 19.2.0(react@19.2.0) + react-i18next: + specifier: 15.7.4 + version: 15.7.4(i18next@25.6.2(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + devDependencies: + '@modern-js/app-tools': + specifier: workspace:* + version: link:../../../../packages/solutions/app-tools + '@modern-js/plugin-ssg': + specifier: workspace:* + version: link:../../../../packages/cli/plugin-ssg + + tests/integration/i18n/mf-consumer: + dependencies: + '@modern-js/plugin-i18n': + specifier: workspace:* + version: link:../../../../packages/runtime/plugin-i18n + '@modern-js/runtime': + specifier: workspace:* + version: link:../../../../packages/runtime/plugin-runtime + '@module-federation/bridge-react': + specifier: 0.0.0-feat-modern-3-0-20251120074204 + version: 0.0.0-feat-modern-3-0-20251120074204(react-dom@19.2.0(react@19.2.0))(react-router-dom@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-router@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) + '@module-federation/modern-js': + specifier: 0.0.0-feat-modern-3-0-20251120074204 + version: 0.0.0-feat-modern-3-0-20251120074204(@rsbuild/core@1.6.7)(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react-router-dom@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-router@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5)) + '@module-federation/runtime': + specifier: 0.0.0-feat-modern-3-0-20251120074204 + version: 0.0.0-feat-modern-3-0-20251120074204 + i18next: + specifier: 25.6.2 + version: 25.6.2(typescript@5.6.3) + react: + specifier: ^19.2.0 + version: 19.2.0 + react-dom: + specifier: ^19.2.0 + version: 19.2.0(react@19.2.0) + react-i18next: + specifier: 15.7.4 + version: 15.7.4(i18next@25.6.2(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + devDependencies: + '@modern-js/app-tools': + specifier: workspace:* + version: link:../../../../packages/solutions/app-tools + '@modern-js/plugin-ssg': + specifier: workspace:* + version: link:../../../../packages/cli/plugin-ssg + + tests/integration/i18n/mf-provider: + dependencies: + '@modern-js/plugin-i18n': + specifier: workspace:* + version: link:../../../../packages/runtime/plugin-i18n + '@modern-js/runtime': + specifier: workspace:* + version: link:../../../../packages/runtime/plugin-runtime + '@module-federation/modern-js': + specifier: 0.0.0-feat-modern-3-0-20251120074204 + version: 0.0.0-feat-modern-3-0-20251120074204(@rsbuild/core@1.6.7)(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react-router-dom@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-router@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5)) + i18next: + specifier: 25.6.2 + version: 25.6.2(typescript@5.6.3) + react: + specifier: ^19.2.0 + version: 19.2.0 + react-dom: + specifier: ^19.2.0 + version: 19.2.0(react@19.2.0) + react-i18next: + specifier: 15.7.4 + version: 15.7.4(i18next@25.6.2(typescript@5.6.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3) + devDependencies: + '@modern-js/app-tools': + specifier: workspace:* + version: link:../../../../packages/solutions/app-tools + '@modern-js/plugin-ssg': + specifier: workspace:* + version: link:../../../../packages/cli/plugin-ssg + tests/integration/i18n/routes-csr: dependencies: '@modern-js/plugin-i18n': @@ -4588,7 +4690,7 @@ importers: version: link:../components antd: specifier: ^5.28.1 - version: 5.28.1(date-fns@2.30.0)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 5.28.1(date-fns@2.30.0)(luxon@3.7.2)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: ^19.2.0 version: 19.2.0 @@ -7532,6 +7634,9 @@ packages: typescript: optional: true + '@modern-js/node-bundle-require@0.0.0-canary-20251119023553': + resolution: {integrity: sha512-LCVN5tKl2W+MHTGPjtsMsqoctbQXcdMp0CHhKcE+fqbbGqu9b7k7rBjHfg+6RM0UkZjZxx6k74aH+g7GxBsiFA==} + '@modern-js/node-bundle-require@2.68.20': resolution: {integrity: sha512-AtDY69NBKFiJ87UKVhuDAVwvjxJT1MMshLaUM0BEtvHuXl6Rmaiy1wKWSVIKwM1H2H8lyUwW0S0vJBvAG9Mp1w==} @@ -7611,27 +7716,179 @@ packages: '@modern-js/types@2.68.20': resolution: {integrity: sha512-X3xtfRKKj4aVXYVBTkopkAhisFCYbn6YLh5Nvv1zCvoD5qF+ZA/CY+l4fRMYJ8FlWaiDXDpa+MPxwlvp7JJLlw==} + '@modern-js/utils@0.0.0-canary-20251119023553': + resolution: {integrity: sha512-XjnFzp8/++26oMR8jfXiULWpdwC0CCKK8efe3edRrEC2srk5Yp+uX44edUSkWsvQ8j03ys+mw0hq4AOqFD9uPQ==} + peerDependencies: + react: ^19.2.0 + react-dom: ^19.2.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + '@modern-js/utils@2.60.3': resolution: {integrity: sha512-g9kxWsYZ71MZPXMEf2ltDP229WjGIChNB95fjmcvtWRoW9grhINdQJ0/tO+jEaHZiDDQEWuPJlqqUrXWcZB0nQ==} '@modern-js/utils@2.68.20': resolution: {integrity: sha512-OA5h2GN7d4IwK5BLmKxEQAXnaEzpKVJayvHPyDIEJt+eiJRixhakNgJVsHcrldrLVAlX0rv/t4eCl83tUSocPA==} + '@module-federation/bridge-react-webpack-plugin@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-8r6jLxBW35mVs1j1vHjhHctsEOv8emPE/GezQiGokOrGHB22mEDMX9hMs9ZZA6VsSB36NL79k7lWT8jxVyEvgQ==} + + '@module-federation/bridge-react@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-epNyHjtNON9thARRXCg3oc16hJsGg92ApCYL/0g0Gv0BCA9hmlmSD72LnD/tIpE3JDIkMNV054JNRQSVvOyjvQ==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + react-router: ^6 || ^7 + react-router-dom: ^4 || ^5 || ^6 || ^7 + peerDependenciesMeta: + react-router: + optional: true + react-router-dom: + optional: true + + '@module-federation/bridge-shared@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-Vtyw+ixcB4Cy90GdlXoT/s5Mvn1MqTn59O+Ap2tFJ+yH8+9xJi3s9O7g9Uj8fm7QbcxheJ1KNa+K9iYuikX90w==} + + '@module-federation/cli@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-78mzRfV4oSiwdMK4M/F5zK2bo+/Tm3lFLQiza2K8sEWBWNkREILk9ERxKbNw6jgbwBzY/Xl26Rg97Wp0wPFQMQ==} + engines: {node: '>=16.0.0'} + hasBin: true + + '@module-federation/data-prefetch@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-knLlwi93KEK9S/VDjZO8UbJxLp6s6rpnl8IXTJ5ELhljD5s6gN1VqtfOXxYYChB2DaUu4EMf/rCApcDoTekuCg==} + peerDependencies: + react: '>=16.9.0' + react-dom: '>=16.9.0' + + '@module-federation/dts-plugin@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-kKaf7SC2/4Ls3op/lgO4eYhXtrnZn3WURdQJKk71y30r68ZKHm+Kzs50vsnlqe8IYxEx+nN9gLn+/tyq4eEBUg==} + peerDependencies: + typescript: ^4.9.0 || ^5.0.0 + vue-tsc: '>=1.0.24' + peerDependenciesMeta: + vue-tsc: + optional: true + + '@module-federation/enhanced@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-s0nQ7295n30dIQwhBHjUEcPvdgjl5e82r7aH9oOe8g/XUePI3blsedVVinrCGaQEW1y5MzrpQY6OBQwsmcjYrQ==} + hasBin: true + peerDependencies: + typescript: ^4.9.0 || ^5.0.0 + vue-tsc: '>=1.0.24' + webpack: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + vue-tsc: + optional: true + webpack: + optional: true + + '@module-federation/error-codes@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-h3+dS/2/Lpp+P+AxnhTVk2hwvx3R4CPewiF96G0GfR3fJT7gXs7A9As++2c+Zcqy0eejRBd08pcBBEO/tnCXxw==} + '@module-federation/error-codes@0.21.4': resolution: {integrity: sha512-ClpL5MereWNXh+EgDjz7w4RrC1JlisQTvXDa1gLxpviHafzNDfdViVmuhi9xXVuj+EYo8KU70Y999KHhk9424Q==} + '@module-federation/inject-external-runtime-core-plugin@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-EwxEnSKm5vegoBXf4QOKdvhbtHhSMAGK0KEIe8Dn1s3prlAabXVYICrhZmkLx7rm7KBZJeQKcSgeJR9jdX+fmQ==} + peerDependencies: + '@module-federation/runtime-tools': 0.0.0-feat-modern-3-0-20251120074204 + + '@module-federation/managers@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-prbeXjTLgYNPF9p0s/XOoQcWE3Ak4AySxqV+iAu2AQs8RIVHXFqZQLXtxCGLzW9K/3KpMnJILIge8vxV18KN3A==} + + '@module-federation/manifest@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-7S/PikFR7sy3yh5PUZELNsupujsLXNheADU1O1T73lCKRUSlJEHNsakCAOrf6v/znTYC8BIf3pkrr6xauDn5zg==} + + '@module-federation/modern-js@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-RbS0GymeY63c9rgqESPn2iTa+YHAps5cgUlKWA67IvFTHOpluKtdOsYdCJOjyKQgcPmO6jjBxpZElA+KZPWg5w==} + peerDependencies: + react: '>=17' + react-dom: '>=17' + react-router: ^7 + react-router-dom: ^4 || ^5 || ^6 || ^7 + typescript: ^4.9.0 || ^5.0.0 + vue-tsc: ^1.0.24 + peerDependenciesMeta: + react-router: + optional: true + react-router-dom: + optional: true + typescript: + optional: true + vue-tsc: + optional: true + + '@module-federation/node@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-0b2wylnLixAJHhEYRAwbU9OYa/hvWou7SfpMYco08ik4dZ82gn+KscdIUXLti5iFUDBQq/oYcEq4ynTztT48fg==} + peerDependencies: + next: '*' + react: ^16||^17||^18||^19 + react-dom: ^16||^17||^18||^19 + webpack: ^5.40.0 + peerDependenciesMeta: + next: + optional: true + react: + optional: true + react-dom: + optional: true + + '@module-federation/rsbuild-plugin@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-XZsYL/PvmRgxjxFgEEoi+gtTOjzImLX/dlZEOzbxmwg4DLXoaUYbKNshF3+zNaC2K2VWWnHFCs+aws1Dw3pjzw==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@rsbuild/core': ^1.6.7 + peerDependenciesMeta: + '@rsbuild/core': + optional: true + + '@module-federation/rspack@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-K7X16L6Fw2buqTuCANGXTyGMxfOFYmBfgO6o0DNT/TB2ZFoJArsPgnCAUk4X7bNshSKT8+Fam9wsdJNU0dl7Sw==} + peerDependencies: + '@rspack/core': '>=0.7' + typescript: ^4.9.0 || ^5.0.0 + vue-tsc: '>=1.0.24' + peerDependenciesMeta: + typescript: + optional: true + vue-tsc: + optional: true + + '@module-federation/runtime-core@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-MfWQE41lutPqbcY9pPk2CSLMU2mT/kXlGNQirm4Y6QhKB/0KRWQ+7FD9yCHIeIqM0fbLJVtA/RDihw/kS2qRyQ==} + '@module-federation/runtime-core@0.21.4': resolution: {integrity: sha512-SGpmoOLGNxZofpTOk6Lxb2ewaoz5wMi93AFYuuJB04HTVcngEK+baNeUZ2D/xewrqNIJoMY6f5maUjVfIIBPUA==} + '@module-federation/runtime-tools@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-RTD9IAV1N9+LmjLzm2RtyrPfFeix0FuKRmJVPvAQGllfjLImprqDg6Dq44Kk0x1FMG0cvglkZrG2lugBu7tiGQ==} + '@module-federation/runtime-tools@0.21.4': resolution: {integrity: sha512-RzFKaL0DIjSmkn76KZRfzfB6dD07cvID84950jlNQgdyoQFUGkqD80L6rIpVCJTY/R7LzR3aQjHnoqmq4JPo3w==} + '@module-federation/runtime@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-LVoGjJQyN+UIoc7hdrKNSzJEpQ9xEFjYytnkKiXUAPrIwXw8zLNkktKJVyJI0hb3aO1Gy0/Su1L6qTWZ4pq5kw==} + '@module-federation/runtime@0.21.4': resolution: {integrity: sha512-wgvGqryurVEvkicufJmTG0ZehynCeNLklv8kIk5BLIsWYSddZAE+xe4xov1kgH5fIJQAoQNkRauFFjVNlHoAkA==} + '@module-federation/sdk@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-Q4ZPCuxncjY6OFF40+GxWJ0bHwwLhO2JFx7VveCgPogsaL99DJmr/AvTxTCP3ooWSe3hrFEGdG07w40l0ZLh7A==} + '@module-federation/sdk@0.21.4': resolution: {integrity: sha512-tzvhOh/oAfX++6zCDDxuvioHY4Jurf8vcfoCbKFxusjmyKr32GPbwFDazUP+OPhYCc3dvaa9oWU6X/qpUBLfJw==} + '@module-federation/third-party-dts-extractor@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-FFH0pL+1rSKBTkofh32WRU7ta9MbyLU4f3zwC5dV7T1ft251zC1Wx0R7rMb123vReG+9vJWRMzhG0Eqh4x3LTA==} + + '@module-federation/webpack-bundler-runtime@0.0.0-feat-modern-3-0-20251120074204': + resolution: {integrity: sha512-ADgapHbMfyGnfM8DuFJjgGtGu5xEXIiGXz+igel0cMuHcSwzvLL4WW0Z3N99LvmJjObt4Lebpgidw8jyjmwxmg==} + '@module-federation/webpack-bundler-runtime@0.21.4': resolution: {integrity: sha512-dusmR3uPnQh9u9ChQo3M+GLOuGFthfvnh7WitF/a1eoeTfRmXqnMFsXtZCUK+f/uXf+64874Zj/bhAgbBcVHZA==} @@ -9088,6 +9345,9 @@ packages: '@types/rimraf@2.0.5': resolution: {integrity: sha512-YyP+VfeaqAyFmXoTh3HChxOQMyjByRMsHU7kc5KOJkSlXudhMhQIALbYV7rHh/l8d2lX3VUQzprrcAgWdRuU8g==} + '@types/semver@7.5.8': + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + '@types/semver@7.7.1': resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} @@ -9410,6 +9670,10 @@ packages: resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} engines: {node: '>= 10.0.0'} + adm-zip@0.5.16: + resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} + engines: {node: '>=12.0'} + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -9570,6 +9834,10 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + audio-context-polyfill@1.0.0: resolution: {integrity: sha512-Ex1jZc8e3AIiOBm8Tn0oS4yZ8aT5VCLygaov+fxJ4ymgUB2GPqW5DtQ8NBpR2dfvSR6RjWvMU8+nDwIE/he49w==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. @@ -9761,6 +10029,11 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + btoa@1.2.1: + resolution: {integrity: sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==} + engines: {node: '>= 0.4.0'} + hasBin: true + buffer-builder@0.2.0: resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} @@ -9869,6 +10142,10 @@ packages: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} + chalk@3.0.0: + resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} + engines: {node: '>=8'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -10271,6 +10548,10 @@ packages: crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + cron-parser@4.9.0: + resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==} + engines: {node: '>=12.0.0'} + cross-env@7.0.3: resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} @@ -10599,6 +10880,10 @@ packages: resolution: {integrity: sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==} engines: {node: '>= 6'} + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + data-uri-to-buffer@6.0.2: resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} engines: {node: '>= 14'} @@ -10611,6 +10896,10 @@ packages: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} + date-format@4.0.14: + resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==} + engines: {node: '>=4.0'} + dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} @@ -11320,6 +11609,10 @@ packages: resolution: {integrity: sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==} engines: {node: '>=0.10.0'} + expand-tilde@2.0.2: + resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} + engines: {node: '>=0.10.0'} + expect-puppeteer@11.0.0: resolution: {integrity: sha512-fgxsbOD+HqwOCMitYqEDzRoJM2fxKbCKPYfUoukK+qdZm/nC+cTOI74Au2MfmMZmF/5CgQGO4+1Ywq2GgD8zCQ==} engines: {node: '>=18'} @@ -11429,6 +11722,10 @@ packages: fengari@0.1.4: resolution: {integrity: sha512-6ujqUuiIYmcgkGz8MGAdERU57EIluGGPSUgGPTsco657EHa+srq0S3/YUl/r9kx1+D+d4rGfYObd+m8K22gB1g==} + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} @@ -11474,10 +11771,18 @@ packages: resolution: {integrity: sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==} engines: {node: '>=0.10.0'} + find-file-up@2.0.1: + resolution: {integrity: sha512-qVdaUhYO39zmh28/JLQM5CoYN9byEOKEH4qfa8K1eNV17W0UUMJ9WgbR/hHFH+t5rcl+6RTb5UC7ck/I+uRkpQ==} + engines: {node: '>=8'} + find-pkg@0.1.2: resolution: {integrity: sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==} engines: {node: '>=0.10.0'} + find-pkg@2.0.0: + resolution: {integrity: sha512-WgZ+nKbELDa6N3i/9nrHeNznm+lY3z4YfhDDWgW+5P0pdmMj26bxaxU11ookgY3NyP9GC7HvZ9etp0jRFqGEeQ==} + engines: {node: '>=8'} + find-process@1.4.7: resolution: {integrity: sha512-/U4CYp1214Xrp3u3Fqr9yNynUrr5Le4y0SsJh2lMDDSbpwYSz3M2SMWQC+wqcx79cN8PQtHQIL8KnuY9M66fdg==} hasBin: true @@ -11544,6 +11849,10 @@ packages: resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} engines: {node: '>= 6'} + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + formidable@2.1.5: resolution: {integrity: sha512-Oz5Hwvwak/DCaXVVUtPn4oLMLLy1CdclLKO1LFgU7XzDpVMUU5UjlSLpGMocyQNNk8F6IJW9M/YdooSn2MRI+Q==} @@ -11591,6 +11900,10 @@ packages: resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} engines: {node: '>=6 <7 || >=8'} + fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} @@ -11730,10 +12043,18 @@ packages: resolution: {integrity: sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==} engines: {node: '>=0.10.0'} + global-modules@1.0.0: + resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} + engines: {node: '>=0.10.0'} + global-prefix@0.1.5: resolution: {integrity: sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==} engines: {node: '>=0.10.0'} + global-prefix@1.0.2: + resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} + engines: {node: '>=0.10.0'} + globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -12351,6 +12672,11 @@ packages: isomorphic-fetch@3.0.0: resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==} + isomorphic-ws@5.0.0: + resolution: {integrity: sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==} + peerDependencies: + ws: '*' + istanbul-lib-coverage@3.2.0: resolution: {integrity: sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==} engines: {node: '>=8'} @@ -12551,6 +12877,10 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true @@ -12694,6 +13024,10 @@ packages: resolution: {integrity: sha512-zPPuIt+ku1iCpFBRwseMcPYQ1cJL8l60rSmKeOuGfOXyE6YnTBmf2aEFNL2HQGrD0cPcLO/t+v9RTgC+fwEh/g==} engines: {node: ^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4} + koa@3.0.3: + resolution: {integrity: sha512-MeuwbCoN1daWS32/Ni5qkzmrOtQO2qrnfdxDHjrm6s4b59yG4nexAJ0pTEFyzjLp0pBVO80CZp0vW8Ze30Ebow==} + engines: {node: '>= 18'} + kolorist@1.8.0: resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} @@ -12868,6 +13202,9 @@ packages: lodash.camelcase@4.3.0: resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lodash.clonedeepwith@4.5.0: + resolution: {integrity: sha512-QRBRSxhbtsX1nc0baxSkkK5WlVTTm/s48DSukcGcWZwIyI8Zz+lB+kFiELJXtzfH4Aj6kMWQ1VWW4U5uUDgZMA==} + lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} @@ -12940,6 +13277,13 @@ packages: resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + log4js@6.9.1: + resolution: {integrity: sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==} + engines: {node: '>=8.0'} + + long-timeout@0.1.1: + resolution: {integrity: sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -12985,6 +13329,10 @@ packages: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} + luxon@3.7.2: + resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} + engines: {node: '>=12'} + lz-string@1.5.0: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true @@ -13094,6 +13442,10 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + medium-zoom@1.1.0: resolution: {integrity: sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==} @@ -13246,10 +13598,18 @@ packages: resolution: {integrity: sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==} engines: {node: '>= 0.6'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -13423,6 +13783,11 @@ packages: node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + node-emoji@1.11.0: resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} @@ -13438,6 +13803,10 @@ packages: encoding: optional: true + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-forge@1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} @@ -13470,6 +13839,10 @@ packages: node-releases@2.0.26: resolution: {integrity: sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==} + node-schedule@2.1.1: + resolution: {integrity: sha512-OXdegQq03OmXEjt2hZP33W2YPs/E5BcFQks46+G2gAxs4gHOIVD1u7EqlYLYSKsaIpyKCK9Gbk0ta1/gjRSMRQ==} + engines: {node: '>=6'} + nopt@5.0.0: resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} engines: {node: '>=6'} @@ -14477,6 +14850,9 @@ packages: radix3@1.1.2: resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + rambda@9.4.2: + resolution: {integrity: sha512-++euMfxnl7OgaEKwXh9QqThOjMeta2HH001N1v4mYQzBjJBnmXBh2BCK6dZAbICFVXOFUVD3xFG0R3ZPU0mxXw==} + randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} @@ -14724,6 +15100,11 @@ packages: peerDependencies: react: ^19.2.0 + react-error-boundary@4.1.2: + resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} + peerDependencies: + react: '>=16.13.1' + react-fast-compare@3.2.0: resolution: {integrity: sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==} @@ -14991,6 +15372,10 @@ packages: resolution: {integrity: sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==} engines: {node: '>=0.10.0'} + resolve-dir@1.0.1: + resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} + engines: {node: '>=0.10.0'} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -15023,6 +15408,10 @@ packages: engines: {node: '>= 0.4'} hasBin: true + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + responselike@2.0.1: resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} @@ -15313,6 +15702,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + semver@7.7.2: resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} engines: {node: '>=10'} @@ -15477,6 +15871,9 @@ packages: resolution: {integrity: sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + sorted-array-functions@1.3.0: + resolution: {integrity: sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==} + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -15577,6 +15974,10 @@ packages: stream-to-string@1.2.0: resolution: {integrity: sha512-8drZlFIKBHSMdX9GCWv8V9AAWnQcTqw0iAI6/GC7UJ0H0SwKeFKjOoZfGY1tOU00GGU7FYZQoJ/ZCUEoXhD7yQ==} + streamroller@3.1.5: + resolution: {integrity: sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==} + engines: {node: '>=8.0'} + streamx@2.22.0: resolution: {integrity: sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==} @@ -16097,6 +16498,10 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + type@2.7.3: resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} @@ -16606,6 +17011,18 @@ packages: utf-8-validate: optional: true + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.18.3: resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} engines: {node: '>=10.0.0'} @@ -19462,6 +19879,15 @@ snapshots: - debug - supports-color + '@modern-js/node-bundle-require@0.0.0-canary-20251119023553(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@modern-js/utils': 0.0.0-canary-20251119023553(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@swc/helpers': 0.5.17 + esbuild: 0.25.5 + transitivePeerDependencies: + - react + - react-dom + '@modern-js/node-bundle-require@2.68.20': dependencies: '@modern-js/utils': 2.68.20 @@ -19583,6 +20009,16 @@ snapshots: '@modern-js/types@2.68.20': {} + '@modern-js/utils@0.0.0-canary-20251119023553(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@swc/helpers': 0.5.17 + caniuse-lite: 1.0.30001754 + lodash: 4.17.21 + rslog: 1.2.11 + optionalDependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + '@modern-js/utils@2.60.3': dependencies: '@swc/helpers': 0.5.13 @@ -19597,26 +20033,271 @@ snapshots: lodash: 4.17.21 rslog: 1.2.11 + '@module-federation/bridge-react-webpack-plugin@0.0.0-feat-modern-3-0-20251120074204': + dependencies: + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + '@types/semver': 7.5.8 + semver: 7.6.3 + + '@module-federation/bridge-react@0.0.0-feat-modern-3-0-20251120074204(react-dom@19.2.0(react@19.2.0))(react-router-dom@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-router@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)': + dependencies: + '@module-federation/bridge-shared': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + lru-cache: 10.4.3 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-error-boundary: 4.1.2(react@19.2.0) + optionalDependencies: + react-router: 7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react-router-dom: 7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + + '@module-federation/bridge-shared@0.0.0-feat-modern-3-0-20251120074204': {} + + '@module-federation/cli@0.0.0-feat-modern-3-0-20251120074204(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)': + dependencies: + '@module-federation/dts-plugin': 0.0.0-feat-modern-3-0-20251120074204(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + chalk: 3.0.0 + commander: 11.1.0 + jiti: 2.4.2 + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - typescript + - utf-8-validate + - vue-tsc + + '@module-federation/data-prefetch@0.0.0-feat-modern-3-0-20251120074204(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@module-federation/runtime': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + fs-extra: 9.1.0 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@module-federation/dts-plugin@0.0.0-feat-modern-3-0-20251120074204(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)': + dependencies: + '@module-federation/error-codes': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/managers': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/third-party-dts-extractor': 0.0.0-feat-modern-3-0-20251120074204 + adm-zip: 0.5.16 + ansi-colors: 4.1.3 + axios: 1.12.2 + chalk: 3.0.0 + fs-extra: 9.1.0 + isomorphic-ws: 5.0.0(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)) + koa: 3.0.3 + lodash.clonedeepwith: 4.5.0 + log4js: 6.9.1 + node-schedule: 2.1.1 + rambda: 9.4.2 + typescript: 5.6.3 + ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - utf-8-validate + + '@module-federation/enhanced@0.0.0-feat-modern-3-0-20251120074204(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5))': + dependencies: + '@module-federation/bridge-react-webpack-plugin': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/cli': 0.0.0-feat-modern-3-0-20251120074204(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@module-federation/data-prefetch': 0.0.0-feat-modern-3-0-20251120074204(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@module-federation/dts-plugin': 0.0.0-feat-modern-3-0-20251120074204(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@module-federation/error-codes': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/inject-external-runtime-core-plugin': 0.0.0-feat-modern-3-0-20251120074204(@module-federation/runtime-tools@0.0.0-feat-modern-3-0-20251120074204) + '@module-federation/managers': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/manifest': 0.0.0-feat-modern-3-0-20251120074204(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@module-federation/rspack': 0.0.0-feat-modern-3-0-20251120074204(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@module-federation/runtime-tools': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + btoa: 1.2.1 + schema-utils: 4.3.2 + upath: 2.0.1 + optionalDependencies: + typescript: 5.6.3 + webpack: 5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5) + transitivePeerDependencies: + - '@rspack/core' + - bufferutil + - debug + - react + - react-dom + - supports-color + - utf-8-validate + + '@module-federation/error-codes@0.0.0-feat-modern-3-0-20251120074204': {} + '@module-federation/error-codes@0.21.4': {} + '@module-federation/inject-external-runtime-core-plugin@0.0.0-feat-modern-3-0-20251120074204(@module-federation/runtime-tools@0.0.0-feat-modern-3-0-20251120074204)': + dependencies: + '@module-federation/runtime-tools': 0.0.0-feat-modern-3-0-20251120074204 + + '@module-federation/managers@0.0.0-feat-modern-3-0-20251120074204': + dependencies: + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + find-pkg: 2.0.0 + fs-extra: 9.1.0 + + '@module-federation/manifest@0.0.0-feat-modern-3-0-20251120074204(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)': + dependencies: + '@module-federation/dts-plugin': 0.0.0-feat-modern-3-0-20251120074204(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@module-federation/managers': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + chalk: 3.0.0 + find-pkg: 2.0.0 + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - typescript + - utf-8-validate + - vue-tsc + + '@module-federation/modern-js@0.0.0-feat-modern-3-0-20251120074204(@rsbuild/core@1.6.7)(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react-router-dom@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-router@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5))': + dependencies: + '@modern-js/node-bundle-require': 0.0.0-canary-20251119023553(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@modern-js/utils': 0.0.0-canary-20251119023553(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@module-federation/bridge-react': 0.0.0-feat-modern-3-0-20251120074204(react-dom@19.2.0(react@19.2.0))(react-router-dom@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react-router@7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(react@19.2.0) + '@module-federation/cli': 0.0.0-feat-modern-3-0-20251120074204(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@module-federation/enhanced': 0.0.0-feat-modern-3-0-20251120074204(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5)) + '@module-federation/node': 0.0.0-feat-modern-3-0-20251120074204(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5)) + '@module-federation/rsbuild-plugin': 0.0.0-feat-modern-3-0-20251120074204(@rsbuild/core@1.6.7)(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5)) + '@module-federation/runtime': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + '@swc/helpers': 0.5.17 + fs-extra: 11.3.0 + lru-cache: 10.4.3 + node-fetch: 3.3.2 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-error-boundary: 4.1.2(react@19.2.0) + optionalDependencies: + react-router: 7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react-router-dom: 7.8.2(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + typescript: 5.6.3 + transitivePeerDependencies: + - '@rsbuild/core' + - '@rspack/core' + - bufferutil + - debug + - next + - supports-color + - utf-8-validate + - webpack + + '@module-federation/node@0.0.0-feat-modern-3-0-20251120074204(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5))': + dependencies: + '@module-federation/enhanced': 0.0.0-feat-modern-3-0-20251120074204(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5)) + '@module-federation/runtime': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + btoa: 1.2.1 + encoding: 0.1.13 + node-fetch: 2.7.0(encoding@0.1.13) + webpack: 5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5) + optionalDependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + transitivePeerDependencies: + - '@rspack/core' + - bufferutil + - debug + - supports-color + - typescript + - utf-8-validate + - vue-tsc + + '@module-federation/rsbuild-plugin@0.0.0-feat-modern-3-0-20251120074204(@rsbuild/core@1.6.7)(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5))': + dependencies: + '@module-federation/enhanced': 0.0.0-feat-modern-3-0-20251120074204(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5)) + '@module-federation/node': 0.0.0-feat-modern-3-0-20251120074204(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.6.3)(utf-8-validate@5.0.10)(webpack@5.99.8(@swc/core@1.14.0(@swc/helpers@0.5.17))(esbuild@0.25.5)) + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + fs-extra: 11.3.0 + optionalDependencies: + '@rsbuild/core': 1.6.7 + transitivePeerDependencies: + - '@rspack/core' + - bufferutil + - debug + - next + - react + - react-dom + - supports-color + - typescript + - utf-8-validate + - vue-tsc + - webpack + + '@module-federation/rspack@0.0.0-feat-modern-3-0-20251120074204(@rspack/core@1.6.4(@swc/helpers@0.5.17))(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10)': + dependencies: + '@module-federation/bridge-react-webpack-plugin': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/dts-plugin': 0.0.0-feat-modern-3-0-20251120074204(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@module-federation/inject-external-runtime-core-plugin': 0.0.0-feat-modern-3-0-20251120074204(@module-federation/runtime-tools@0.0.0-feat-modern-3-0-20251120074204) + '@module-federation/managers': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/manifest': 0.0.0-feat-modern-3-0-20251120074204(bufferutil@4.0.8)(typescript@5.6.3)(utf-8-validate@5.0.10) + '@module-federation/runtime-tools': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + '@rspack/core': 1.6.4(@swc/helpers@0.5.17) + btoa: 1.2.1 + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - bufferutil + - debug + - supports-color + - utf-8-validate + + '@module-federation/runtime-core@0.0.0-feat-modern-3-0-20251120074204': + dependencies: + '@module-federation/error-codes': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/runtime-core@0.21.4': dependencies: '@module-federation/error-codes': 0.21.4 '@module-federation/sdk': 0.21.4 + '@module-federation/runtime-tools@0.0.0-feat-modern-3-0-20251120074204': + dependencies: + '@module-federation/runtime': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/webpack-bundler-runtime': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/runtime-tools@0.21.4': dependencies: '@module-federation/runtime': 0.21.4 '@module-federation/webpack-bundler-runtime': 0.21.4 + '@module-federation/runtime@0.0.0-feat-modern-3-0-20251120074204': + dependencies: + '@module-federation/error-codes': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/runtime-core': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/runtime@0.21.4': dependencies: '@module-federation/error-codes': 0.21.4 '@module-federation/runtime-core': 0.21.4 '@module-federation/sdk': 0.21.4 + '@module-federation/sdk@0.0.0-feat-modern-3-0-20251120074204': {} + '@module-federation/sdk@0.21.4': {} + '@module-federation/third-party-dts-extractor@0.0.0-feat-modern-3-0-20251120074204': + dependencies: + find-pkg: 2.0.0 + fs-extra: 9.1.0 + resolve: 1.22.8 + + '@module-federation/webpack-bundler-runtime@0.0.0-feat-modern-3-0-20251120074204': + dependencies: + '@module-federation/runtime': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/sdk': 0.0.0-feat-modern-3-0-20251120074204 + '@module-federation/webpack-bundler-runtime@0.21.4': dependencies: '@module-federation/runtime': 0.21.4 @@ -21215,6 +21896,8 @@ snapshots: '@types/glob': 7.2.0 '@types/node': 20.8.8 + '@types/semver@7.5.8': {} + '@types/semver@7.7.1': {} '@types/send@0.17.4': @@ -21630,6 +22313,8 @@ snapshots: address@1.2.2: {} + adm-zip@0.5.16: {} + agent-base@6.0.2: dependencies: debug: 4.4.3(supports-color@5.5.0) @@ -21695,7 +22380,7 @@ snapshots: ansi-styles@6.2.1: {} - antd@5.28.1(date-fns@2.30.0)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + antd@5.28.1(date-fns@2.30.0)(luxon@3.7.2)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: '@ant-design/colors': 7.2.1 '@ant-design/cssinjs': 1.24.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -21727,7 +22412,7 @@ snapshots: rc-motion: 2.9.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0) rc-notification: 5.6.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) rc-pagination: 5.1.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - rc-picker: 4.11.3(date-fns@2.30.0)(dayjs@1.11.18)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + rc-picker: 4.11.3(date-fns@2.30.0)(dayjs@1.11.18)(luxon@3.7.2)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) rc-progress: 4.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) rc-rate: 2.13.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) rc-resize-observer: 1.4.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -21809,6 +22494,8 @@ snapshots: asynckit@0.4.0: {} + at-least-node@1.0.0: {} + audio-context-polyfill@1.0.0: {} autoprefixer@10.4.22(postcss@8.5.6): @@ -22055,6 +22742,8 @@ snapshots: dependencies: node-int64: 0.4.0 + btoa@1.2.1: {} + buffer-builder@0.2.0: {} buffer-crc32@0.2.13: {} @@ -22171,6 +22860,11 @@ snapshots: escape-string-regexp: 1.0.5 supports-color: 5.5.0 + chalk@3.0.0: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 @@ -22580,6 +23274,10 @@ snapshots: crelt@1.0.6: {} + cron-parser@4.9.0: + dependencies: + luxon: 3.7.2 + cross-env@7.0.3: dependencies: cross-spawn: 7.0.6 @@ -22984,6 +23682,8 @@ snapshots: data-uri-to-buffer@3.0.1: {} + data-uri-to-buffer@4.0.1: {} + data-uri-to-buffer@6.0.2: {} data-urls@3.0.2: @@ -22997,6 +23697,8 @@ snapshots: '@babel/runtime': 7.28.4 optional: true + date-format@4.0.14: {} + dayjs@1.11.13: {} dayjs@1.11.18: {} @@ -23742,6 +24444,10 @@ snapshots: dependencies: os-homedir: 1.0.2 + expand-tilde@2.0.2: + dependencies: + homedir-polyfill: 1.0.3 + expect-puppeteer@11.0.0: {} expect-type@1.1.0: {} @@ -23888,6 +24594,11 @@ snapshots: sprintf-js: 1.1.3 tmp: 0.0.33 + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + fflate@0.8.2: {} figures@2.0.0: @@ -23947,10 +24658,18 @@ snapshots: fs-exists-sync: 0.1.0 resolve-dir: 0.1.1 + find-file-up@2.0.1: + dependencies: + resolve-dir: 1.0.1 + find-pkg@0.1.2: dependencies: find-file-up: 0.1.3 + find-pkg@2.0.0: + dependencies: + find-file-up: 2.0.1 + find-process@1.4.7: dependencies: chalk: 4.1.2 @@ -24015,6 +24734,10 @@ snapshots: hasown: 2.0.2 mime-types: 2.1.35 + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + formidable@2.1.5: dependencies: '@paralleldrive/cuid2': 2.2.2 @@ -24071,6 +24794,13 @@ snapshots: jsonfile: 4.0.0 universalify: 0.1.2 + fs-extra@9.1.0: + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + fs-minipass@2.1.0: dependencies: minipass: 3.3.3 @@ -24232,6 +24962,12 @@ snapshots: global-prefix: 0.1.5 is-windows: 0.2.0 + global-modules@1.0.0: + dependencies: + global-prefix: 1.0.2 + is-windows: 1.0.2 + resolve-dir: 1.0.1 + global-prefix@0.1.5: dependencies: homedir-polyfill: 1.0.3 @@ -24239,6 +24975,14 @@ snapshots: is-windows: 0.2.0 which: 1.3.1 + global-prefix@1.0.2: + dependencies: + expand-tilde: 2.0.2 + homedir-polyfill: 1.0.3 + ini: 1.3.8 + is-windows: 1.0.2 + which: 1.3.1 + globals@11.12.0: {} globals@15.15.0: {} @@ -24995,6 +25739,10 @@ snapshots: transitivePeerDependencies: - encoding + isomorphic-ws@5.0.0(ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10)): + dependencies: + ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) + istanbul-lib-coverage@3.2.0: {} istanbul-lib-instrument@5.2.0: @@ -25573,6 +26321,8 @@ snapshots: jiti@1.21.7: {} + jiti@2.4.2: {} + jiti@2.6.1: {} joi@17.13.3: @@ -25743,6 +26493,27 @@ snapshots: transitivePeerDependencies: - supports-color + koa@3.0.3: + dependencies: + accepts: 1.3.8 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookies: 0.9.1 + delegates: 1.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + fresh: 0.5.2 + http-assert: 1.5.0 + http-errors: 2.0.0 + koa-compose: 4.1.0 + mime-types: 3.0.1 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + type-is: 2.0.1 + vary: 1.1.2 + kolorist@1.8.0: {} langium@3.3.1: @@ -25927,6 +26698,8 @@ snapshots: lodash.camelcase@4.3.0: {} + lodash.clonedeepwith@4.5.0: {} + lodash.debounce@4.0.8: {} lodash.defaults@4.2.0: {} @@ -25982,6 +26755,18 @@ snapshots: strip-ansi: 7.1.0 wrap-ansi: 8.1.0 + log4js@6.9.1: + dependencies: + date-format: 4.0.14 + debug: 4.4.3(supports-color@5.5.0) + flatted: 3.3.3 + rfdc: 1.3.0 + streamroller: 3.1.5 + transitivePeerDependencies: + - supports-color + + long-timeout@0.1.1: {} + longest-streak@3.1.0: {} longest@1.0.1: {} @@ -26019,6 +26804,8 @@ snapshots: lru-cache@7.18.3: {} + luxon@3.7.2: {} + lz-string@1.5.0: {} magic-string@0.30.17: @@ -26227,6 +27014,8 @@ snapshots: media-typer@0.3.0: {} + media-typer@1.1.0: {} + medium-zoom@1.1.0: {} memfs@3.5.3: @@ -26567,10 +27356,16 @@ snapshots: mime-db@1.53.0: {} + mime-db@1.54.0: {} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 + mime-types@3.0.1: + dependencies: + mime-db: 1.54.0 + mime@1.6.0: {} mime@2.6.0: {} @@ -26726,6 +27521,8 @@ snapshots: node-addon-api@7.1.1: {} + node-domexception@1.0.0: {} + node-emoji@1.11.0: dependencies: lodash: 4.17.21 @@ -26738,6 +27535,12 @@ snapshots: optionalDependencies: encoding: 0.1.13 + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + node-forge@1.3.1: {} node-gyp-build@4.8.2: {} @@ -26766,6 +27569,12 @@ snapshots: node-releases@2.0.26: {} + node-schedule@2.1.1: + dependencies: + cron-parser: 4.9.0 + long-timeout: 0.1.1 + sorted-array-functions: 1.3.0 + nopt@5.0.0: dependencies: abbrev: 1.1.1 @@ -27764,6 +28573,8 @@ snapshots: radix3@1.1.2: {} + rambda@9.4.2: {} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 @@ -27927,7 +28738,7 @@ snapshots: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - rc-picker@4.11.3(date-fns@2.30.0)(dayjs@1.11.18)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + rc-picker@4.11.3(date-fns@2.30.0)(dayjs@1.11.18)(luxon@3.7.2)(moment@2.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: '@babel/runtime': 7.28.4 '@rc-component/trigger': 2.3.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -27940,6 +28751,7 @@ snapshots: optionalDependencies: date-fns: 2.30.0 dayjs: 1.11.18 + luxon: 3.7.2 moment: 2.30.1 rc-progress@4.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0): @@ -28107,6 +28919,11 @@ snapshots: react: 19.2.0 scheduler: 0.27.0 + react-error-boundary@4.1.2(react@19.2.0): + dependencies: + '@babel/runtime': 7.28.4 + react: 19.2.0 + react-fast-compare@3.2.0: {} react-helmet@6.1.0(react@19.2.0): @@ -28420,6 +29237,11 @@ snapshots: expand-tilde: 1.2.2 global-modules: 0.2.3 + resolve-dir@1.0.1: + dependencies: + expand-tilde: 2.0.2 + global-modules: 1.0.0 + resolve-from@4.0.0: {} resolve-from@5.0.0: {} @@ -28449,6 +29271,12 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + resolve@1.22.8: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + responselike@2.0.1: dependencies: lowercase-keys: 2.0.0 @@ -28722,6 +29550,8 @@ snapshots: dependencies: lru-cache: 6.0.0 + semver@7.6.3: {} + semver@7.7.2: {} semver@7.7.3: {} @@ -28971,6 +29801,8 @@ snapshots: ip-address: 9.0.5 smart-buffer: 4.2.0 + sorted-array-functions@1.3.0: {} + source-map-js@1.2.1: {} source-map-support@0.5.13: @@ -29068,6 +29900,14 @@ snapshots: dependencies: promise-polyfill: 1.1.6 + streamroller@3.1.5: + dependencies: + date-format: 4.0.14 + debug: 4.4.3(supports-color@5.5.0) + fs-extra: 8.1.0 + transitivePeerDependencies: + - supports-color + streamx@2.22.0: dependencies: fast-fifo: 1.3.2 @@ -29705,6 +30545,12 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + type@2.7.3: {} typed-query-selector@2.12.0: {} @@ -30198,6 +31044,11 @@ snapshots: bufferutil: 4.0.8 utf-8-validate: 5.0.10 + ws@8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10): + optionalDependencies: + bufferutil: 4.0.8 + utf-8-validate: 5.0.10 + ws@8.18.3(bufferutil@4.0.8)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.8 diff --git a/tests/integration/i18n/mf-app-provider/modern.config.ts b/tests/integration/i18n/mf-app-provider/modern.config.ts new file mode 100644 index 000000000000..4cdff279fc19 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/modern.config.ts @@ -0,0 +1,27 @@ +import { appTools, defineConfig } from '@modern-js/app-tools'; +import { i18nPlugin } from '@modern-js/plugin-i18n'; +import { moduleFederationPlugin } from '@module-federation/modern-js'; + +export default defineConfig({ + server: { + ssr: { + mode: 'stream', + }, + port: 3005, + }, + performance: { + buildCache: false, + }, + plugins: [ + appTools(), + i18nPlugin({ + localeDetection: { + localePathRedirect: true, + languages: ['zh', 'en'], + fallbackLanguage: 'en', + ignoreRedirectRoutes: ['/about', '/'], + }, + }), + moduleFederationPlugin(), + ], +}); diff --git a/tests/integration/i18n/mf-app-provider/module-federation.config.ts b/tests/integration/i18n/mf-app-provider/module-federation.config.ts new file mode 100644 index 000000000000..ee4f7d8cf244 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/module-federation.config.ts @@ -0,0 +1,28 @@ +import { createModuleFederationConfig } from '@module-federation/modern-js'; +import { dependencies } from './package.json'; + +export default createModuleFederationConfig({ + name: 'i18nAppProvider', + filename: 'remoteEntry.js', + exposes: { + './export-app': './src/export-app.tsx', + }, + bridge: { + enableBridgeRouter: false, + }, + shared: { + react: { singleton: true, requiredVersion: dependencies.react }, + 'react-dom': { + singleton: true, + requiredVersion: dependencies['react-dom'], + }, + 'react-i18next': { + singleton: true, + requiredVersion: dependencies['react-i18next'], + }, + i18next: { + singleton: true, + requiredVersion: dependencies.i18next, + }, + }, +}); diff --git a/tests/integration/i18n/mf-app-provider/package.json b/tests/integration/i18n/mf-app-provider/package.json new file mode 100644 index 000000000000..1bdafa76f622 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/package.json @@ -0,0 +1,23 @@ +{ + "private": true, + "name": "i18n-mf-app-provider", + "version": "2.66.0", + "scripts": { + "dev": "modern dev", + "build": "modern build" + }, + "dependencies": { + "i18next":"25.6.2", + "react-i18next": "15.7.4", + "@modern-js/runtime": "workspace:*", + "@modern-js/plugin-i18n": "workspace:*", + "@module-federation/modern-js": "0.0.0-feat-modern-3-0-20251120074204", + "@module-federation/bridge-react": "0.0.0-feat-modern-3-0-20251120074204", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@modern-js/app-tools": "workspace:*", + "@modern-js/plugin-ssg": "workspace:*" + } +} diff --git a/tests/integration/i18n/mf-app-provider/src/export-app.tsx b/tests/integration/i18n/mf-app-provider/src/export-app.tsx new file mode 100644 index 000000000000..36fa5d5bf7f9 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/src/export-app.tsx @@ -0,0 +1,15 @@ +import '@modern-js/runtime/registry/index'; +import { render } from '@modern-js/runtime/browser'; +import { createRoot } from '@modern-js/runtime/react'; +import { createBridgeComponent } from '@module-federation/bridge-react/v19'; +import type { ReactElement } from 'react'; + +const ModernRoot = createRoot(); + +export const provider = createBridgeComponent({ + rootComponent: ModernRoot, + render: (Component, dom) => + render(Component as ReactElement<{ basename: string }>, dom), +}); + +export default provider; diff --git a/tests/integration/i18n/mf-app-provider/src/i18n.ts b/tests/integration/i18n/mf-app-provider/src/i18n.ts new file mode 100644 index 000000000000..bcb60f121938 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/src/i18n.ts @@ -0,0 +1,24 @@ +import originalI18next from 'i18next'; + +const i18next = originalI18next.createInstance(); + +i18next.init({ + lng: 'en', + fallbackLng: 'en', + resources: { + en: { + translation: { + key: 'Hello World(provider)', + about: 'About(provider)', + }, + }, + zh: { + translation: { + key: '你好,世界(provider)', + about: '关于(provider)', + }, + }, + }, +}); + +export default i18next; diff --git a/tests/integration/i18n/mf-app-provider/src/modern-app-env.d.ts b/tests/integration/i18n/mf-app-provider/src/modern-app-env.d.ts new file mode 100644 index 000000000000..d8912d28ef5a --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/src/modern-app-env.d.ts @@ -0,0 +1,4 @@ +/// +/// + +declare module 'normalize-path'; diff --git a/tests/integration/i18n/mf-app-provider/src/modern.runtime.tsx b/tests/integration/i18n/mf-app-provider/src/modern.runtime.tsx new file mode 100644 index 000000000000..0cdd1c32a6f5 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/src/modern.runtime.tsx @@ -0,0 +1,8 @@ +import { defineRuntimeConfig } from '@modern-js/runtime'; +import i18next from './i18n'; + +export default defineRuntimeConfig({ + i18n: { + i18nInstance: i18next, + }, +}); diff --git a/tests/integration/i18n/mf-app-provider/src/routes/[lang]/test/page.data.ts b/tests/integration/i18n/mf-app-provider/src/routes/[lang]/test/page.data.ts new file mode 100644 index 000000000000..fd8ab28108f4 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/src/routes/[lang]/test/page.data.ts @@ -0,0 +1,13 @@ +import i18next from '../../../i18n'; +export interface ProfileData { + /* some types */ + data: string; +} + +export const loader = async ({ params }: any): Promise => { + console.log( + '===i18next.t("key")', + i18next.t('key', { lng: params.lang || i18next.language }), + ); + return { data: i18next.t('key', { lng: params.lang || i18next.language }) }; +}; diff --git a/tests/integration/i18n/mf-app-provider/src/routes/[lang]/test/page.tsx b/tests/integration/i18n/mf-app-provider/src/routes/[lang]/test/page.tsx new file mode 100644 index 000000000000..3f9c94a7b5c1 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/src/routes/[lang]/test/page.tsx @@ -0,0 +1,16 @@ +import { useLoaderData } from '@modern-js/runtime/router'; +import i18next from '../../../i18n'; +import type { ProfileData } from './page.data'; + +export default () => { + const profileData = useLoaderData() as ProfileData; + const data = profileData.data; + if (typeof data !== 'string') { + return ( + <> +
Loading...
+ + ); + } + return
{data}
; +}; diff --git a/tests/integration/i18n/mf-app-provider/src/routes/about/page.tsx b/tests/integration/i18n/mf-app-provider/src/routes/about/page.tsx new file mode 100644 index 000000000000..bc4ba4bd85d8 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/src/routes/about/page.tsx @@ -0,0 +1,6 @@ +import { useTranslation } from 'react-i18next'; + +export default () => { + const { t } = useTranslation(); + return
{t('about')}
; +}; diff --git a/tests/integration/i18n/mf-app-provider/src/routes/layout.tsx b/tests/integration/i18n/mf-app-provider/src/routes/layout.tsx new file mode 100644 index 000000000000..16d79950aba1 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/src/routes/layout.tsx @@ -0,0 +1,19 @@ +import { useModernI18n } from '@modern-js/plugin-i18n/runtime'; +import { Outlet } from '@modern-js/runtime/router'; + +export default function Layout() { + const { changeLanguage } = useModernI18n(); + return ( +
+
+ + +
+ +
+ ); +} diff --git a/tests/integration/i18n/mf-app-provider/src/routes/page.data.ts b/tests/integration/i18n/mf-app-provider/src/routes/page.data.ts new file mode 100644 index 000000000000..bb93c7a565f9 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/src/routes/page.data.ts @@ -0,0 +1,13 @@ +import i18next from '../i18n'; +export interface ProfileData { + /* some types */ + data: string; +} + +export const loader = async ({ params }: any): Promise => { + console.log( + '===i18next.t("key")', + i18next.t('key', { lng: params.lang || i18next.language }), + ); + return { data: i18next.t('key', { lng: params.lang || i18next.language }) }; +}; diff --git a/tests/integration/i18n/mf-app-provider/src/routes/page.tsx b/tests/integration/i18n/mf-app-provider/src/routes/page.tsx new file mode 100644 index 000000000000..d6b82ccaebd3 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/src/routes/page.tsx @@ -0,0 +1,15 @@ +import { useLoaderData } from '@modern-js/runtime/router'; +import type { ProfileData } from './page.data'; + +export default () => { + const profileData = useLoaderData() as ProfileData; + const data = profileData.data; + if (typeof data !== 'string') { + return ( + <> +
Loading...
+ + ); + } + return
{data}
; +}; diff --git a/tests/integration/i18n/mf-app-provider/tsconfig.json b/tests/integration/i18n/mf-app-provider/tsconfig.json new file mode 100644 index 000000000000..20bd5c24f7a7 --- /dev/null +++ b/tests/integration/i18n/mf-app-provider/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@modern-js/tsconfig/base", + "compilerOptions": { + "declaration": false, + "jsx": "preserve", + "baseUrl": "./", + "outDir": "dist", + "paths": { + "@/*": ["./src/*"], + "@shared/*": ["./shared/*"] + } + }, + "include": ["src", "tests", "modern.config.ts"] +} diff --git a/tests/integration/i18n/mf-consumer/@mf-types/AppRemote/apis.d.ts b/tests/integration/i18n/mf-consumer/@mf-types/AppRemote/apis.d.ts new file mode 100644 index 000000000000..3ad2fa95ab2a --- /dev/null +++ b/tests/integration/i18n/mf-consumer/@mf-types/AppRemote/apis.d.ts @@ -0,0 +1,3 @@ + + export type RemoteKeys = 'AppRemote/export-app'; + type PackageType = T extends 'AppRemote/export-app' ? typeof import('AppRemote/export-app') :any; \ No newline at end of file diff --git a/tests/integration/i18n/mf-consumer/@mf-types/AppRemote/compiled-types/src/export-app.d.ts b/tests/integration/i18n/mf-consumer/@mf-types/AppRemote/compiled-types/src/export-app.d.ts new file mode 100644 index 000000000000..f586bc612679 --- /dev/null +++ b/tests/integration/i18n/mf-consumer/@mf-types/AppRemote/compiled-types/src/export-app.d.ts @@ -0,0 +1,6 @@ +import '@modern-js/runtime/registry/index'; +export declare const provider: () => { + render(info: import("@module-federation/bridge-react/v19").RenderParams): Promise; + destroy(info: import("@module-federation/bridge-react/v19").DestroyParams): void; +}; +export default provider; diff --git a/tests/integration/i18n/mf-consumer/@mf-types/AppRemote/export-app.d.ts b/tests/integration/i18n/mf-consumer/@mf-types/AppRemote/export-app.d.ts new file mode 100644 index 000000000000..841b8bf51310 --- /dev/null +++ b/tests/integration/i18n/mf-consumer/@mf-types/AppRemote/export-app.d.ts @@ -0,0 +1,2 @@ +export * from './compiled-types/src/export-app'; +export { default } from './compiled-types/src/export-app'; \ No newline at end of file diff --git a/tests/integration/i18n/mf-consumer/@mf-types/componentRemote/Text.d.ts b/tests/integration/i18n/mf-consumer/@mf-types/componentRemote/Text.d.ts new file mode 100644 index 000000000000..3484abf43a3d --- /dev/null +++ b/tests/integration/i18n/mf-consumer/@mf-types/componentRemote/Text.d.ts @@ -0,0 +1,2 @@ +export * from './compiled-types/src/components/Text'; +export { default } from './compiled-types/src/components/Text'; \ No newline at end of file diff --git a/tests/integration/i18n/mf-consumer/@mf-types/componentRemote/apis.d.ts b/tests/integration/i18n/mf-consumer/@mf-types/componentRemote/apis.d.ts new file mode 100644 index 000000000000..f78f7d55a8eb --- /dev/null +++ b/tests/integration/i18n/mf-consumer/@mf-types/componentRemote/apis.d.ts @@ -0,0 +1,3 @@ + + export type RemoteKeys = 'componentRemote/Text'; + type PackageType = T extends 'componentRemote/Text' ? typeof import('componentRemote/Text') :any; \ No newline at end of file diff --git a/tests/integration/i18n/mf-consumer/@mf-types/componentRemote/compiled-types/src/components/Text.d.ts b/tests/integration/i18n/mf-consumer/@mf-types/componentRemote/compiled-types/src/components/Text.d.ts new file mode 100644 index 000000000000..839269d7d389 --- /dev/null +++ b/tests/integration/i18n/mf-consumer/@mf-types/componentRemote/compiled-types/src/components/Text.d.ts @@ -0,0 +1,2 @@ +declare const _default: () => import("react").JSX.Element; +export default _default; diff --git a/tests/integration/i18n/mf-consumer/@mf-types/componentRemote/compiled-types/src/i18n.d.ts b/tests/integration/i18n/mf-consumer/@mf-types/componentRemote/compiled-types/src/i18n.d.ts new file mode 100644 index 000000000000..7d204961dc9f --- /dev/null +++ b/tests/integration/i18n/mf-consumer/@mf-types/componentRemote/compiled-types/src/i18n.d.ts @@ -0,0 +1,2 @@ +declare const i18next: import("i18next").i18n; +export default i18next; diff --git a/tests/integration/i18n/mf-consumer/@mf-types/index.d.ts b/tests/integration/i18n/mf-consumer/@mf-types/index.d.ts new file mode 100644 index 000000000000..d4f9c554ae0e --- /dev/null +++ b/tests/integration/i18n/mf-consumer/@mf-types/index.d.ts @@ -0,0 +1,35 @@ +import type { PackageType as PackageType_0,RemoteKeys as RemoteKeys_0 } from './AppRemote/apis.d.ts'; +import type { PackageType as PackageType_1,RemoteKeys as RemoteKeys_1 } from './componentRemote/apis.d.ts'; + declare module "@module-federation/runtime" { + type RemoteKeys = RemoteKeys_0 | RemoteKeys_1; + type PackageType = T extends RemoteKeys_0 ? PackageType_0 : +T extends RemoteKeys_1 ? PackageType_1 : +Y ; + export function loadRemote(packageName: T): Promise>; + export function loadRemote(packageName: T): Promise>; + } +declare module "@module-federation/enhanced/runtime" { + type RemoteKeys = RemoteKeys_0 | RemoteKeys_1; + type PackageType = T extends RemoteKeys_0 ? PackageType_0 : +T extends RemoteKeys_1 ? PackageType_1 : +Y ; + export function loadRemote(packageName: T): Promise>; + export function loadRemote(packageName: T): Promise>; + } +declare module "@module-federation/runtime-tools" { + type RemoteKeys = RemoteKeys_0 | RemoteKeys_1; + type PackageType = T extends RemoteKeys_0 ? PackageType_0 : +T extends RemoteKeys_1 ? PackageType_1 : +Y ; + export function loadRemote(packageName: T): Promise>; + export function loadRemote(packageName: T): Promise>; + } +declare module "@module-federation/modern-js/runtime" { + type RemoteKeys = RemoteKeys_0 | RemoteKeys_1; + type PackageType = T extends RemoteKeys_0 ? PackageType_0 : +T extends RemoteKeys_1 ? PackageType_1 : +Y ; + export function loadRemote(packageName: T): Promise>; + export function loadRemote(packageName: T): Promise>; + } + \ No newline at end of file diff --git a/tests/integration/i18n/mf-consumer/modern.config.ts b/tests/integration/i18n/mf-consumer/modern.config.ts new file mode 100644 index 000000000000..c775fb400b39 --- /dev/null +++ b/tests/integration/i18n/mf-consumer/modern.config.ts @@ -0,0 +1,27 @@ +import { appTools, defineConfig } from '@modern-js/app-tools'; +import { i18nPlugin } from '@modern-js/plugin-i18n'; +import { moduleFederationPlugin } from '@module-federation/modern-js'; + +export default defineConfig({ + server: { + ssr: { + mode: 'stream', + }, + port: 3007, + }, + performance: { + buildCache: false, + }, + plugins: [ + appTools(), + i18nPlugin({ + localeDetection: { + localePathRedirect: true, + languages: ['zh', 'en'], + fallbackLanguage: 'en', + ignoreRedirectRoutes: ['/remote'], + }, + }), + moduleFederationPlugin(), + ], +}); diff --git a/tests/integration/i18n/mf-consumer/module-federation.config.ts b/tests/integration/i18n/mf-consumer/module-federation.config.ts new file mode 100644 index 000000000000..8386a7eaa5f8 --- /dev/null +++ b/tests/integration/i18n/mf-consumer/module-federation.config.ts @@ -0,0 +1,19 @@ +import { createModuleFederationConfig } from '@module-federation/modern-js'; + +export default createModuleFederationConfig({ + name: 'consumer', + remotes: { + componentRemote: + 'i18nComponentProvider@http://localhost:3006/mf-manifest.json', + AppRemote: 'i18nAppProvider@http://localhost:3005/mf-manifest.json', + }, + bridge: { + enableBridgeRouter: false, + }, + shared: { + react: { singleton: true }, + 'react-dom': { singleton: true }, + 'react-i18next': { singleton: true }, + i18next: { singleton: true }, + }, +}); diff --git a/tests/integration/i18n/mf-consumer/package.json b/tests/integration/i18n/mf-consumer/package.json new file mode 100644 index 000000000000..01a7d8dc257d --- /dev/null +++ b/tests/integration/i18n/mf-consumer/package.json @@ -0,0 +1,24 @@ +{ + "private": true, + "name": "i18n-mf-consumer", + "version": "2.66.0", + "scripts": { + "dev": "modern dev", + "build": "modern build" + }, + "dependencies": { + "i18next":"25.6.2", + "react-i18next": "15.7.4", + "@modern-js/runtime": "workspace:*", + "@modern-js/plugin-i18n": "workspace:*", + "@module-federation/modern-js": "0.0.0-feat-modern-3-0-20251120074204", + "@module-federation/bridge-react": "0.0.0-feat-modern-3-0-20251120074204", + "@module-federation/runtime": "0.0.0-feat-modern-3-0-20251120074204", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@modern-js/app-tools": "workspace:*", + "@modern-js/plugin-ssg": "workspace:*" + } +} diff --git a/tests/integration/i18n/mf-consumer/src/components/RemoteApp.tsx b/tests/integration/i18n/mf-consumer/src/components/RemoteApp.tsx new file mode 100644 index 000000000000..517faaf8391f --- /dev/null +++ b/tests/integration/i18n/mf-consumer/src/components/RemoteApp.tsx @@ -0,0 +1,35 @@ +import { createRemoteAppComponent } from '@module-federation/bridge-react'; +import { loadRemote } from '@module-federation/modern-js/runtime'; +import React from 'react'; + +// 错误回退组件 +const FallbackErrorComp = (info: any) => { + return ( +
+

加载失败

+

{info?.error?.message}

+ +
+ ); +}; + +// 加载中组件 +const FallbackComp = ( +
+
正在加载远程应用...
+
+); + +// 创建远程应用组件 +const RemoteApp = createRemoteAppComponent({ + // loader: () => import('AppRemote/export-App'), + // 或者使用 loadRemote: + loader: () => loadRemote('AppRemote/export-app'), + export: 'provider' as any, // 指定导出的 provider + fallback: FallbackErrorComp, + loading: FallbackComp, +}); + +export default RemoteApp; diff --git a/tests/integration/i18n/mf-consumer/src/i18n.ts b/tests/integration/i18n/mf-consumer/src/i18n.ts new file mode 100644 index 000000000000..4b1ce7f5efb4 --- /dev/null +++ b/tests/integration/i18n/mf-consumer/src/i18n.ts @@ -0,0 +1,24 @@ +import originalI18next from 'i18next'; + +const i18next = originalI18next.createInstance(); + +i18next.init({ + lng: 'en', + fallbackLng: 'en', + resources: { + en: { + translation: { + key: 'Hello World(consumer)', + about: 'About(consumer)', + }, + }, + zh: { + translation: { + key: '你好,世界(consumer)', + about: '关于(consumer)', + }, + }, + }, +}); + +export default i18next; diff --git a/tests/integration/i18n/mf-consumer/src/modern-app-env.d.ts b/tests/integration/i18n/mf-consumer/src/modern-app-env.d.ts new file mode 100644 index 000000000000..d8912d28ef5a --- /dev/null +++ b/tests/integration/i18n/mf-consumer/src/modern-app-env.d.ts @@ -0,0 +1,4 @@ +/// +/// + +declare module 'normalize-path'; diff --git a/tests/integration/i18n/mf-consumer/src/modern.runtime.tsx b/tests/integration/i18n/mf-consumer/src/modern.runtime.tsx new file mode 100644 index 000000000000..0cdd1c32a6f5 --- /dev/null +++ b/tests/integration/i18n/mf-consumer/src/modern.runtime.tsx @@ -0,0 +1,8 @@ +import { defineRuntimeConfig } from '@modern-js/runtime'; +import i18next from './i18n'; + +export default defineRuntimeConfig({ + i18n: { + i18nInstance: i18next, + }, +}); diff --git a/tests/integration/i18n/mf-consumer/src/routes/[lang]/about/page.tsx b/tests/integration/i18n/mf-consumer/src/routes/[lang]/about/page.tsx new file mode 100644 index 000000000000..bc4ba4bd85d8 --- /dev/null +++ b/tests/integration/i18n/mf-consumer/src/routes/[lang]/about/page.tsx @@ -0,0 +1,6 @@ +import { useTranslation } from 'react-i18next'; + +export default () => { + const { t } = useTranslation(); + return
{t('about')}
; +}; diff --git a/tests/integration/i18n/mf-consumer/src/routes/[lang]/page.data.ts b/tests/integration/i18n/mf-consumer/src/routes/[lang]/page.data.ts new file mode 100644 index 000000000000..2d6f26824e0c --- /dev/null +++ b/tests/integration/i18n/mf-consumer/src/routes/[lang]/page.data.ts @@ -0,0 +1,9 @@ +import i18next from '../../i18n'; +export interface ProfileData { + /* some types */ + data: string; +} + +export const loader = async ({ params }: any): Promise => { + return { data: i18next.t('key', { lng: params.lang || i18next.language }) }; +}; diff --git a/tests/integration/i18n/mf-consumer/src/routes/[lang]/page.tsx b/tests/integration/i18n/mf-consumer/src/routes/[lang]/page.tsx new file mode 100644 index 000000000000..dd74f1f0e6e8 --- /dev/null +++ b/tests/integration/i18n/mf-consumer/src/routes/[lang]/page.tsx @@ -0,0 +1,26 @@ +import { createLazyComponent } from '@module-federation/modern-js/react'; +import { getInstance } from '@module-federation/modern-js/runtime'; +import { useTranslation } from 'react-i18next'; + +const RemoteSSRComponent = createLazyComponent({ + instance: getInstance(), + loader: () => import('componentRemote/Text'), + loading: 'loading...', + export: 'default', + fallback: ({ error }) => { + if (error instanceof Error && error.message.includes('not exist')) { + return
fallback - not existed id
; + } + return
fallback
; + }, +}); + +export default () => { + const { t } = useTranslation(); + return ( +
+ {t('key')} + +
+ ); +}; diff --git a/tests/integration/i18n/mf-consumer/src/routes/layout.tsx b/tests/integration/i18n/mf-consumer/src/routes/layout.tsx new file mode 100644 index 000000000000..16d79950aba1 --- /dev/null +++ b/tests/integration/i18n/mf-consumer/src/routes/layout.tsx @@ -0,0 +1,19 @@ +import { useModernI18n } from '@modern-js/plugin-i18n/runtime'; +import { Outlet } from '@modern-js/runtime/router'; + +export default function Layout() { + const { changeLanguage } = useModernI18n(); + return ( +
+
+ + +
+ +
+ ); +} diff --git a/tests/integration/i18n/mf-consumer/src/routes/remote/$.tsx b/tests/integration/i18n/mf-consumer/src/routes/remote/$.tsx new file mode 100644 index 000000000000..16b0e15dcec4 --- /dev/null +++ b/tests/integration/i18n/mf-consumer/src/routes/remote/$.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import RemoteApp from '../../components/RemoteApp'; + +export default (props: Record) => { + return ( +
+

远程应用页面

+ +
+ ); +}; diff --git a/tests/integration/i18n/mf-consumer/tsconfig.json b/tests/integration/i18n/mf-consumer/tsconfig.json new file mode 100644 index 000000000000..66f49dece30b --- /dev/null +++ b/tests/integration/i18n/mf-consumer/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "@modern-js/tsconfig/base", + "compilerOptions": { + "declaration": false, + "jsx": "preserve", + "baseUrl": "./", + "outDir": "dist", + "paths": { + "@/*": ["./src/*"], + "@shared/*": ["./shared/*"], + "*": ["./@mf-types/*"] + } + }, + "include": ["src", "tests", "modern.config.ts"] +} diff --git a/tests/integration/i18n/mf-provider/modern.config.ts b/tests/integration/i18n/mf-provider/modern.config.ts new file mode 100644 index 000000000000..97317c238e0b --- /dev/null +++ b/tests/integration/i18n/mf-provider/modern.config.ts @@ -0,0 +1,26 @@ +import { appTools, defineConfig } from '@modern-js/app-tools'; +import { i18nPlugin } from '@modern-js/plugin-i18n'; +import { moduleFederationPlugin } from '@module-federation/modern-js'; + +export default defineConfig({ + server: { + ssr: { + mode: 'stream', + }, + port: 3006, + }, + performance: { + buildCache: false, + }, + plugins: [ + appTools(), + i18nPlugin({ + localeDetection: { + localePathRedirect: true, + languages: ['zh', 'en'], + fallbackLanguage: 'en', + }, + }), + moduleFederationPlugin(), + ], +}); diff --git a/tests/integration/i18n/mf-provider/module-federation.config.ts b/tests/integration/i18n/mf-provider/module-federation.config.ts new file mode 100644 index 000000000000..a680e9191b21 --- /dev/null +++ b/tests/integration/i18n/mf-provider/module-federation.config.ts @@ -0,0 +1,25 @@ +import { createModuleFederationConfig } from '@module-federation/modern-js'; +import { dependencies } from './package.json'; + +export default createModuleFederationConfig({ + name: 'i18nComponentProvider', + filename: 'remoteEntry.js', + exposes: { + './Text': './src/components/Text.tsx', + }, + shared: { + react: { singleton: true, requiredVersion: dependencies.react }, + 'react-dom': { + singleton: true, + requiredVersion: dependencies['react-dom'], + }, + 'react-i18next': { + singleton: true, + requiredVersion: dependencies['react-i18next'], + }, + i18next: { + singleton: true, + requiredVersion: dependencies.i18next, + }, + }, +}); diff --git a/tests/integration/i18n/mf-provider/package.json b/tests/integration/i18n/mf-provider/package.json new file mode 100644 index 000000000000..6be3235dd4b9 --- /dev/null +++ b/tests/integration/i18n/mf-provider/package.json @@ -0,0 +1,22 @@ +{ + "private": true, + "name": "i18n-mf-provider", + "version": "2.66.0", + "scripts": { + "dev": "modern dev", + "build": "modern build" + }, + "dependencies": { + "i18next":"25.6.2", + "react-i18next": "15.7.4", + "@modern-js/runtime": "workspace:*", + "@modern-js/plugin-i18n": "workspace:*", + "@module-federation/modern-js": "0.0.0-feat-modern-3-0-20251120074204", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@modern-js/app-tools": "workspace:*", + "@modern-js/plugin-ssg": "workspace:*" + } +} diff --git a/tests/integration/i18n/mf-provider/src/components/Text.tsx b/tests/integration/i18n/mf-provider/src/components/Text.tsx new file mode 100644 index 000000000000..862bd291b766 --- /dev/null +++ b/tests/integration/i18n/mf-provider/src/components/Text.tsx @@ -0,0 +1,19 @@ +import { useTranslation } from 'react-i18next'; +import i18next from '../i18n'; +import styles from './text.module.css'; + +export default () => { + const { t } = useTranslation(); + return ( +
+
+ 🌐 + Remote Component +
+ {/** use i18next.t to get the key will use provider's i18n instance */} +

{i18next.t('key')}

+ {/** use useTranslation to get the key will use consumer's i18n instance */} +

{t('about')}

+
+ ); +}; diff --git a/tests/integration/i18n/mf-provider/src/components/text.module.css b/tests/integration/i18n/mf-provider/src/components/text.module.css new file mode 100644 index 000000000000..8ace6c687002 --- /dev/null +++ b/tests/integration/i18n/mf-provider/src/components/text.module.css @@ -0,0 +1,37 @@ +.text1 { + color: red; +} + +.text2 { + color: blue; +} + +.remoteBadge { + margin-top: 30px; + display: inline-flex; + align-items: center; + gap: 4px; + padding: 4px 8px; + background-color: rgba(0, 0, 0, 0.04); + border: 1px solid rgba(0, 0, 0, 0.08); + border-radius: 12px; + font-size: 0.75rem; + color: #666; + margin-bottom: 8px; + opacity: 0.7; + transition: opacity 0.2s ease; +} + +.remoteBadge:hover { + opacity: 1; +} + +.remoteIcon { + font-size: 0.875rem; + line-height: 1; +} + +.remoteText { + font-weight: 500; + letter-spacing: 0.01em; +} diff --git a/tests/integration/i18n/mf-provider/src/i18n.ts b/tests/integration/i18n/mf-provider/src/i18n.ts new file mode 100644 index 000000000000..bcb60f121938 --- /dev/null +++ b/tests/integration/i18n/mf-provider/src/i18n.ts @@ -0,0 +1,24 @@ +import originalI18next from 'i18next'; + +const i18next = originalI18next.createInstance(); + +i18next.init({ + lng: 'en', + fallbackLng: 'en', + resources: { + en: { + translation: { + key: 'Hello World(provider)', + about: 'About(provider)', + }, + }, + zh: { + translation: { + key: '你好,世界(provider)', + about: '关于(provider)', + }, + }, + }, +}); + +export default i18next; diff --git a/tests/integration/i18n/mf-provider/src/modern-app-env.d.ts b/tests/integration/i18n/mf-provider/src/modern-app-env.d.ts new file mode 100644 index 000000000000..d8912d28ef5a --- /dev/null +++ b/tests/integration/i18n/mf-provider/src/modern-app-env.d.ts @@ -0,0 +1,4 @@ +/// +/// + +declare module 'normalize-path'; diff --git a/tests/integration/i18n/mf-provider/src/modern.runtime.tsx b/tests/integration/i18n/mf-provider/src/modern.runtime.tsx new file mode 100644 index 000000000000..0cdd1c32a6f5 --- /dev/null +++ b/tests/integration/i18n/mf-provider/src/modern.runtime.tsx @@ -0,0 +1,8 @@ +import { defineRuntimeConfig } from '@modern-js/runtime'; +import i18next from './i18n'; + +export default defineRuntimeConfig({ + i18n: { + i18nInstance: i18next, + }, +}); diff --git a/tests/integration/i18n/mf-provider/src/routes/[lang]/about/page.tsx b/tests/integration/i18n/mf-provider/src/routes/[lang]/about/page.tsx new file mode 100644 index 000000000000..bc4ba4bd85d8 --- /dev/null +++ b/tests/integration/i18n/mf-provider/src/routes/[lang]/about/page.tsx @@ -0,0 +1,6 @@ +import { useTranslation } from 'react-i18next'; + +export default () => { + const { t } = useTranslation(); + return
{t('about')}
; +}; diff --git a/tests/integration/i18n/mf-provider/src/routes/[lang]/page.data.ts b/tests/integration/i18n/mf-provider/src/routes/[lang]/page.data.ts new file mode 100644 index 000000000000..2d6f26824e0c --- /dev/null +++ b/tests/integration/i18n/mf-provider/src/routes/[lang]/page.data.ts @@ -0,0 +1,9 @@ +import i18next from '../../i18n'; +export interface ProfileData { + /* some types */ + data: string; +} + +export const loader = async ({ params }: any): Promise => { + return { data: i18next.t('key', { lng: params.lang || i18next.language }) }; +}; diff --git a/tests/integration/i18n/mf-provider/src/routes/[lang]/page.tsx b/tests/integration/i18n/mf-provider/src/routes/[lang]/page.tsx new file mode 100644 index 000000000000..d1af9bd86904 --- /dev/null +++ b/tests/integration/i18n/mf-provider/src/routes/[lang]/page.tsx @@ -0,0 +1,17 @@ +import { useLoaderData } from '@modern-js/runtime/router'; +import type { ProfileData } from './page.data'; + +/** + * Note: In SSR scenarios, the data loader may not reflect language updates in time. + * This is because the execution order of data loaders and onBeforeRender differs between SSR and CSR: + * - In SSR: data loaders execute before onBeforeRender completes language detection/initialization + * - In CSR: onBeforeRender runs first, ensuring language is set before data loaders execute + */ +export default () => { + const profileData = useLoaderData() as ProfileData; + const data = profileData.data; + if (typeof data !== 'string') { + return
Loading...
; + } + return
{data}
; +}; diff --git a/tests/integration/i18n/mf-provider/src/routes/layout.tsx b/tests/integration/i18n/mf-provider/src/routes/layout.tsx new file mode 100644 index 000000000000..16d79950aba1 --- /dev/null +++ b/tests/integration/i18n/mf-provider/src/routes/layout.tsx @@ -0,0 +1,19 @@ +import { useModernI18n } from '@modern-js/plugin-i18n/runtime'; +import { Outlet } from '@modern-js/runtime/router'; + +export default function Layout() { + const { changeLanguage } = useModernI18n(); + return ( +
+
+ + +
+ +
+ ); +} diff --git a/tests/integration/i18n/mf-provider/tsconfig.json b/tests/integration/i18n/mf-provider/tsconfig.json new file mode 100644 index 000000000000..20bd5c24f7a7 --- /dev/null +++ b/tests/integration/i18n/mf-provider/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "@modern-js/tsconfig/base", + "compilerOptions": { + "declaration": false, + "jsx": "preserve", + "baseUrl": "./", + "outDir": "dist", + "paths": { + "@/*": ["./src/*"], + "@shared/*": ["./shared/*"] + } + }, + "include": ["src", "tests", "modern.config.ts"] +}