skip to Main Content

Let’s assume I have several single-spa react microfrontend apps in my project, e.g. Cart and Products

I want to redefine console.log, console.error, etc. so that it had prefix with appropriate microfrontend app name:

  • console.log invoked from Cart app: [Cart]: some log info

  • console.log invoked from Products app: [Products]: some log info

Is it possible to achieve this behavior?

I thought of zone.js, but the execution context is not being passed to component’s children:

import type React from 'react';
import 'zone.js';

export const withLogger = (
  Component: React.ReactElement,
  regionName: string
): React.ReactElement =>
  Zone.current
    .fork({
      name: regionName
    })
    .run(() => {
      const consoleLogOG = console.log;
      window.console.log = (...args): void => {
        const newArgs = [`[${Zone.current.name}]`, ...args];
        consoleLogOG.apply(console, newArgs);
      };

      return Component;
    });

UPD: I want to create out of the box solution for about 20 microfronts, so I don’t want to move from standard console.log to any custom logger. Ideally, I want to create some kind of a HOC which will redefine console.log for all of the calls within wrapper’s subtree (execution context)

2

Answers


  1. it is not possible to make zone.js work in a situation where multiple microfrontends are being used with single-spa. This is because all of the microfrontends share the same environment and zone.js cannot handle this dynamic change.

    one possible way would be to create a new function for logging that takes in a specific name for each microfrontend and includes it in the log message. Then, instead of using console.log, each microfrontend can use this new function for logging. This will help differentiate the logs from each microfrontend.

    // Custom logging function
    const customLog = (regionName, ...args) => {
      const newArgs = [`[${regionName}]:`, ...args];
      console.log.apply(console, newArgs);
    };
    
    // In your Cart microfront, you can use the custom log function like this:
    customLog("Cart", "foo");
    
    // In your Products microfront, you can use it like this:
    customLog("Products", "foo");
    

    Basically, instead of having all the log messages mixed together in a single file, we can organize them into separate files for each microfront. This will help us easily identify which microfront the log messages belong to by adding the region name before the message. It’s like each microfront has their own little diary, but with their name on the cover so we know whose diary it is.

    Login or Signup to reply.
  2. // HOC that wraps each microfront
    const withLogger = (Component, regionName) => {
      const log = console.log;
    
      return (props) => {
        return <Component {...props} customLog={(...args) => log(`[${regionName}]:`, ...args)} />
      };
    };
    
    // using the HOC in a microfront app
    const App = (props) => {
      const { customLog } = props;
    
      // This customLog prop will now be available and can be used
      customLog("foo");
    
      // other code
    };
    
    export default withLogger(App, "Products"); // App will now be wrapped with the HOC and have access to the customLog prop with the appropriate region name.
    

    note: you have to consider how to handle asynchronous functions and error logging in a similar way. thoroughly test

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search