Parcel打包Express+EJS的Node.js应用遇items未定义错误求助
问题根源分析
你遇到的核心问题是对Parcel的定位和使用场景理解偏差:Parcel是前端静态资源打包工具,它编译index.ejs时,会直接尝试解析EJS模板生成静态HTML,但这个过程完全不会运行你的Express后端代码——自然也就拿不到后端通过res.render()传递的items变量,所以才会报items is not defined的错误。
而你用node app.js能正常运行,是因为这时候是Express服务器在处理请求:当用户访问根路径时,后端先执行数据库查询,再把items变量注入EJS模板进行服务端渲染,整个流程是有后端上下文支撑的。
解决方案(两种可选方向)
方向一:保留Express服务端渲染架构(推荐,适合原有逻辑)
让Parcel专注处理前端静态资源(JS/CSS等),Express负责运行后端和渲染EJS模板,两者分工协作:
1. 调整项目结构与依赖
- 把前端独立资源(比如自定义JS、CSS)放到单独目录,比如
public/src - 安装
concurrently来同时启动Express和Parcel监听:npm install --save-dev concurrently
2. 修改package.json的scripts
"scripts": { "dev": "concurrently \"node app.js\" \"parcel watch public/src/index.js --out-dir public/dist\"", "build": "parcel build public/src/index.js --out-dir public/dist" }
3. 在EJS中引入Parcel打包后的资源
在index.ejs的<head>或<body>末尾添加:
<script src="/dist/index.js"></script> <!-- 如果有CSS的话也同理引入 --> <link rel="stylesheet" href="/dist/index.css">
4. 保持原有Express路由逻辑不变
你的数据库查询和res.render()代码完全不需要修改,因为依然由Express负责渲染EJS并传递items变量,Parcel只处理前端静态资源的打包和热更新。
方向二:改为前端静态页面+API模式(适合纯前端渲染场景)
如果想完全用Parcel做静态打包,需要把EJS模板改成纯前端页面,通过API从后端获取数据:
1. 改造前端页面与逻辑
- 把
views/index.ejs改为public/src/index.html,去掉EJS模板语法,只保留基础结构:<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>My website</title> </head> <body> <div class="menu"></div> <script src="./index.js"></script> </body> </html> - 在
public/src/index.js中通过API获取数据并渲染:document.addEventListener('DOMContentLoaded', async () => { try { // 调用后端API获取数据 const res = await fetch('/api/items'); const items = await res.json(); // 动态生成菜单 const menuEl = document.querySelector('.menu'); items.forEach(row => { const itemDiv = document.createElement('div'); itemDiv.className = 'item'; itemDiv.dataset.value = row.id; itemDiv.textContent = row.name; menuEl.appendChild(itemDiv); }); } catch (err) { console.error('加载数据失败:', err); } });
2. 在Express中添加API路由
router.get("/api/items", async function(req, res) { const client = await pool.connect() try { const result = await client.query('select id, name from mytable') res.json(result.rows) // 返回JSON格式数据 } finally { client.release() } }); // 配置静态文件目录,让Express能访问Parcel打包后的前端资源 app.use(express.static('public/dist'));
3. 修改package.json的scripts
"scripts": { "dev": "concurrently \"node app.js\" \"parcel watch public/src/index.html --out-dir public/dist\"", "build": "parcel build public/src/index.html --out-dir public/dist" }
内容的提问来源于stack exchange,提问作者vagvaf
相关产品推荐
相关产品推荐

