在 grunt 构建中注入 ModuleFederationPlugin 配置
解读
国内前端项目普遍采用 webpack 作为最终打包器,而 Grunt 仅负责“任务编排”。
面试官真正想确认的是:
- 你能否把 webpack 5 的 ModuleFederationPlugin 这一“新基建”无缝嫁接到 存量 Grunt 流程;
- 你是否理解 Grunt 与 webpack 的职责边界——Grunt 只做“驱动”,具体联邦配置仍由 webpack 完成;
- 你是否能在 不 eject、不改造原有 Gruntfile 风格 的前提下,用 最轻量的方式注入插件,并保证 多环境变量隔离 与 构建缓存优化,以符合国内 CI/CD 规范。
知识点
- grunt-webpack 官方插件的 webpack 5 适配版本(≥5.0.0)
- ModuleFederationPlugin 的 name/remotes/shared/exposes 四元组语义
- Gruntfile.js 的 grunt.initConfig 层级,以及 grunt.config.merge 运行时补丁机制
- webpack.config 工厂函数(导出函数)与 grunt.template.process 结合,实现 <%= conf.xxx %> 变量替换
- 国内镜像加速:在 shared 里强制 singleton 并 strictVersion,避免低版本重复下载
- CI 场景下通过 process.env.APP_ENV 动态切换 publicPath,保证 cdn/oss 路径正确
- Grunt watch 子进程与 webpack --watch 的 端口隔离,防止 livereload 35729 与 federation 热更新 3000 冲突
答案
-
安装依赖
npm i -D webpack@5 webpack-cli grunt-webpack@5 module-federation-plugin -
在 Gruntfile.js 同级新建 webpack.federation.js
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); const deps = require('./package.json').dependencies; module.exports = ({ production, publicPath }) => ({ output: { publicPath, // 国内 OSS 路径 uniqueName: 'microAppA', // 微应用唯一命名 }, optimization: { runtimeChunk: false, // 保证 remoteEntry 自包含 }, plugins: [ new ModuleFederationPlugin({ name: 'microAppA', filename: 'remoteEntry.js', exposes: { './Button': './src/components/Button', }, shared: { ...deps, react: { singleton: true, strictVersion: true, requiredVersion: deps.react }, 'react-dom': { singleton: true, strictVersion: true, requiredVersion: deps['react-dom'] }, }, }), ], }); -
在 Gruntfile.js 中注入
module.exports = function (grunt) { const isProd = grunt.option('env') === 'prod'; const publicPath = isProd ? 'https://cdn.xxx.com/microAppA/' : 'http://localhost:3001/'; grunt.initConfig({ webpack: { federation: (() => { const base = require('./webpack.federation.js')({ production: isProd, publicPath, }); return { mode: isProd ? 'production' : 'development', entry: './src/index', ...base, }; })(), }, }); grunt.loadNpmTasks('grunt-webpack'); grunt.registerTask('build:federation', ['webpack:federation']); }; -
运行
npx grunt build:federation --env=prod
产物 dist/remoteEntry.js 可直接上传 阿里云 OSS,并在 主应用 中通过 import('microAppA/Button') 消费。
拓展思考
- 多子应用并行构建:利用 grunt-concurrent 把 webpack:federationA、webpack:federationB 并行跑,缩短 GitLab CI 总时长 40%;
- 灰度发布:在 shared.strategy 里增加 eager: true 与 custom 函数,按 cookie 版本号 动态降级;
- 老项目渐进迁移:把 UMD 老 bundle 通过 ModuleFederationPlugin.exposes 暴露成 remote,让 React 18 新应用 以 webpack 5 消费,实现 “灰度微前端”;
- 性能兜底:在 Gruntfile 里追加 grunt-contrib-compress 任务,对 remoteEntry.js 做 brotli 压缩,结合 阿里云 CDN 自动回源,减少 首屏 120 KB;
- 合规审计:在 CI 阶段通过 grunt-eslint 扫描 exposes 路径,禁止 src/api/secret 目录被意外暴露,满足国内 金融客户安全评审 要求。