Giter Club home page Giter Club logo

module-federation-react-router-dom's Introduction

Hi there ๐Ÿ‘‹

nebarf's Linkdein nebarf's Github

About me

๐Ÿ’ป Senior JS/TS Software Engineer

๐Ÿ”ญ Currently working @ Facile.it website

๐ŸŒฑ OSS contributor

๐Ÿ’ก Always looking for new software architecture trends


Tech Languages and Tools

TypeScript logo JavaScript logo React logo Next.js logo Angular logo Node.js logo Fastify logo Express.js logo NestJS logo Rust logo



nebarf's github stats

module-federation-react-router-dom's People

Contributors

nebarf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

module-federation-react-router-dom's Issues

Dynamic Remote Modules

How would you go about using this solution with dynamic remote modules?

I need to configure dynamic remote modules to handle deploying to different environments. Most implementations I've seen pull the remote URLs from either a static manifest or an API and import them using React.lazy. That doesn't play nicely with the use of the mount function here.

I've tried something like this but it doesn't seem to work properly. Any suggestions?

Remote app bootstrap.tsx:

import { useRef, useEffect } from 'react';
import { createRoot } from 'react-dom/client';
import { RouterProvider, useLocation, useNavigate } from 'react-router-dom';

import { createRouter } from './app/routing/router-factory';
import { RoutingStrategy } from './app/routing/types';

const mount = ({
  mountPoint,
  initialPathname,
  routingStrategy,
}: {
  mountPoint: HTMLDivElement;
  initialPathname?: string;
  routingStrategy?: RoutingStrategy;
}) => {
  const router = createRouter({ strategy: routingStrategy, initialPathname });
  const root = createRoot(mountPoint);
  root.render(<RouterProvider router={router} />);

  return () => queueMicrotask(() => root.unmount());
};

const RemoteApp1 = ({ initialPathname }: any) => {
  const wrapperRef = useRef<HTMLDivElement>(null);
  const navigate = useNavigate();
  const location = useLocation();

  useEffect(() => {
    const remoteAppNavigationEventHandler = (event: Event) => {
      const pathname = (event as CustomEvent<string>).detail;
      const newPathname = `${initialPathname}${pathname}`;
      if (newPathname === location.pathname) {
        return;
      }
      navigate(newPathname);
    };
    window.addEventListener(
      '[RA1] navigated',
      remoteAppNavigationEventHandler 
    );

    return () => {
      window.removeEventListener(
        '[RA1] navigated',
        remoteAppNavigationEventHandler 
      );
    };
  }, [location]);

  useEffect(() => {
    if (location.pathname.startsWith(initialPathname)) {
      window.dispatchEvent(
        new CustomEvent('[host] navigated', {
          detail: location.pathname.replace(initialPathname, ''),
        })
      );
    }
  }, [location]);

  const isFirstRunRef = useRef(true);
  const unmountRef = useRef(() => {});

  useEffect(() => {
    if (!isFirstRunRef.current) {
      return;
    }
    unmountRef.current = mount({
      mountPoint: wrapperRef.current!,
      initialPathname: location.pathname.replace(initialPathname, ''),
    });
    isFirstRunRef.current = false;
  }, [location]);

  useEffect(() => unmountRef.current, []);

  return <div ref={wrapperRef} id="remote-app-1" />;
};

export default RemoteApp1;

Host component RemoteApp1.tsx:

import { loadRemoteModule } from './load-remote-module';
import { lazy, Suspense } from 'react';

import { REMOTE_APP_1_ROUTING_PREFIX } from '../routing/constants';

const remoteApp1Basename= `/${REMOTE_APP_1_ROUTING_PREFIX}`;

const RemoteApp1Module = lazy(() =>
  loadRemoteModule('remote-app-1', './Module')
);

const RemoteApp1 = () => {
  return (
    <Suspense>
      <RemoteApp1Module initialPathname={remoteApp1Basename} />
    </Suspense>
  );
};

export default RemoteApp1 ;

Issue with child routes - MemoryRouter combining independent app route paths

@nebarf I've been testing the new code and ran into an issue and not sure how to solve it.

When changing the children path in app1 to only have a "page-1" and "page-3" (eliminate page 2 completely and update all references from page-2 to page-3 in app1 and shell)

app1>src>routing>routes.tsx
...
- path: "page-2",
+ path: "page-3",

there is a console warning upon navigating to app2/page-2: No routes matched location "/page-2".
Upon navigating back to app1/page-3 there is another console warning: No routes matched location "/page-3".

Navigation works fine in both scenarios.

app1>src>routing>routes.tsx
path: "/",
    element: (
      <NavigationManager>
        <Outlet /> # <== is issue here?
      </NavigationManager>
    ),

I am not that familiar with the NavigationManager for App1 but I'm wondering if this is caused by both routes for app1 and app2 being combined with createMemoryRouter.

So app2 is expecting a child route for app2/page-3 and app1 is expecting a child route for app1/page-2? If so is there a way to separate the routes so that each app only references its own routes?

How to navigate from app1 to app2

Hello, I have done setup by referring this repository.
How can navigate from app1 to app2 without reloading like single page routing

Module not found: Error: Can't resolve 'history' in '/app/src'

Issue: The project uses react-router-dom v6.3 which removed history as a dependency.

When creating node modules from scratch using package.json file the history module is not installed which throws the above error from the "app1/app2 > src > bootstrap.tsx" & "shell > src > routing > constants.ts" files.

In looking at documentation for react-router-dom upgrade from v5 to v6 it mentions removing history from the package.json as an upgrade step:

Upgrade to v6 Guide

"You'll also want to remove the history dependency from your package.json. The history library is a direct dependency of v6 (not a peer dep), so you won't ever import or use it directly. Instead, you'll use the useNavigate() hook for all navigation"

By chance did your node_modules still contain the old reference to the history module enabling the old import from 'history' to work?

This is a nice implementation of the MFE course from Stephen Grider.

Although you could install the history module v5.3 as a hack - since RRD v6 is designed to work with useNavigate() have you found a way to get the history to work with upgraded navigation without reinstalling the history module?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.