ES模块作用域中 require 未定义的解决方案
问题描述
当在 Node.js 项目中遇到以下错误时:
ReferenceError: require is not defined in ES module scope, you can use import instead
通常是因为项目或文件被配置为 ES 模块(ECMAScript Modules),但代码中仍在使用 CommonJS 的 require()
语法。
具体到使用 gulp-sass 的场景:
const sass = require('gulp-sass')(require('sass'));
错误信息明确指出:由于 package.json
中包含 "type": "module"
且文件扩展名为 .js
,该文件被当作 ES 模块处理。
根本原因
Node.js 支持两种模块系统:
- CommonJS:使用
require()
和module.exports
- ES 模块:使用
import
和export
当 package.json
设置 "type": "module"
时,所有 .js
文件都被视为 ES 模块,无法使用 require()
。
解决方案
方案一:修改 package.json(推荐用于传统项目)
如果项目主要是 CommonJS 模块,最简单的方法是修改 package.json
:
{
"type": "commonjs"
}
这样所有 .js
文件将使用 CommonJS 模块系统,require()
语法可以正常工作。
注意事项
修改模块类型可能会影响项目中其他依赖 ES 模块的库,请确保兼容性。
方案二:使用 ES 模块导入语法(推荐用于新项目)
将代码中的 require()
替换为 ES 模块的 import
语法:
// 替换前
const sass = require('gulp-sass')(require('sass'));
// 替换后
import gulpSass from 'gulp-sass';
import dartSass from 'sass';
const sass = gulpSass(dartSass);
同时确保 package.json
中有 "type": "module"
设置。
方案三:使用 .cjs 文件扩展名
如果只想在特定文件中使用 CommonJS,可以将文件扩展名改为 .cjs
:
// 将 gulpfile.js 重命名为 gulpfile.cjs
这样即使 package.json
设置了 "type": "module"
,该文件也会被当作 CommonJS 模块处理。
方案四:使用 createRequire 方法(混合模块环境)
在 ES 模块中使用 createRequire
来加载 CommonJS 模块:
import { createRequire } from 'module';
const require = createRequire(import.meta.url);
const sass = require('gulp-sass')(require('sass'));
这种方法适合在 ES 模块项目中需要兼容个别 CommonJS 包的情况。
解决 yargs 相关问题
原始问题中提到的第二个错误:
TypeError: Cannot read property 'prod' of undefined
这是由于在 ES 模块中,yargs.argv
的访问方式发生了变化。解决方案:
// CommonJS 方式
const PRODUCTION = yargs.argv.prod;
// ES 模块方式
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
const argv = yargs(hideBin(process.argv)).argv;
const PRODUCTION = argv.prod;
其他常见场景
TypeScript 和 Jest 环境
在 TypeScript 和 Jest 测试环境中,可能需要特殊配置:
function legacyRequireImport(path) {
if (process.env.NODE_ENV === "test") {
return require(path);
}
const _require = createRequire(import.meta.url);
return _require(path);
}
const someModule = legacyRequireImport("some_module");
在 jest.config.js
中需要相应配置以支持这种混合模式。
Node.js 版本兼容性
确保 Node.js 版本与项目配置兼容。可以通过 .nvmrc
文件指定 Node.js 版本:
node --version > .nvmrc
或使用 nvm 管理多版本:
nvm install 20
nvm use 20
总结
场景 | 解决方案 | 适用情况 |
---|---|---|
完全使用 CommonJS | 设置 "type": "commonjs" | 传统项目,大量使用 require |
完全使用 ES 模块 | 使用 import/export 语法 | 新项目,现代前端开发 |
混合模块环境 | 使用 createRequire 或文件扩展名 | 过渡期项目,需要兼容两种模块 |
最佳实践建议
- 新项目推荐使用 ES 模块语法
- 现有项目可根据依赖库的兼容性决定是否迁移
- 大型项目迁移时可采用渐进式策略,逐步替换 require 为 import
通过正确配置模块系统和统一代码风格,可以避免 "require is not defined" 错误,确保项目正常运行。