如何在NRWL React Monorepo中将Tailwind CSS纳入Module Federation的remoteEntry
Nx Monorepo中Module Federation + Tailwind CSS加载问题解决方案
两种可行方案
针对外部shell应用无法获取remoteEntry中CSS的问题,基于@nrwl-tailwind-postcss可以实现两种效果:要么把CSS内嵌进remoteEntry.js,要么让shell从remote的托管地址加载独立CSS文件,具体配置如下:
方案1:CSS内嵌到remoteEntry.js
适合小体积样式场景,无需额外请求,直接把CSS打包进JS:
1. 配置PostCSS(每个remote应用)
在app1和app2根目录创建/修改postcss.config.js:
const { createGlobPatternsForDependencies } = require('@nrwl/react/tailwind'); const { join } = require('path'); module.exports = { plugins: { tailwindcss: { config: join(__dirname, 'tailwind.config.js') }, autoprefixer: {}, }, };
2. 修改remote的webpack配置
在app1的project.json中指定自定义webpack配置:
{ "targets": { "build": { "executor": "@nrwl/webpack:webpack", "options": { "webpackConfig": "apps/app1/webpack.config.js", // 保留原有其他配置 } } } }
创建apps/app1/webpack.config.js(app2复制后修改对应路径即可):
const { withModuleFederation } = require('@nrwl/react/module-federation'); const baseConfig = require('./module-federation.config'); const config = withModuleFederation({ ...baseConfig }); // 替换CSS提取为内嵌规则 config.module.rules.push({ test: /\.css$/i, use: ['style-loader', 'css-loader', 'postcss-loader'], }); // 移除默认的CSS提取插件 const cssPluginIdx = config.plugins.findIndex(p => p.constructor.name === 'MiniCssExtractPlugin'); if (cssPluginIdx !== -1) config.plugins.splice(cssPluginIdx, 1); module.exports = config;
方案2:生成独立CSS文件并由shell加载
适合大体积样式场景,remote输出独立CSS,shell主动加载:
1. 确保remote生成独立CSS
在app1的webpack.config.js中保留CSS提取配置(Nx默认可能已有,可补充完善):
const { withModuleFederation } = require('@nrwl/react/module-federation'); const baseConfig = require('./module-federation.config'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const config = withModuleFederation({ ...baseConfig }); config.module.rules.push({ test: /\.css$/i, use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'], }); config.plugins.push(new MiniCssExtractPlugin({ filename: '[name].[contenthash].css', })); module.exports = config;
2. 在shell中加载remote的CSS
在shell的入口文件(比如src/main.tsx)中,动态插入CSS链接:
// 封装加载函数 const loadRemoteCss = (url) => { const link = document.createElement('link'); link.rel = 'stylesheet'; link.href = url; document.head.appendChild(link); }; // 启动时加载remote的CSS,替换为实际托管地址 loadRemoteCss('http://localhost:4201/styles.[contenthash].css'); loadRemoteCss('http://localhost:4202/styles.[contenthash].css');
如果需要和remote模块加载同步,可在加载模块后执行:
import { loadRemoteModule } from '@nrwl/react/module-federation'; async function loadApp1() { await loadRemoteModule({ remoteEntry: 'http://localhost:4201/remoteEntry.js', remoteName: 'app1', exposedModule: './Module', }); loadRemoteCss('http://localhost:4201/styles.[contenthash].css'); } // 按需调用 loadApp1();
验证步骤
- 构建并启动remote应用:
nx build app1 && nx serve app1 nx build app2 && nx serve app2
- 启动外部shell应用:
- 方案1:查看remoteEntry.js源码,确认包含内嵌的CSS代码
- 方案2:打开浏览器网络面板,确认能从remote地址下载到CSS文件
内容的提问来源于stack exchange,提问作者anujayk
相关产品推荐
相关产品推荐

