为服务端EJS项目配置Webpack:动态插入构建资源
解决方案:动态在EJS中注入Webpack打包资源标签
嘿,我来帮你搞定这个Webpack和EJS的资源注入问题!你提到要用webpack-middleware,这个思路完全正确,接下来我一步步给你讲怎么配置,保证能动态插入打包后的JS和CSS标签。
第一步:安装所需依赖
首先得把必要的工具包装上,打开终端跑这个命令:
npm install webpack-dev-middleware webpack-hot-middleware express --save-dev
(如果你的项目已经用了Express,可以跳过express的安装)
第二步:调整Webpack配置
修改你的webpack.config.js,重点添加publicPath(确保浏览器能正确找到打包后的资源),以及开发环境的热更新支持(可选但能提升开发体验):
import path from 'path'; import ExtractTextPlugin from 'extract-text-webpack-plugin'; import CleanWebpackPlugin from 'clean-webpack-plugin'; import webpack from 'webpack'; const inProduction = process.argv[process.argv.length - 1] .match(/[a-z]+$/g)[0] === 'production'; const basic = { entry: { app: path.join(__dirname, 'frontend/source/scripts/main.js'), }, output: { path: path.join(__dirname, 'frontend/build'), filename: '[name].[chunkhash].js', // 关键:设置publicPath,让浏览器知道资源的基础路径 publicPath: '/frontend/build/' }, }; const module = { rules: [{ test: /\.css$/, use: ExtractTextPlugin.extract({ use: ['css-loader'], }), }, { test: /\.js$/, use: ['babel-loader'], exclude: ['/node_modules'], }, ], }; const plugins = [ new ExtractTextPlugin('[name].[contenthash].css'), new CleanWebpackPlugin('build'), ]; // 开发环境添加热更新插件,修改入口 if (!inProduction) { plugins.push(new webpack.HotModuleReplacementPlugin()); basic.entry.app = ['webpack-hot-middleware/client?reload=true', basic.entry.app]; } export default { ...basic, module, plugins };
第三步:配置Express服务器(核心逻辑)
创建一个server.js文件,把Webpack中间件集成进去,这样就能实时获取打包后的资源信息,然后传给EJS模板:
import express from 'express'; import webpack from 'webpack'; import webpackDevMiddleware from 'webpack-dev-middleware'; import webpackHotMiddleware from 'webpack-hot-middleware'; import webpackConfig from './webpack.config.js'; import path from 'path'; const app = express(); const compiler = webpack(webpackConfig); // 配置Webpack Dev Middleware,负责编译和提供静态资源 app.use(webpackDevMiddleware(compiler, { publicPath: webpackConfig.output.publicPath, stats: { colors: true } // 控制台输出彩色日志,方便调试 })); // 开发环境启用热更新,代码变动自动刷新浏览器 if (!inProduction) { app.use(webpackHotMiddleware(compiler)); } // 设置EJS为模板引擎,指定EJS文件所在目录(根据你的实际路径调整) app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, './')); // 假设你的index.ejs在项目根目录,按需修改 // 处理路由,渲染index.ejs app.get('*', (req, res) => { // 获取Webpack编译后的资源统计信息 const stats = compiler.getStats().toJson(); // 从stats里提取JS和CSS文件路径(兼容单文件和数组格式) const assets = { js: Array.isArray(stats.assetsByChunkName.app) ? stats.assetsByChunkName.app.filter(asset => asset.endsWith('.js')) : [stats.assetsByChunkName.app].filter(asset => asset.endsWith('.js')), css: Array.isArray(stats.assetsByChunkName.app) ? stats.assetsByChunkName.app.filter(asset => asset.endsWith('.css')) : [stats.assetsByChunkName.app].filter(asset => asset.endsWith('.css')) }; // 渲染EJS模板,把assets和你原本需要的变量(branches、commits等)传进去 res.render('index', { assets, branches: req.branches, commits: req.commits, files: req.files, file: req.file }); }); // 启动服务器 const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`服务器跑在端口 ${PORT} 啦!`); });
第四步:修改index.ejs动态插入标签
最后更新你的index.ejs,利用传过来的assets变量生成对应的<link>和<script>标签:
<header class="header">Git Rendering</header> <!-- 动态插入CSS样式 --> <% if (assets && assets.css.length) { %> <% assets.css.forEach(cssFile => { %> <link rel="stylesheet" href="<%= '/frontend/build/' %><%= cssFile %>"> <% }) %> <% } %> <main class="container"> <% if (branches) { %> <%- include('branches'); %> <% } %> <% if (commits) { %> <%- include('commits'); %> <% } %> <% if (files) { %> <%- include('files'); %> <% } %> <% if (file) { %> <%- include('file'); %> <% } %> </main> <!-- 动态插入JS脚本 --> <% if (assets && assets.js.length) { %> <% assets.js.forEach(jsFile => { %> <script src="<%= '/frontend/build/' %><%= jsFile %>"></script> <% }) %> <% } %>
额外提示
- 如果你的EJS文件不在根目录,记得修改
app.set('views', ...)的路径为实际存放EJS的文件夹。 - 生产环境下,你可以预先执行
webpack --json > stats.json生成静态的资源统计文件,然后在服务器启动时读取这个文件,不用实时编译,性能会更好。 - 如果后续要把资源部署到CDN,只需要修改Webpack的
publicPath为CDN地址即可,EJS里的标签会自动用新路径。
内容的提问来源于stack exchange,提问作者Rami Chasygov
相关产品推荐
相关产品推荐

