模块联邦

274 阅读2分钟

在大型项目中,往往会把项目中的某个区域或功能模块作为单独的项目开发,最终形成了【微前端】架构。 在微前端架构中,不同的工程可能会出现以下的场景: shit moutain-屎山

项目1项目2项目3
开发首页开发活动页开发新闻页
独有模块独有模块独有模块
从2引入:分享模块提供:分享模块从2引入:分享模块
提供:分享模块从1引入:分享模块从1引入:分享模块
公共模块公共模块公共模块

解决: 划分为一个个个独立的项目,每个项目有独立的团队、测试、开发、运营、部署、技术。

这涉及到很多问题:

  1. 划分后如何共享代码?
  2. 如何避免公共模块重复打包
  3. 如何将项目的一部分模块分享出去,同时避免重复打包?
  4. 如何管理依赖的不同版本

示例:

现有两个微前端工程,它们各自独立开发、测试、部署。保它们有一些相同的公共模块,并有一些自己的模块需要分享给其他工程使用,同时又要引入其他工程的模块。

HomeContent
开发首页开发内容页
独有模块:index.js独有模块:index.js
引入:news.js提供:news.js
提供:now.js引入:now.js
公共:utils公共模块:utils

初始化工程

home项目

    // 1. 安装
    // 进入home目录下
    cd home;
    // 初始化 package.json
    npm init -y
    // 安装依赖
    npm i -D webpack webpack-cli webpack-dev-server style-loader css-loader html-webpack-plugin
    npm i jquery
    // 2. 修改package.json
    "script":{
        "build":'webpack',
        "dev": 'webpack serve'
    }
    // 3. 配置webpack.config.js
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const path = require('path');
    module.exports = {
        entry:'./src/index.js',
        mode:'development',
        devtool:'source-map',
        devServer:{
            port:8080
        },
        output:{
            clean:true
        },
        module:{
            rules:[
               {
                    test:/\.css/,
                    use:['style-loader','css-loader']
               }
            ]
        },
        plugins:[new HtmlWebpackPlugin()]
    }
    
    // 完成代码编写后,修改webpack.config.js,暴露自己的模块
    const ModuleFederaionPlugin = require('webpack/lib/container/ModuleFederationPlugin');
    module.exports = {
        new ModuleFederationPlugin({
            // 模块联邦的名称
            // 该名称将成为一个全局变量,通过该变量将可获取当前联邦的所有暴露模块
            name:'home',
            // 模块联邦生成的文件名,全部变量将置入到该文件中
            filename:'home-entry.js',
            // 模块联邦暴露的所有模块
            exposes:{
                // key:相对于模块联邦的路径
                // 这里的./now 将决定该模块的访问路径 为home/now
                // value:模块的具体路径
                './now':'./src/now.js'
            }
        })
    }

content项目

引入外部模块

new ModuleFederationPlugin({
    // 远程使用其他项目暴露的模块
    remotes:{
        // key: 自定义远程暴露的联邦名
        // 比如为 abc,则之后引用该联邦的模块则使用 import ‘'abc/模块名'
        // value:模块联邦名@模块联邦访问地址
        // 远程访问时,将下面的地址加载
        value:'home@http://localhost:8080/home-entry.js'
    }
})

在js中导入

    import now from 'home/now'