Webpack打包Node.js项目:解决EJS模板与静态资源路径冲突
本文详解在Node.js后端结合EJS模板引擎时,使用Webpack打包前端代码遇到的EJS解析、静态资源路径及locals未定义等问题。通过修改Express引擎注册方式,将EJS转为HTML处理,并利用HtmlWebpackPlugin配置入口与模板,实现代码压缩与资源正确引用,解决打包后Node.js服务无法找到资源的问题。
Webpack核心概念简介
随着前端应用体积日益庞大且功能愈发复杂,前端工程化已成为必然趋势,而Webpack正是实现将各类前端文件统一打包的核心工具。一个基础的Webpack配置通常涉及几个关键概念。
- 入口起点
- 输出
- 配置
- 组件
- 加载器
- 插件
- 模块
- 模块热替换
Node.js与EJS项目背景及问题
首先需说明,本文所述情况并非普遍适用。若你的项目场景与笔者相似,希望本文能为你提供解决思路。
我的项目背景如下:后端采用Node.js,模板引擎使用EJS(即整个页面由一个EJS文件构成)。Node.js负责渲染数据,生成完整页面后返回给用户。
这种架构会引发以下问题:
1. 本项目不存在独立的HTML页面,EJS也不用于引入公共组件,而是直接渲染完整页面。Webpack中处理EJS文件的Loader返回的是一个函数,这会导致执行异常。
2. 由于Node.js配置了静态资源目录public,且视图目录与其同级,Webpack在处理图像等静态资源路径时会出现引用错误。
3. 若设置publicPath,Node.js运行时将无法找到资源,因为静态资源目录已明确指定。
如果你也面临类似困境,希望能在本文中找到解决方案。
补充说明:不必觉得项目结构奇怪,这源于初期知识储备不足。待发现问题时,重构成本过高,因此选择维持现状。
鉴于修改成本高昂,最终决定将错就错。
解决方案
EJS处理与Webpack配置方案
1. 处理EJS文件
我在各大论坛及官网反复搜索,始终未找到能直接处理此类情况的Loader。
无奈之下,只能转换思路:先将EJS文件转换为HTML文件。
要修改文件,首先需调整服务器端的模板引擎配置(即app.js)。
具体修改目标为:让Node.js继续使用EJS模板引擎,但通过HTML文件进行渲染。

这里需要利用Express中的app.engine方法来注册一个新的引擎映射。
相关代码如下:
[原图,由程序原样保留,不描述看不到的内容]
app.set('views',path.join(__dirname,'views'));//设置模板引擎的目录
app.engine('html', require('ejs').renderFile);
app.set('view engine','html');
通过上述配置,即可将原本views视图目录中的EJS文件后缀更改为.html。
2. Webpack处理HTML文件
首先引入的Webpack插件是HtmlWebpackPlugin。
查阅众多文章后发现,处理HTML文件时几乎都使用了该插件。
既然广泛使用,其功能强大性毋庸置疑。
然而配置完成后运行Webpack,却报出locals未定义的错误。
报错代码:

[原图,由程序原样保留,不描述看不到的内容]
由于locals是由Express中的res.render()传递至页面的数据,Webpack在处理时自然无法获取该变量,从而报错。
那么如何解决此问题?
当前需求是:让Webpack处理HTML中的资源,同时忽略EJS语法并继续压缩代码,这导致陷入两难境地。

经过长时间搜索无果后,一篇误打误撞的文章提供了启发。
[原图,由程序原样保留,不描述看不到的内容]
该博主希望将EJS引入的模板打包至单一页面,而我恰恰相反,需要Webpack忽略EJS代码。
于是解决方案应运而生。
首先,将HTML中的JS代码抽离至test.js文件中。
然后,以该JS文件作为入口文件,以原始HTML文件作为模板。
利用HtmlWebpackPlugin生成压缩后的HTML文件。
'use strict';
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
//打包ejs
module.exports = {
entry: {
test: './test.js',//入口文件 即一般来说app.js
},
mode:"production",//生产环境
output: {
path: path.resolve(__dirname,'build'),//输出路径
filename: 'js/[name]/[name].js'//输出后的文件名
},
externals: {
jquery:'window.jQuery'
},//外部加载的资源 这些都是不需要进行打包的
module: {
rules: [//设置处理js文件的loader
{test:/\.js$/,use:'babel-loader',exclude:/node_modules/},
{test:/\.css$/,use:["style-loader","css-loader"]},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'images/[name].[ext]'
}
}
]
},
{
test: /\.(html)$/,
use: {
loader: 'html-loader',
options: {
attrs: [':data-src']
}
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
name:'test',
template:'./public/init.html',//模板文件
filename:'views/test.html',//目标文件
minify:{
collapseWhitespace:true,
collapseInlineTagWhitespace:true,
conservativeCollapse:true,
minifyCSS:true,
minifyJS: true,
removeComments:true,
trimCustomFragments:true
}
})
],
optimization: {
minimize: true//是否压缩代码
}
};
解决代码
webpack.config.js
上述minify参数主要用于配置HTML压缩选项。
入口文件test.js

该文件仅包含项目业务代码,无Webpack相关配置,故此处省略。
运行Webpack,打包成功。

查看打包前后的HTML对比:

打包前:

[原图,由程序原样保留,不描述看不到的内容]

打包后
[原图,由程序原样保留,不描述看不到的内容]
NestJS 是什么?与 Express、Koa 的核心区别及选型建议
2026-11-05 13:46:41
生产环境升级 Node.js 的注意事项与兼容性测试策略
2026-11-05 09:19:24
nvm 常用命令详解:怎么平滑切换和升级 Node.js 版本
2026-11-04 09:02:34
JavaScript和JSP的根本区别:运行环境与执行机制解析
2026-11-03 23:30:18
使用nvm卸载指定版本Node.js并切换默认环境
2026-11-03 23:09:26
