likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 0

前言

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

其实这玩意刚开始听说还是接触微前端的时候,依稀、好像已经过去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,项目初始化

yarn init -y

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

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项目

npm install react react-dom

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

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

App.js

import React from 'react';
import User from './User'

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

export default App;

index.html

<!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

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

user.js

import React from 'react';

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

export default User;

1.5,根目录新建webpack.config.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组件

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组件

import {defineAsyncComponent} from "vue"

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

webpakck5里的配置和react是一样的

4,导入导出多个模块

B项目的配置

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

A项目的配置

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;

完结

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

欢迎转载,但请注明来源。 最后,希望小伙伴们给我个免费的点赞,祝大家心想事成,平安喜乐。

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