Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with dynamic route when reloading application with RSBuild and MF v2 #3343

Open
5 tasks done
petrosD93 opened this issue Dec 11, 2024 · 8 comments
Open
5 tasks done

Comments

@petrosD93
Copy link

Describe the bug

I have created a POC to test out the configuration of RSBuild and Module Federation v2. Everything was working fine and I managed to expose the remote so it can be consumed by another app.

This was achieved by the following RSBuild configuration:

{
  plugins: [
    pluginReact({ splitChunks: { react: false, router: false } }),
    pluginSass({
      sassLoaderOptions: {
        sassOptions: {
          silenceDeprecations: ['import', 'global-builtin', 'abs-percent', 'color-functions', 'mixed-decls'],
        },
      },
    }),
  ],
  html: {
    template: path.resolve(process.cwd(), 'public/index.html'),
  },
  server: {
    port: 3001,
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
  },
  tools: {
    rspack: {
      plugins:[
        new ModuleFederationPlugin(
          {
    name: 'remote',
    filename:'remoteAppEntry.js',
    exposes: {
        './button': './src/button.tsx',
        './getItem': './src/util.ts',
    },
    shared: ['react', 'react-dom'],
    runtimePlugins: [require.resolve('./offline-remote.js')],

    }
     ),
      ],
      output: {
        publicPath: 'auto',
      },
    },
  },
  output: {
    distPath: {
      root: 'build',
    },
  },
}

Now everything was working fine, until I introduced a dynamic route to my React Router.

{
    path: '/',
    element: <Outlet />,
    errorElement: <RouteErrorBoundary/>,
    children: [

        {
            path:":realm",
            element: <App/>,
            children:[
                {
                    path:"route2",
                    element: <div>test</div>
                },
                {
                    path:"route1",
                    element: <Home/>
                }
            ]
        },

    ],
}

The issue is that when my browser is at localhost:3001/something/route2 and I hit refresh, the application breaks with the following error and a white page is displayed:

Screenshot 2024-12-11 at 9 26 43 AM

If my browser is at localhost:3001/something and I hit refresh, everything works fine.

I do believe that this has to do with the rsbuild configuration and the publicPath: 'auto', however this is required in order to expose the application and consume it by the host.

Is there a way to bypass the above issue?
Also maybe it would be a good idea to include a working example of Module Federated apps with React and React Router using dynamic routes as this is a very common setup

Reproduction

https://github.com/petrosD93/rspack-remote.git

Used Package Manager

npm

System Info

System:
    OS: macOS 15.1
    CPU: (8) arm64 Apple M1 Pro
    Memory: 84.83 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.11.0 - ~/.nvm/versions/node/v22.11.0/bin/node
    npm: 10.9.0 - ~/.nvm/versions/node/v22.11.0/bin/npm
  Browsers:
    Chrome: 131.0.6778.109
    Safari: 18.1

Validations

@petrosD93
Copy link
Author

@ScriptedAlchemy The above occurs when we have publicpath set to auto. If we have publicpath set to '/' the application works but the host breaks! Any suggestion for this?

@petrosD93
Copy link
Author

Update: Issue is with children routes and not the dynamic route... If we have all routes on the same level everything is fine... if not when refreshing a child route, the browser tries to resolve the static files with:

http://localhost:3001/some/static/js/vendors-node_modules_rspack_plugin-react-refresh_client_reactRefreshEntry_js-_module-federati-74bf07.js

where some is the parent route, in this example the dynamic one.

@ScriptedAlchemy
Copy link
Member

Use getPublicPath instead.

@ScriptedAlchemy
Copy link
Member

Or set base meta tag in your head

@petrosD93
Copy link
Author

petrosD93 commented Dec 12, 2024

Or set base meta tag in your head

This seems to work and I can dynamically set my base ref in my index.html using

     <script>
            // Create and append the base tag before importing bootstrap
            const base = document.createElement('base');
            base.href = window.location.origin;
            document.head.appendChild(base);
      </script>

However, shouldn't this be handled by rspack when setting publicPath: 'auto'?

Also, we can now see two entries in network.. One going to http://localhost:3001/some/static/js/vendors-node_modules_rspack_plugin-react-refresh_client_reactRefreshEntry_js-_module-federati-74bf07.js

and the other one going to http://localhost:3001/static/js/vendors-node_modules_rspack_plugin-react-refresh_client_reactRefreshEntry_js-_module-federati-74bf07.js

Is this the expected behavior?

@ScriptedAlchemy
Copy link
Member

no it shouldnt, compiler is not a framework.

setting base can cause issues.

alternatively, use getPublicPath option or hard code them

@petrosD93
Copy link
Author

no it shouldnt, compiler is not a framework.

setting base can cause issues.

alternatively, use getPublicPath option or hard code them

I agree with the statement that compiler is not a framework but it feels like that I am missing something. In the example of 2 react apps (one host and one remote), setting publicPath: 'auto' in rspack config, works!

One would expect that this configuration will keep working even if a nested route is introduced on the remote. What am I missing here with the nested route? Why do we have different behavior between the scenarios of just having single routes vs nested routes? Is it something with the devServer?

In our previous configurations with Webpack5, setting publicPath: 'auto' was working for both scenarios (single routes and nested routes).

I do want to explore the getPublicPath option, that you mentioned, however I am struggling a bit with understanding the context of it given the documentation here.

Where should the getPublicPath be configured? On the remote mf config or the host? And what does it actually do? I tried to configure

getPublicPath: `function() {return "http://localhost:3001/"}`

on the remote mf confing and also leaving rspack publicPath: 'auto' but this does not solve the issue of reloading a nested route!
Should it be the other way around? Should we have rspack publicPath: '/' with setting also getPublicPath in mf config?

Apologies for the long question, I am just trying to understand how I can correctly configure this setup. I do know that this might not be the correct place to post such questions so feel free to direct me to the correct channels or people where we can join knowledge to address this and finally come up with an example repo for react and nested routes for module federation.

@ScriptedAlchemy
Copy link
Member

play around with it and see.

https://module-federation.io/configure/getpublicpath.html

most likely would be on the remote side since they are the ones using auto to figure out base paths

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants