⚡模块联邦很高大上?马上你就会了

前言

今天和小伙伴们唠唠模块联邦~~~ 这玩意我一直很感兴趣,不为别的,就因为他听起来很高大上,哈哈~~~

其实这玩意刚开始听说还是接触微前端的时候,依稀、好像已经过去2年了...

今天无聊翻之前的笔记,又发现了这个模块联邦,索性就了解下这个之前觉得高大上的小玩意吧。

这里,我尽量把里面包含的小知识点给小伙伴们嚼碎了给大家。(其实,想入门的话,就学一个导入导出的方式就行了~~~)

正文开始

微前端和模块联邦有啥牵扯不清的关系吗?

ps: 本文使用qiankun模块联邦进行对比

1,微前端分为进行运行时和构建时

运行时,动态加载

构建时

  • EMP:基于webpack5提供的模块联邦,构建过程中把不同子应用的依赖,样式表打包到基座中

2,加载子应用(模块)的大概流程是什么? 加载的时机有哪些不一样?

qiankun

  • 主应用提供一个容器

  • 主应用运行时向qiankun注册子应用的路由、渲染位置等信息

  • 根据监听路由变化匹配到子应用的路径进行动态加载、解析,之后在所提供的容器里进行渲染

  • 每个子应用都是一个独立运行的小项目,可以是vue项目或react项目。

模块联邦

  • 构建时,配置哪些模块导出(暴漏出去可以被远程加载),导入哪些模块

  • 主应用启动时就会加载好导入的远程模块

3,什么是去中心化?

说到模块联邦,网上很多文章都会提到去中心化,这里简单说下我的理解~~~

去中心化就像一群人合作建造一座大楼,每个人都清楚知道自己的任务并且负责一部分工程,不需要一个人来指挥所有人该搬砖还是该刷墙。

是否是去中心化,就看让每个模块是否都可以独立构建和管理,就像每个建筑工人可以自主完成自己的任务一样。

qiankun和模块联邦都具备一定程度的去中心化,qiankun更侧重于应用/项目级别,而模块联邦更侧重于工具/模块级别

到这里,小伙伴们应该对模块联邦脑瓜子里有个大概的概念了。

下面来个动手环节加深下印象吧~~~

实战案例

B项目的User组件

A项目导入B项目User组件后的样子

其实,主要就是A项目中如何导入B项目的一个组件 估计几分钟就看完了,哈哈

1,准备两个webpack5的小demo

想省时间,去Github一搜全都是,这一点篇幅略长,可以点击右侧目录跳到第二点

想这一步也自己动手的,可以继续看(此处的是B项目的页面文件,A项目可参考这个,无非是页面内容的展示不一样)

1.1,项目初始化

js 复制代码
yarn init -y

1.2,安装webpack 5 项目的基础包

js 复制代码
npm install webpack webpack-cli html-webpack-plugin webpack-dev-server css-loader style-loader babel-loader @babel/core @babel/preset-env @babel/preset-react -D

1.3,安装demo项目

js 复制代码
npm install react react-dom

1.4,根目录新建src文件夹(不是核心代码,可直接划到第二点)

App.js

js 复制代码
import React from 'react';
import User from './User'

let App = ()=>{
    return (
        <div>
            <h3>webpack 5</h3>
            <User />
        </div>
    )
}

export default App;

index.html

js 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>RootReact</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>

index.js

js 复制代码
import React from "react"
import ReactDom from "react-dom"
import App from "./App"
ReactDom.render(<App />, document.getElementById("root"))

user.js

js 复制代码
import React from 'react';

let User = ()=>{
    return (
        <div>
            user - UserList
        </div>
    )
}

export default User;

1.5,根目录新建webpack.config.js

js 复制代码
const path = require('path');
const htmlWebpackPlugin = require('html-webpack-plugin');
const MF = require('webpack').container.ModuleFederationPlugin

module.exports = {
    // mode 工作模式
    mode: 'development', // production development none
    // 入口
    entry: './src/index.js',
    // 出口
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: './bundle.js'
    },
    // 模块
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: [
                    {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-env', '@babel/preset-react']
                        }
                    }
                ]
            },
        ]
    },
    // 插件
    plugins: [
        new htmlWebpackPlugin({
            template: './src/index.html',
        }),
        new MF({
            // 对外提供打包后的文件名。导入时会使用
            filename: 'myUser.js',
            // 微应用名字
            name: 'study',
            exposes:{
                // 名字: 具体文件
                './user': './src/User.js'
            }
        })
    ],
    // 服务器
    devServer: {
        static: path.join(__dirname, 'dist'), // 指定资源路径
        port: 3001,
        open: true
    }
    
}

2,webpack5模块联邦 - webpack.conifg.js核心配置划重点

先说下B项目的配置

  • filename: 对外提供打包后的文件名,A项目中导入时会用到

  • name:可以看作应用名称,A项目中导入时会用到

  • exposes:模块暴露出去(导出)

    • 名字: 具体文件的路径

    • './user': './src/User.js',

A项目的配置

  • name:可以看作应用名称(A项目没有模块需要导出,这个可不写)
  • remotes:引入之前B项目导出的模块(A项目中导入)
    • A项目导入的远程模块的别名:B项目中写的应用名@B项目地址/B项目配置的打包后文件名
    • home: 'study@http://localhost:3001/myUser.js'

3,A项目组件中导入B项目的组件

react组件

js 复制代码
import React from 'react';
const Us = React.lazy(()=>import("home/user"))

let App = ()=>{
    return (
        <div>
            <h3>webpack 5</h3>
            <React.Suspense callback="loading">
                <Us />
            </React.Suspense>
        </div>
    )
}

export default App;

因为模块联邦导入的未异步组件,react中使用 React.lazy + React.Suspense进行使用

vue组件

js 复制代码
import {defineAsyncComponent} from "vue"

const Us = defineAsyncComponent(()=> import("home/user"))

webpakck5里的配置和react是一样的

4,导入导出多个模块

B项目的配置

js 复制代码
new MF({
            // 对外提供打包后的文件名。导入时会使用
            filename: 'myUser.js',
            // 微应用名字
            name: 'study',
            exposes:{
                // 名字: 具体文件
                './user': './src/User.js',
                './goods': './src/Goods.js'
            }
        })

A项目的配置

js 复制代码
import React from 'react';

const Us = React.lazy(() => import("home/user"))
const Gs = React.lazy(() => import("home/goods"))

let App = () => {
  return (
    <div>
      <h3>webpack 5</h3>
      <React.Suspense callback="loading">
        <Us />
        <Gs />
      </React.Suspense>
    </div>
  )
}

export default App;

完结

这篇文章我尽力把我的笔记和想法放到这了,希望对小伙伴有帮助。

欢迎转载,但请注明来源。

最后,希望小伙伴们给我个免费的点赞,祝大家心想事成,平安喜乐。

相关推荐
代码猎人几秒前
forEach和map方法有哪些区别
前端
恋猫de小郭1 分钟前
Google DeepMind :RAG 已死,无限上下文是伪命题?RLM 如何用“代码思维”终结 AI 的记忆焦虑
前端·flutter·ai编程
byzh_rc9 分钟前
[微机原理与系统设计-从入门到入土] 微型计算机基础
开发语言·javascript·ecmascript
m0_4711996310 分钟前
【小程序】订单数据缓存 以及针对海量库存数据的 懒加载+数据分片 的具体实现方式
前端·vue.js·小程序
编程大师哥11 分钟前
Java web
java·开发语言·前端
A小码哥12 分钟前
Vibe Coding 提示词优化的四个实战策略
前端
Murrays12 分钟前
【React】01 初识 React
前端·javascript·react.js
大喜xi16 分钟前
ReactNative 使用百分比宽度时,aspectRatio 在某些情况下无法正确推断出高度,导致图片高度为 0,从而无法显示
前端
helloCat16 分钟前
你的前端代码应该怎么写
前端·javascript·架构
电商API_1800790524717 分钟前
大麦网API实战指南:关键字搜索与详情数据获取全解析
java·大数据·前端·人工智能·spring·网络爬虫