Skip to content

Support Modern.js SSR #2348

@2heal1

Description

@2heal1

Changelog 2024-05-22:draft
Implementation PR  WIP...

Summary

Module Federation supports Modern.js SSR , includes stream ssr and string ssr two modes.

Basic example

  • Static remote (register remotes in build config)
// config
new ModuleFederation({
  remotes: {
    remote: 'remote@http://localhost:3001/mf-manifest.json'
  }
})

// usage
import Comp from 'remote/Content'
  • Dynamic remote(register remotes in runtime)
import React, { Suspense } from 'react';
import Button from 'antd/lib/button';
import {
  loadRemote,
  registerRemotes,
} from '@module-federation/enhanced/runtime';

registerRemotes([
  {
    name: 'dynamic_remote',
    entry: 'http://localhost:3008/mf-stats.json',
  },
]);

const Comp = React.lazy(() =>
loadRemote('dynamic_remote/Image').then((m) => {
    return m;
  }),
);

export default (): JSX.Element => (
  <Suspense fallback={'loading'}>
    <Comp />
  </Suspense>
);

Motivation

  • Optimize first screen performance
  • Support ssr can help to investigate more performance optimization ways

Detailed design

Update stats/manifest/snapshot

Stats/Manifest

Add ssr related fields

// metaData
interface BasicStatsMetaData {
+ ssrRemoteEntry?: ResourceInfo;
}

Snapshot

Add ssr related fields

interface BasicProviderModuleInfo extends BasicModuleInfo {
  // ssrRemoteEntry/ssrRemoteEntryType only appear while manifest has serveSideRemoteEntry field
+ ssrRemoteEntry?: string;
+ ssrRemoteEntryType?: RemoteEntryType
}

render mode

only support stream ssr mode

CSS flickering issue

Leverage mf-stats.json , we can easily get the module css assets, and insert them to html

// encapsulation component for users
const Comp = React.lazy(() =>
  loadRemote('dynamic_remote/Image').then((m) => {
    return {
      default:()=><div>
        <link href='http://localhost:3008/static/css/async/__federation_expose_Image.css' rel="stylesheet" type="text/css" />
        <span>11</span>
        <m.default />
      </div>
    };
  }),
);

Cache Strategy

For static remote , there won't be any serious problems. But for dynamic remotes , it may add endless dynamic remotes , and cause memory crashes.

To avoid the issue , it needs to add LRU cache:

  • Delete the reference of least usage mf instance, include the shared and expose modules

Data Fetch

Use Modernjs Data loader

Downgrade strategy

Provide two ways to help CSR cab work normally while SSR failed

  1. Use the runtime version plugin to downgrade the latest available modules
  • runtime version plugin: allows users downgrade specific fallback modules while the entry can not get normally
  1. Provide encapsulation component for users which provide fallback

Dev

LiveReload

fetch all loaded remotes before render host , and judge whether remoteEntry content hash has changed . If yes , flush chunks .

import type { Plugin } from '@modern-js/runtime';

export const mfPluginSSR = (): Plugin => ({
  name: '@module-federation/modern-js',

  setup: () => ({
    async init({ context }, next) {
      if (typeof window !== 'undefined') {
        return next({ context });
      }
      const nodeUtils = await import('@module-federation/node/utils');
      const shouldUpdate = await nodeUtils.revalidate();
      if (shouldUpdate) {
        console.log('should HMR', shouldUpdate);
      }
      return next({ context });
    },
  }),
});

Dynamic remote type hints

notify local broker server while calling loadRemotes , and then the broker server will have the full relationship .

import type { FederationRuntimePlugin } from '@module-federation/enhanced/runtime';

const notifyDynamicRemotePlugin: () => FederationRuntimePlugin = () => ({
  name: 'notify-dynamic-remote-plugin',
  loadRemote(args) {
    if(isDynamicRemote(args)){
        notifyBrokerServer(args.remote);
    }
    return args;
  },
});
export default notifyDynamicRemotePlugin;

debug

Because node server can not access local env , so not support yet.

It will auto forceCSR when accepting the debug info:

  • Chrome devtools
  • Skip collect downgrade rate

Drawbacks

  • Only support stream ssr , it means that react under version 18 is not supported

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions