如何基于Express实例在React脚手架中实现Webpack多入口共享代码库应用
没问题,我来帮你梳理这个「React脚手架+Webpack多入口+共享代码+双Express服务」的完整实现方案,咱们一步一步来落地:
一、Webpack 多入口配置(基于Create React App 自定义)
因为Create React App默认隐藏Webpack配置,咱们用react-app-rewired来修改更省心,不用 eject。
- 先安装依赖:
npm install react-app-rewired customize-cra html-webpack-plugin --save-dev
- 在项目根目录新建
config-overrides.js,配置多入口、多HTML模板和共享代码拆分:
const { override, addWebpackPlugin, addWebpackEntry, addWebpackOutput } = require('customize-cra'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const path = require('path'); module.exports = override( // 配置多入口,关联你的两个入口JS文件 addWebpackEntry({ vendor: path.resolve(__dirname, 'src/vendor.js'), settings: path.resolve(__dirname, 'src/settings.js'), }), // 配置输出规则,让两个应用的产物分开存放 addWebpackOutput({ filename: '[name]/static/js/[name].[contenthash:8].js', chunkFilename: '[name]/static/js/[name].[contenthash:8].chunk.js', path: path.resolve(__dirname, 'build'), // 统一输出到build目录下的子文件夹 }), // 配置两个HTML模板,分别对应两个应用的入口页面 addWebpackPlugin([ new HtmlWebpackPlugin({ inject: true, template: path.resolve(__dirname, 'public/vendor.html'), filename: 'vendor/index.html', chunks: ['vendor', 'vendors'], // 关联vendor入口和共享代码chunk }), new HtmlWebpackPlugin({ inject: true, template: path.resolve(__dirname, 'public/settings.html'), filename: 'settings/index.html', chunks: ['settings', 'vendors'], // 关联settings入口和共享代码chunk }), ]), // 配置共享代码自动拆分,提取被两个入口共同引用的代码 (config) => { config.optimization.splitChunks = { chunks: 'all', name: 'vendors', // 共享chunk的统一名称 minChunks: 2, // 被至少2个入口引用才会拆分 }; return config; } );
二、完善Express Server.js 配置
把你现有的Server.js补全,实现两个独立的Express服务,分别对应两个应用的静态资源和路由:
const express = require('express'); const path = require('path'); const { resolve } = path; // 通用的服务初始化函数,复用逻辑 function setup(app, { domain, outputPath, publicPath }) { // 生产环境:托管打包后的静态文件 app.use(publicPath, express.static(outputPath)); // 路由:返回对应应用的HTML入口 app.get('*', (req, res) => { res.sendFile(resolve(outputPath, 'index.html')); }); // 启动服务,给两个应用分配不同端口 const port = domain === 'Vendor' ? 3001 : 3002; app.listen(port, () => { console.log(`${domain} app running at http://localhost:${port}`); }); } // 初始化两个应用服务 const appVendor = express(); const appSetting = express(); // 注意:这里的outputPath要和Webpack配置的输出目录对应 setup(appVendor, { domain: 'Vendor', outputPath: resolve(process.cwd(), 'build/vendor'), publicPath: '/', }); setup(appSetting, { domain: 'Settings', outputPath: resolve(process.cwd(), 'build/settings'), publicPath: '/', });
如果是开发环境,还要集成Webpack热更新,修改setup函数:
const webpack = require('webpack'); const webpackDevMiddleware = require('webpack-dev-middleware'); const webpackHotMiddleware = require('webpack-hot-middleware'); const webpackConfig = require('./config-overrides.js'); function setup(app, { domain, outputPath, publicPath }) { if (process.env.NODE_ENV === 'development') { // 开发环境:启用Webpack实时编译和热更新 const compiler = webpack(webpackConfig); app.use(webpackDevMiddleware(compiler, { publicPath: publicPath, stats: 'minimal', })); app.use(webpackHotMiddleware(compiler)); } else { // 生产环境:托管静态文件 app.use(publicPath, express.static(outputPath)); } // 路由逻辑适配开发/生产环境 app.get('*', (req, res) => { const htmlPath = process.env.NODE_ENV === 'development' ? resolve(__dirname, `public/${domain.toLowerCase()}.html`) : resolve(outputPath, 'index.html'); res.sendFile(htmlPath); }); // 启动服务 const port = domain === 'Vendor' ? 3001 : 3002; app.listen(port, () => { console.log(`${domain} app running at http://localhost:${port}`); }); }
三、共享代码的组织与使用
在src目录下新建shared文件夹,把两个应用共用的组件、工具函数、样式放在这里:
src/ ├── vendor.js # Vendor应用入口 ├── settings.js # Settings应用入口 └── shared/ ├── components/ # 共享组件(比如通用Button、Header) ├── utils/ # 共享工具函数(比如请求工具、日期格式化) └── styles/ # 共享全局样式
然后在两个入口文件里直接引用即可,Webpack会自动把被两个入口共同引用的代码拆分到vendors chunk里:
// src/vendor.js import React from 'react'; import ReactDOM from 'react-dom/client'; import './shared/styles/global.css'; import VendorApp from './components/VendorApp'; import { formatDate } from './shared/utils/date'; ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <VendorApp /> </React.StrictMode> );
四、配置构建与运行脚本
修改package.json里的scripts,方便一键构建和启动:
{ "scripts": { "start:dev": "cross-env NODE_ENV=development node Server.js", "build": "react-app-rewired build", "start:prod": "node Server.js" } }
(注:如果是Windows系统,安装cross-env来兼容环境变量配置,避免命令报错)
最后验证一下:
- 开发环境运行
npm run start:dev,两个服务会分别在3001和3002端口启动,修改代码会实时热更新 - 生产环境运行
npm run build,会在build目录下生成vendor和settings两个子文件夹,对应两个应用的产物,再运行npm run start:prod即可启动生产服务
内容的提问来源于stack exchange,提问作者Rohit Dubey
相关产品推荐
相关产品推荐

