使用gulp-jasmine时出现Cannot find module错误的求助
这个错误本质上是TypeScript编译时的模块解析规则和Node.js运行时的模块解析规则不匹配导致的,具体有这几个关键点:
1. TS的paths别名只是编译时“糖”,Node.js不认
你在tsconfig.json里配置的paths是给TypeScript编译器用的——它能帮TS找到src/api下的源文件,但编译成JS后,import * as myapi from "api/myapi";这句话原封不动保留了下来。而Node.js运行Jasmine测试时,会按自己的规则找模块:要么找node_modules里的包,要么找相对路径,它完全不知道你TS里的paths映射,自然找不到api/myapi这个模块。
2. 测试代码和API代码的编译输出目录完全分离
你的API代码编译到root/distr,但测试代码编译后留在root/tests里。这种情况下,测试JS文件在root/tests/unit/specs/api/目录下,要找api/myapi的话,Node会在当前目录的node_modules或者上级目录找,根本不会去distr目录里找,所以直接触发MODULE_NOT_FOUND。
3. 没有给Node.js配置运行时的模块映射
就算TS编译时能正确关联模块,你也没告诉Node.js:“当我找api/*的时候,去distr/api/*里找”,所以Node只能一脸懵圈地报错。
方法1:直接用相对路径(最快见效)
把testA.spec.ts里的import改成相对路径,指向编译后的API文件就行:
// 你的testA.spec.ts在root/tests/unit/specs/api/,所以往上跳4级到root,再指向distr/api/myapi.js import * as myapi from "../../../../distr/api/myapi";
编译后的JS里就会是Node能直接识别的相对路径,立刻解决问题。
方法2:用module-alias让Node识别TS别名(保持代码整洁)
如果你不想改大量的import语句,可以用module-alias包来让Node.js支持TS的paths映射:
- 先装依赖:
npm install module-alias --save-dev
- 在项目根目录的
package.json里加一个_moduleAliases字段,对应你的TS paths:
{ "_moduleAliases": { "api": "./distr/api", "*": "./distr" } }
- 在
gulpfile.js的jasmine任务开头加一行,注册这个别名:
gulp.task('jasmine', function(done) { require('module-alias/register'); // 加这行 return gulp.src('tests/**/*.spec.js') .pipe(plumber(function (error) { console.log(error.toString()); this.emit('end'); })) .pipe(jasmine()); })
这样Node运行测试时,就会自动把api/myapi映射到distr/api/myapi.js了。
方法3:把测试代码也编译到distr目录(更规范的工程化方式)
调整你的gulp配置,把测试代码编译后放到distr/tests下,让测试代码和API代码在同一输出目录:
// 修改build:tests任务的输出目录 gulp.task('build:tests', function () { return gulp.src(['tests/**/*.ts']) .pipe(ts()) .pipe(gulp.dest('distr/tests/')); // 输出到distr下的tests文件夹 }); // 同时修改jasmine任务的测试文件路径 gulp.task('jasmine', function(done) { return gulp.src('distr/tests/**/*.spec.js') .pipe(plumber(function (error) { console.log(error.toString()); this.emit('end'); })) .pipe(jasmine()); })
然后调整tsconfig.json的baseUrl和paths,确保TS编译时能正确找到API模块,这样运行时在同一distr目录下,配合module-alias或者调整路径,就能顺利解析模块了。
内容的提问来源于stack exchange,提问作者kevinob

