”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 使用 Rspack 和 Modern.js 的微前端

使用 Rspack 和 Modern.js 的微前端

发布于2024-11-04
浏览:355

Photo by Markus Spiske on Unsplash

Introduction

Web developers are beginning to take a strong interest in the idea of Micro-Frontends. Remix and Next.js are two examples of React meta-frameworks that have a lot of useful capabilities, but they don't always give complete support for creating micro-frontends. By providing built-in support for micro-frontends, Modern.js fills this gap and enables developers to design modular, scalable, and flexible apps.

Modern.js Framework

ByteDance created Modern.js, a progressive web framework built on React. Giving developers an outstanding development experience and empowering applications to provide better user experiences simplifies the process of creating contemporary web applications. In addition to having built-in state management, data gathering, and routing capabilities, Modern.js offers all required setups and tools for React applications.

Key features of Modern.js include:

  • Rust Bundler: The primary bundler is Rspack, however, it can be switched to Webpack.
  • Progressive: Facilitates the incremental integration of features via templates and plugins.
  • Integration: Offers isomorphic CSR and SSR development in a unified development and production environment.
  • Out of the Box: Provides debugging tools, ESLint, default TypeScript support, and integrated build tools.
  • Ecology: Module packaging, micro-frontend support, and integrated state management.
  • Routing Modes: Allows for file-convention-based and self-controlled routing.
  • With integrated micro-frontend functionality, Modern.js facilitates scalable, maintainable, and flexible apps while streamlining the development process.

Rspack

Rspack is a high-performance JavaScript bundler written in Rust, designed to be compatible with the webpack ecosystem while providing significantly faster build speeds.

Why Rspack?
Rspack was created to solve performance issues at ByteDance, where large app projects had excessively long build and startup times. Rspack addresses these problems with:

  • Fast Dev Mode Startup: Ensures quick startup to maintain developer productivity.
  • Quick Builds: Reduces CI/CD pipeline build times, improving productivity and application delivery.
  • Flexible Configuration: Maintains webpack's flexibility, easing the transition for legacy projects.
  • Optimized Production Builds: Enhances production optimizations with Rust's multithreading capabilities.

Let's start

This guide will walk us through setting up a Modern.js project, enabling micro-frontend capabilities, and configuring multiple applications to work together seamlessly. We will use pnpm as our package manager and Rspack as the bundler. The shell app will act as the main application that dynamically loads micro-frontends.

Step-by-Step Instructions

1. Initialize the Repository
Start by initializing a new pnpm project in the root directory.

pnpm init

This will create a package.json file to manage dependencies and scripts for your project.

2. Create the Shell Application
Next, create the shell application using Modern.js.

npx @modern-js/create@latest shell-app

( Note: npx @modern-js/create@latest will also commit new changes. So you might have to manually remove .git folder and keep it only on the top level: rm -rf .git )

Select the following options:

  • Project type: Web App
  • Programming language: TS (TypeScript)
  • Package manager: pnpm

  • In the latest versions, Rspack is used as the default bundler.

3. Run the Shell Application
Navigate into the shell application directory and start the development server.

cd shell-app
pnpm start

Running the application ensures everything is set up correctly. You should see the default Modern.js application running in your browser.

4. Enable Micro-frontend Features
Enable micro-frontend features for the shell application.

pnpm run new

Select the following options:

  • Operation: Enable Features
  • Feature: Enable Micro Frontend

Enabling micro-frontend features configures the project to support dynamic loading and micro-frontend integration, allowing us to build modular and scalable applications.

5. Update modern.config.ts
Modify the configuration file to include necessary plugins and runtime settings.

// shell-app/modern.config.ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { garfishPlugin } from '@modern-js/plugin-garfish';

export default defineConfig({
  runtime: {
    router: true,
    state: true,
    masterApp: {},
  },
  plugins: [appTools(), garfishPlugin()],
});

This configuration enables the router and sets up the shell app as a main application using the garfishPlugin.
(Garfish, developed by the ByteDance team, is a micro-frontend framework similar to single-spa. Modern.js handles the rest under the hood, so we don't need to focus much on it.)

6. Create Custom Entry and Update App.tsx
Remove the default routes folder and create a new App.tsx file in the src directory.

// shell-app/src/App.tsx
import { Suspense } from 'react';
import { defineConfig } from '@modern-js/runtime';
import {
  BrowserRouter as Router,
  Routes,
  Route,
} from '@modern-js/runtime/router';
import styled from '@modern-js/runtime/styled';

const AppContainer = styled.div`
  text-align: center;
  padding: 20px;
  background-color: #f5f5f5;
`;

const Title = styled.h1`
  color: #333;
`;

const Loading = styled.div`
  font-size: 1.2em;
  color: #666;
`;

const App: React.FC = () => {
  return (
    
      
        Loading...}>
          
            Welcome to the Shell Application}
            />
          
        
      
    
  );
};

export default defineConfig(App, {
  masterApp: {
    manifest: {
      getAppList: async () => {
        // here we will add our mfe
        return [];
      },
    },
  },
});

Here, we set up the main component for the shell application, configuring it as the master application that will manage micro-frontends.

7. Create the First Micro-frontend Application
Navigate back to the root directory and create the first micro-frontend.

cd ..
npx @modern-js/create@latest mfe1

Select the following options:

  • Project type: Web App
  • Programming language: TS (TypeScript)
  • Package manager: pnpm

8. Enable Micro-frontend Feature for mfe1
Enable micro-frontend features for the first micro-frontend application.

cd mfe1
pnpm run new

Select the following options:

  • Operation: Enable Features
  • Feature: Enable Micro Frontend

9. Update modern.config.ts for mfe1
Update the configuration file for the micro-frontend.

// mfe1/modern.config.ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { garfishPlugin } from '@modern-js/plugin-garfish';

export default defineConfig({
  server: {
    port: 8081,
  },
  deploy: {
    microFrontend: true,
  },
  plugins: [appTools(), garfishPlugin()],
});

This configuration sets the port and enables micro-frontend features.

10. Create Custom Entry and Update App.tsx for mfe1
Remove the default routes folder and create a new App.tsx file in the src directory.

// mfe1/src/App.tsx
import React from 'react';
import {
  BrowserRouter as Router,
  Routes,
  Route,
  Link,
} from '@modern-js/runtime/router';
import styled from '@modern-js/runtime/styled';

const Container = styled.div`
  font-size: 1.2em;
  color: #333;
`;

const AppContainer = styled.div`
  text-align: center;
  padding: 20px;
  background-color: #f5f5f5;
`;

const NavBar = styled.nav`
  margin-bottom: 20px;
  a {
    margin: 0 10px;
    color: #007acc;
    text-decoration: none;
  }
`;

const Contact: React.FC = () => {
  return Contact Page;
};

const Home: React.FC = () => {
  return Home Page;
};

const About: React.FC = () => {
  return About Page;
};

const App: React.FC = () => {
  return (
    
      
        
          Home
          About
          Contact
        
        
          } />
          } />
          } />
        
      
    
  );
};

export default App;

Here, we set up the micro-frontend application with its routes and navigation.

11. Update the Root package.json
Add a start script in the root package.json to run both the shell app and the micro-frontend simultaneously.

{
  "name": "micro-frontends-with-modern.js-and-rspack",
  "version": "1.0.0",
  "description": "",
  "scripts": {
     "start": "pnpm --filter shell-app --filter mfe1 --parallel start"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

12. Update App.tsx in shell-app to Load mfe1
Modify the App.tsx file in the shell application to dynamically load and integrate the micro-frontend.

// shell-app/src/App.tsx
import React, { Suspense } from 'react';
import { useModuleApps } from '@modern-js/plugin-garfish/runtime';
import { defineConfig } from '@modern-js/runtime';
import {
  BrowserRouter as Router,
  Routes,
  Route,
  Link,
} from '@modern-js/runtime/router';
import styled from '@modern-js/runtime/styled';

const AppContainer = styled.div`
  text-align: center;
  padding: 20px;
  background-color: #f5f5f5;
`;

const Title = styled.h1`
  color: #333;
`;

const Loading = styled.div`
  font-size: 1.2em;
  color: #666;
`;

const App: React.FC = () => {
  const { MApp } = useModuleApps();
  return (
    
      
        Welcome to the Shell Application
        Loading...}>
          
          
            
                  
MFE1
> } />
); }; export default defineConfig(App, { masterApp: { manifest: { getAppList: async () => { return [ { name: 'mfe1', entry: 'http://localhost:8081/index.js', activeWhen: path => path.includes('mfe1'), }, ]; }, }, }, });

The useModuleApps hook returns sub-app components and gives us full control of routing.

13. Run Both Applications
Navigate back to the root directory and run the start script to launch both applications.

pnpm start

This command will start both the shell-app and mfe1 concurrently, allowing you to access mfe1 inside the shell-app and navigate its subroutes.

Vertical vs Horizontal splits for micro-frontends

We looked at the vertical split of micro-frontends in the previous section. The horizontal divide with module federation will be discussed in the following section. What do these splits indicate, though?

A horizontal split is a pattern in which various application components—manufactured by separate teams—are merged into a single view or path. Every team is in charge of particular features or portions of the page, which are then smoothly integrated. Because teams may operate independently without impacting the program as a whole, this enables parallel development and speedier deployment.

On the other hand, a vertical split separates the application into discrete micro-frontends, each in charge of a separate feature or area of the system as a whole. These micro-frontends operate as distinct, feature-rich programs that can be accessed via several URLs. Because each micro-frontend can be designed, deployed, and updated individually, this approach improves modularity and scalability.

Micro-frontends with Rspack and Modern.js

Adding mfe2 with Module Federation for Horizontal Split

This section will create mfe2 using Module Federation, focusing on a horizontal split. This means mfe2 will handle a specific part of the application's UI, such as a shared component or feature, that can be dynamically loaded and shared across different parts of the shell application.

1. Create the Second Microfrontend Application
Navigate back to the root directory and create the second micro-frontend ( since it's module-federation we can use not only Modern.js ):

cd ..
npx @modern-js/create@latest mfe2

Select the following options:

  • Project type: Web App
  • Programming language: TS (TypeScript)
  • Package manager: pnpm

2. Update modern.config.ts for mfe2
Update the configuration file to include module federation settings.
We added some additional configurations to make module federation work with Modern.js. You can use a regular React app with Rspack instead of Modern.js as well. Additional examples you can find here module-fedration examples.

// mfe2/modern.config.ts
import { appTools, defineConfig } from '@modern-js/app-tools';

export default defineConfig({
  server: {
    port: 8082,
  },
  source: {
    enableAsyncEntry: true,
  },
  plugins: [appTools({ bundler: 'rspack' })],
  tools: {
    rspack: (config, { rspack, appendPlugins }) => {
      // just to remove noise form ts
      if (config.output) {
        config.output.publicPath = 'auto';
        config.output.uniqueName = 'mfe2';
      } else {
        config.output = {
          publicPath: 'auto',
          uniqueName: 'mfe2',
        };
      }

      if (config.optimization) {
        delete config.optimization.splitChunks;
        delete config.optimization.runtimeChunk;
      }

      appendPlugins([
        new rspack.container.ModuleFederationPlugin({
          name: 'mfe2',
          library: { type: 'var', name: 'mfe2' },
          filename: 'static/js/remoteEntry.js',
          exposes: {
            './MFE2Component': './src/MFE2Component.tsx',
          },
          shared: {
            react: { singleton: true },
            'react-dom': { singleton: true },
          },
        }),
      ]);
    },
  },
});

3. Create MFE2Component
Create a new component that will be exposed via module federation.

// src/MFE2Component.tsx
import React from 'react';
import styled from '@modern-js/runtime/styled';

const Container = styled.div`
  font-size: 1.2em;
  color: #007acc;
`;

const MFE2Component: React.FC = () => {
  return This is MFE2 Component!;
};

export default MFE2Component;

4. Update the Shell App modern.config.ts
We need to add module fedration configuration in the Shell App to consume what mfe2 produce.

import { appTools, defineConfig } from '@modern-js/app-tools';
import { garfishPlugin } from '@modern-js/plugin-garfish';

export default defineConfig({
  runtime: {
    router: true,
    state: true,
    masterApp: {},
  },
  source: {
    // automatically generated asynchronous boundary via Dynamic Import, allowing the page code to consume remote modules generated by the module federation.
    enableAsyncEntry: true,
  },
  output: {
    disableTsChecker: true,
  },
  tools: {
    rspack: (config, { rspack, appendPlugins }) => {
      appendPlugins([
        new rspack.container.ModuleFederationPlugin({
          name: 'host',
          remotes: {
            mfe2: 'mfe2@http://localhost:8082/static/js/remoteEntry.js',
          },
          shared: {
            react: { singleton: true },
            'react-dom': { singleton: true },
          },
        }),
      ]);
    },
  },
  plugins: [
    appTools({
      bundler: 'rspack',
    }),
    garfishPlugin(),
  ],
});

5. Update the Shell App to Load mfe2
Update the App.tsx in the shell-app to dynamically load mfe2.

// shell-app/src/App.tsx
...
import MFE2Component from 'mfe2/MFE2Component';
...
 Welcome to the Shell Application
 

In this updated App.tsx, we've added a link to mfe2 and included it in the manifest configuration.

6. Run Both Applications
Navigate back to the root directory, and update the script.

// package.json
...
"scripts": {
    "start": "pnpm --filter shell-app --filter mfe1  --filter mfe2 --parallel start"
  },
...

Run the start script to launch all applications.

pnpm start

This command will start both the shell-app, mfe1, and mfe2 concurrently, allowing you to access mfe2 inside the shell-app and navigate its subroutes.

Conclusion

We have barely scratched the surface of Modern.js by concentrating on just a couple of its features: integrated micro-frontend capabilities and module federation using Rspack. This is merely a simple illustration to help you get ideas for using Modern.js and creating micro-frontends for your applications.

? Find the code for this article on GitHub.

版本声明 本文转载于:https://dev.to/kyrylobashtenko/micro-frontends-with-rspack-and-modernjs-2l2d?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 同实例无需转储复制MySQL数据库方法
    同实例无需转储复制MySQL数据库方法
    在同一实例上复制一个MySQL数据库而无需转储在同一mySQL实例上复制数据库,而无需创建InterMediate sqql script。以下方法为传统的转储和IMPORT过程提供了更简单的替代方法。 直接管道数据 MySQL手动概述了一种允许将mysqldump直接输出到MySQL clie...
    编程 发布于2025-05-06
  • PHP与C++函数重载处理的区别
    PHP与C++函数重载处理的区别
    作为经验丰富的C开发人员脱离谜题,您可能会遇到功能超载的概念。这个概念虽然在C中普遍,但在PHP中构成了独特的挑战。让我们深入研究PHP功能过载的复杂性,并探索其提供的可能性。在PHP中理解php的方法在PHP中,函数超载的概念(如C等语言)不存在。函数签名仅由其名称定义,而与他们的参数列表无关。...
    编程 发布于2025-05-06
  • Java中如何使用观察者模式实现自定义事件?
    Java中如何使用观察者模式实现自定义事件?
    在Java 中创建自定义事件的自定义事件在许多编程场景中都是无关紧要的,使组件能够基于特定的触发器相互通信。本文旨在解决以下内容:问题语句我们如何在Java中实现自定义事件以促进基于特定事件的对象之间的交互,定义了管理订阅者的类界面。以下代码片段演示了如何使用观察者模式创建自定义事件: args)...
    编程 发布于2025-05-06
  • 如何处理PHP文件系统功能中的UTF-8文件名?
    如何处理PHP文件系统功能中的UTF-8文件名?
    在PHP的Filesystem functions中处理UTF-8 FileNames 在使用PHP的MKDIR函数中含有UTF-8字符的文件很多flusf-8字符时,您可能会在Windows Explorer中遇到comploreer grounder grounder grounder gro...
    编程 发布于2025-05-06
  • 如何将PANDAS DataFrame列转换为DateTime格式并按日期过滤?
    如何将PANDAS DataFrame列转换为DateTime格式并按日期过滤?
    Transform Pandas DataFrame Column to DateTime FormatScenario:Data within a Pandas DataFrame often exists in various formats, including strings.使用时间数据时...
    编程 发布于2025-05-06
  • Python高效去除文本中HTML标签方法
    Python高效去除文本中HTML标签方法
    在Python中剥离HTML标签,以获取原始的文本表示Achieving Text-Only Extraction with Python's MLStripperTo streamline the stripping process, the Python standard librar...
    编程 发布于2025-05-06
  • 在Java中如何为PNG文件添加坐标轴和标签?
    在Java中如何为PNG文件添加坐标轴和标签?
    如何用java 在现有png映像中添加轴和标签的axes和labels如何注释png文件可能具有挑战性。与其尝试可能导致错误和不一致的修改,不如建议在图表创建过程中集成注释。使用JFReechArt import java.awt.color; 导入java.awt.eventqueue; 导入...
    编程 发布于2025-05-06
  • 您可以使用CSS在Chrome和Firefox中染色控制台输出吗?
    您可以使用CSS在Chrome和Firefox中染色控制台输出吗?
    在javascript console 中显示颜色是可以使用chrome的控制台显示彩色文本,例如红色的redors,for for for for错误消息?回答是的,可以使用CSS将颜色添加到Chrome和Firefox中的控制台显示的消息(版本31或更高版本)中。要实现这一目标,请使用以下模...
    编程 发布于2025-05-06
  • PHP阵列键值异常:了解07和08的好奇情况
    PHP阵列键值异常:了解07和08的好奇情况
    PHP数组键值问题,使用07&08 在给定数月的数组中,键值07和08呈现令人困惑的行为时,就会出现一个不寻常的问题。运行print_r($月)返回意外结果:键“ 07”丢失,而键“ 08”分配给了9月的值。此问题源于PHP对领先零的解释。当一个数字带有0(例如07或08)的前缀时,PHP将其...
    编程 发布于2025-05-06
  • 为什么不使用CSS`content'属性显示图像?
    为什么不使用CSS`content'属性显示图像?
    在Firefox extemers属性为某些图像很大,&& && && &&华倍华倍[华氏华倍华氏度]很少见,却是某些浏览属性很少,尤其是特定于Firefox的某些浏览器未能在使用内容属性引用时未能显示图像的情况。这可以在提供的CSS类中看到:。googlepic { 内容:url(&#...
    编程 发布于2025-05-06
  • 为什么我的CSS背景图像出现?
    为什么我的CSS背景图像出现?
    故障排除:CSS背景图像未出现 ,您的背景图像尽管遵循教程说明,但您的背景图像仍未加载。图像和样式表位于相同的目录中,但背景仍然是空白的白色帆布。而不是不弃用的,您已经使用了CSS样式: bockent {背景:封闭图像文件名:背景图:url(nickcage.jpg); 如果您的html,css...
    编程 发布于2025-05-06
  • 在Go语言中如何简洁定义10的幂常量
    在Go语言中如何简洁定义10的幂常量
    在GO 利用浮点线文字一种简洁的方式是使用浮点文字,该方法是使用floingpoint protals。写作1E3比写作1000更有效。这是一个示例(67个没有空间的字符):的文字用于未构图的整数常数,我们可以将1000用于KB,并用KB将随后的常量乘以KB,如下所示(77个没有空格的字符):,作...
    编程 发布于2025-05-06
  • 查找当前执行JavaScript的脚本元素方法
    查找当前执行JavaScript的脚本元素方法
    如何引用当前执行脚本的脚本元素在某些方案中理解问题在某些方案中,开发人员可能需要将其他脚本动态加载其他脚本。但是,如果Head Element尚未完全渲染,则使用document.getElementsbytagname('head')[0] .appendChild(v)的常规方...
    编程 发布于2025-05-06
  • Android如何向PHP服务器发送POST数据?
    Android如何向PHP服务器发送POST数据?
    在android apache httpclient(已弃用) httpclient httpclient = new defaulthttpclient(); httppost httppost = new httppost(“ http://www.yoursite.com/script.p...
    编程 发布于2025-05-06
  • 为什么在我的Linux服务器上安装Archive_Zip后,我找不到“ class \” class \'ziparchive \'错误?
    为什么在我的Linux服务器上安装Archive_Zip后,我找不到“ class \” class \'ziparchive \'错误?
    Class 'ZipArchive' Not Found Error While Installing Archive_Zip on Linux ServerSymptom:When attempting to run a script that utilizes the ZipAr...
    编程 发布于2025-05-06

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3