You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js+Express后端遇Uncaught SyntaxError: import not found问题

部署Express应用后出现模块导入错误:Uncaught SyntaxError: import not found

我用Node.js + Express开发Web应用后端,在Parcel开发服务器上运行正常,但部署后,其中一个模块(@tonaljs)出现Uncaught SyntaxError: import not found错误,Vexflow模块却能正常运行。


后端app.js代码

const express = require("./node_modules/express/index.js");
const app = express();
const ejs = require("./node_modules/ejs/ejs.js")
const path = require("node:path")

app.use("/", express.static("public"));
app.use("/tonal", express.static(path.join(__dirname + "/node_modules/@tonaljs/tonal/dist")))
app.use("/tonal2", express.static(path.join(__dirname + "/node_modules/@tonaljs")))
app.use("/note", express.static(path.join(__dirname + "/node_modules/@tonaljs/note/dist")))
app.use("/chord", express.static(path.join(__dirname + "/node_modules/@tonaljs/chord/dist")))
app.use("/scale", express.static(path.join(__dirname + "/node_modules/@tonaljs/scale/dist")))
app.use("/interval", express.static(path.join(__dirname + "/node_modules/@tonaljs/interval/dist")))
app.use("/vexflow", express.static(path.join(__dirname + "/node_modules/vexflow/build/esm/src")))
app.use("/images", express.static(path.join(__dirname + "/images")))

app.use("*", async(req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", "https://ejercicios-de-armonia.herokuapp.com")
  res.setHeader("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS")
  res.setHeader("Access-Control-Allow-Headers", "Origin, Accept, Content-Type, Authorization")
  res.setHeader("Access-Control-Allow-Credentials", true)
  res.setHeader("Content-Security-Policy", "default-src 'self'; font-src 'self'; img-src 'self'; script-src 'self'; style-src 'self'; frame-src 'self'")
  next()
})

app.set('view engine', 'ejs')

app.get("/", (req, res) => {
  res.render("armonia.ejs")
});

app.listen(process.env.PORT || 1234, () => {
  console.log("listening on port 1234")
})

前端导入语句(public/scripts/armonia.js)

import { Note, Chord, Scale, Interval } from "/tonal/index.js"
import { Vex, Stave, StaveNote, Formatter, Voice, KeySignature} from "/vexflow/index.js"

项目文件夹结构

- node_modules
  - @tonaljs
    - note
    - chord
    - interval
    - scale
    - tonal
  - vexflow
- public
  - scripts
    - armonia.js (主js文件)
  - styles
    - armonia.css
- views
  - armonia.ejs
- app.js
- package-lock.json
- package.json

问题原因与解决方法

1. 核心问题

@tonaljs/tonal的dist/index.js内部依赖了@tonaljs下的其他子模块(如note、chord),当前的静态资源映射仅暴露了tonal/dist目录,导致部署后子模块的相对路径无法被正确解析,触发导入错误。而Vexflow的ESM包是独立打包的,没有跨模块依赖,因此可以正常加载。

2. 修复步骤

  • 简化静态资源映射:删除所有@tonaljs相关的分散映射,替换为统一映射整个@tonaljs目录:

    // 替换原有多个@tonaljs映射
    app.use("/@tonaljs", express.static(path.join(__dirname, "node_modules/@tonaljs")))
    

    同时调整前端导入语句,使用@tonaljs官方推荐的ES模块入口:

    import { Note, Chord, Scale, Interval } from "/@tonaljs/tonal/dist/tonal.esm.js"
    
  • 验证部署文件完整性:确认部署环境中node_modules/@tonaljs/tonal/dist下的文件完整,部分平台(如Heroku)可能因.gitignore或依赖安装配置丢失文件,需确保package.json中依赖声明正确,且部署时执行了npm install。

  • CSP规则检查:当前script-src 'self'允许本地脚本加载,但如果@tonaljs内部有相对路径导入,需确保这些路径在静态资源映射范围内,避免被CSP拦截。

3. 生产环境优化建议

  • 不要直接require本地node_modules文件(如require("./node_modules/express/index.js")),直接写require("express")即可,Node.js会自动从node_modules查找,部署更稳定。
  • 用Parcel、Webpack等工具打包前端依赖为单个文件,避免直接依赖node_modules中的文件,彻底消除路径问题和资源加载风险。

内容的提问来源于stack exchange,提问作者Soter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 12:39:23