Rollup打包speaker模块报无法动态require binding.node如何解决
speaker是Node.js生态的原生C扩展包,它依赖bindings工具包在运行时动态查找、加载对应平台/Node版本编译生成的.node二进制文件。
你看到的不存在的/path/to/Project/build/binding.node路径,是bindings包内置的默认候选查找路径之一,既不是构建生成的临时文件也不是虚拟路径,只是运行时查找二进制的固定探测位置。
配置dynamicRequireTargets不生效的核心原因是:**原生C扩展模块不适合被直接打包进Rollup bundle**。这类模块的加载逻辑依赖运行时文件系统探测、平台架构匹配的二进制文件,Rollup的静态打包逻辑会直接破坏动态加载链路,无法通过枚举动态require路径解决。
另外你的Rollup配置存在一个路径错误:output.file字段以/dist/开头,会把构建产物输出到系统根目录的dist文件夹,而非项目目录下的dist文件夹,会直接导致后续相对路径依赖查找全部失效。
1. 修正输出路径错误
修改rollup.config.ts中output配置的file字段,去掉开头的多余斜杠,确保产物输出到项目内的dist目录:
output: { file: 'dist/' + require(path.join(process.cwd(), 'package.json')).name, format: 'cjs', banner: '#!/usr/bin/env node\n', },
2. 将原生依赖标记为外部模块
原生扩展和它的加载依赖不需要打包进bundle,修改external配置,让Rollup保留原生require语句,运行时直接从依赖目录查找模块:
external: [ 'speaker', 'bindings' ],
3. 调整commonjs插件配置
给@rollup/plugin-commonjs添加配置,跳过对动态require语句的静态转换,避免拦截原生模块的运行时加载逻辑:
commonjs({ ignoreDynamicRequires: true, }),
4.(可选,独立产物场景)拷贝原生二进制到产物目录
如果你需要dist目录的产物可以脱离项目node_modules独立运行,安装rollup-plugin-copy插件,把speaker包内置的编译二进制目录拷贝到dist目录,匹配bindings的默认查找规则:
- 安装依赖:
npm i -D rollup-plugin-copy
- 在rollup配置的头部引入插件:
import copy from 'rollup-plugin-copy';
- 在plugins数组中添加拷贝规则:
plugins: [ nodeResolve(), typescript({ tsconfig: fs.existsSync(path.join(process.cwd(), './tsconfig.build.json')) ? './tsconfig.build.json' : './tsconfig.json', }), json(), commonjs({ ignoreDynamicRequires: true, }), // 新增拷贝规则 copy({ targets: [ { src: 'node_modules/speaker/build/**/*', dest: 'dist/build' } ] }), executable(), ]
.node原生二进制文件和操作系统、CPU架构、Node.js版本强绑定,你在当前环境拷贝的二进制文件只能在同环境运行,跨环境部署时需要重新在对应环境执行npm rebuild speaker编译对应版本的二进制文件,否则会出现加载失败。
重新执行构建命令后,运行dist目录下的产物即可正常导入Speaker模块,不会再出现动态require相关报错。
内容的提问来源于stack exchange,提问作者DemiPixel

