module-federation-examples icon indicating copy to clipboard operation
module-federation-examples copied to clipboard

Issue with Dynamic Chunk Loading in React Projects Using Webpack

Open CuriousDevX opened this issue 2 years ago • 5 comments

Hello,

I am encountering an issue with dynamic chunk loading in two React projects named Host and Remote1, both running on React version 18.2.0 and created using Create React App (CRA).

Overview of the Setup:

  1. Projects Configuration:
  • Both projects employ customize-cra and react-app-rewired to modify their configurations without ejecting. This is implemented through a config-overrides.js file at the root level of each project.
  • We have a build-config.js script that dynamically builds a JavaScript file, which is then added to the public folder as global environment variables. This file is imported in the public HTML file, enabling us to alter configurations dynamically (like changing remote component addresses or toggling components at runtime).
  1. Modules Exposed:
  • Host (http://localhost:3000/) exposes two modules:
    • AuthProvider: A wrapper that handles authentication for both the Host and remote apps.
    • preventCSSCollision: It manages CSS file tagging and enables/disables CSS files based on the active application.
  • Remote1 (http://localhost:3001/) is set to only share itself.

Issue Description:

  1. Primary Problem:
  • I encountered a chunk loading error when trying to load a chunk from the Remote1 component standalone. But it works inside the Host:

Error Message: Loading chunk vendors-node_modules_css-loader_dist_runtime_api_js-node_modules_css-loader_dist_runtime_sour-d924d0 failed. (missing: http://localhost:3001/static/js/vendors-node_modules_css-loader_dist_runtime_api_js-node_modules_css-loader_dist_runtime_sour-d924d0.chunk.js)

  1. Configuration Attempts:
  • Setting config.output.publicPath = '/' in config-overrides.js ensures the Host application works correctly, but standalone Remote applications throw errors.
  • Setting config.output.publicPath = 'auto' allows sub-routes of the remote component on the Host to function, but refreshing these pages results in failures (e.g., http://localhost:3000/remote1/page1).
  • Attempts to set config.output.publicPath dynamically using webpack_public_path = window.location.origin + '/' have been unsuccessful.

Steps to Reproduce:

For a clearer understanding, I have created a simplified version of the projects and uploaded it to GitHub: dynamic-wmf-demo.

I would greatly appreciate any insights or suggestions on how to resolve this issue.

Thank you for your time and assistance.

CuriousDevX avatar Nov 22 '23 16:11 CuriousDevX

I updated to code and examples of what I tried to solve problems to make it more clear.

Expected Behavior

- We should able to load Host and Remote1 standalone without error.
- We should able to browse Remote1 application sub routes on Host. 
Example : http://localhost:3000/remote1/page2
- We should able to refresh the page while browse Remote1 applications sub routes on Host.
Example : http://localhost:3000/remote1/page3 (Hit refresh)

Problem

  1. If config.output.publicPath = '/':

    Browsing sub routes are work on the Host application including refreshing page while on sub routes but remote applications standalone throws error.

    Error : Uncaught SyntaxError: Unexpected token '<'

  2. If config.output.publicPath = 'auto',

    While browsing sub routes on the Host and Remote1 works but when you on sub route on Host and refreshing the page causes error.

    Error : Uncaught SyntaxError: Unexpected token '<'

  3. If we set config.output.publicPath = 'http://localhost:3000/' everything works but it's not dynamic.

    • Instead of setting publicPath in config-overrides.js we can try to set webpack_public_path variable dynamically. We cerate a file ./src/dynamicPublicPath.ts with below content and import as very first item inside the entry point of Host app;

      webpack_public_path = window.location.origin + '/'

    • Also tried to set config.output.publicPath = 'auto', '/' with ./src/dynamicPublicPath.ts. Result is same with previous attempts.

CuriousDevX avatar Nov 24 '23 15:11 CuriousDevX

You might be able to set this with html attributes like base or something in the head tag to let browser know what base url is.

I cant remember the exact but theres a html head attr for setting base url.

We will be releasing a new version of federation soon. module-federation/universe repo is where you can track progress. In there youll have direct control over the MF lifecycle via runtime hooks and plugins for end users to enjoy

ScriptedAlchemy avatar Nov 27 '23 06:11 ScriptedAlchemy

Hello @ScriptedAlchemy, thank you for your suggestion. I attempted to implement a static tag in the head section of Remote1's HTML file, but unfortunately, it didn't resolve the issue. Additionally, I'm concerned about how this method might affect the internal URL handling within the application. Do you have any other recommendations or insights that might help with this specific scenario?

CuriousDevX avatar Nov 27 '23 11:11 CuriousDevX

if you cant do base path then youll have to use hard coded public paths for the time being. Check back once we release a new iteration of the plugin or finalize the runtime.

I have other options but they are complex and soon to be deprecated. We are adding middleware to MFP so you can have more control over it. But this nested issue is a problem only for the host.

ScriptedAlchemy avatar Nov 30 '23 23:11 ScriptedAlchemy

Thank you, seems like I have to wait for the middleware.

CuriousDevX avatar Dec 01 '23 12:12 CuriousDevX

module-federation.io

ScriptedAlchemy avatar Apr 29 '24 01:04 ScriptedAlchemy