Webpack打包Node.js项目:解决EJS模板与静态资源路径冲突

作者:栖木

时间:2026-10-22

浏览:335

本文详解在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文件进行渲染。

Webpack核心概念简介

这里需要利用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未定义的错误。

报错代码:

Webpack核心概念简介

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

由于locals是由Express中的res.render()传递至页面的数据,Webpack在处理时自然无法获取该变量,从而报错。

那么如何解决此问题?

当前需求是:让Webpack处理HTML中的资源,同时忽略EJS语法并继续压缩代码,这导致陷入两难境地。

Webpack核心概念简介

经过长时间搜索无果后,一篇误打误撞的文章提供了启发。

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

该博主希望将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相关配置,故此处省略。

运行Webpack,打包成功。

Webpack核心概念简介

查看打包前后的HTML对比:

Webpack核心概念简介

打包前:

Webpack核心概念简介

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

Webpack核心概念简介

打包后

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

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章