使用ES6语法和绝对路径导入外部模块

5

我有一个类似于以下结构的项目:

app/
  bin/
  lib/
  src/
    main/
      submodule.ts
    utilities/
      common.ts
    main.ts
    tsconfig.json
  gulpfile.js

app/src/main/submodule.ts 需要导入 app/src/utilities/common.ts。我想使用 ES6 语法来实现这一点。因此,我期望在 submodule.ts 中看到类似于下面的代码:

import {common} from '/utilities/common';

根目录为/,即tsconfig所在的位置是app/src/。是的,app/src/utilities/common.ts导出了一个名为common的模块。
问题在于我遇到了“无法找到模块'/utilities/common'”的错误。我尝试了各种方法:
  • utilities/common
  • /src/utilities/common
  • /app/src/utilities/common
但这些都不起作用。相对路径../utilities/common可以工作,但是对于常见模块使用相对路径是一种维护上的噩梦。
值得注意的是,我刚从TS 1.5升级到1.6:在1.5中使用utilities/common是可行的。虽然我在1.6的文档中没有找到任何关于此类变化的提及。
我提到了gulpfile.ts和其他文件夹,因为最终我希望Gulp从src获取TS文件,并将编译后的JS文件放在bin中。我有信心正确地配置了Gulp来完成这个任务,使用的是gulp-typescript,但是为了完整起见,这里是我的tsconfig.jsongulpfile.js
  • tsconfig.json

    {
        "compilerOptions": {
            "module": "commonjs",
            "target": "es5",
            "experimentalDecorators": true,
            "emitDecoratorMetadata": true,
            "noEmitOnError": true
        },
        "filesGlob": [
            "./**/*.ts",
            "!./typings/**/*.ts"
        ]
    }
  • gulpfile.js

    var gulp = require('gulp');
    var ts   = require('gulp-typescript');
    var less = require('gulp-less');
    var sourcemaps = require('gulp-sourcemaps');
    var merge = require('merge2'); var path = require('path');
    var tsProject = ts.createProject('src/tsconfig.json', { noExternalResolve: true });
    gulp.task('html', function () { gulp.src([ 'src/**/*.html', ]) .pipe(gulp.dest('bin')); });
    gulp.task('typescript', function () { tsProject.src() .pipe(sourcemaps.init()) .pipe(ts(tsProject)) .js .pipe(sourcemaps.write()) .pipe(gulp.dest('bin')); });
    gulp.task('less', function () { gulp.src([ 'src/**/*.less', ]) .pipe(sourcemaps.init()) .pipe(less()) .pipe(sourcemaps.write()) .pipe(gulp.dest('bin')) });
    gulp.task('default', ['html', 'typescript', 'less']);
2个回答

3
最终解决了这个问题。根据最新消息,1.6版更改了模块解析方式以与Node相似。我尚未调查Node的模块解析方式是否可以使用该行为进行修复,但我已经找到了一种解决方法:
tsconfig.json中指定"moduleResolution": "classic"即可触发旧的行为。

1

如果路径以./../开头,则模块解析相对于当前文件执行。

这里是一个使用的快速示例:

/
/src/
/src/thing.ts
/main/
/main/submodule.ts
/utilities/
/utilities/common.ts

因此,将common.ts导入到submodule.ts的正确语句应该是:

import {common} from '../utilities/common';

您也可以使用以下根路径(请注意,此处没有前导/或任何.):
import {common} from 'src/utilities/common';

这对我来说在Visual Studio代码中有效,将src的父文件夹作为工作文件夹打开。在我的情况下,我使用UMD模块针对ES5进行目标设置。

It Works!

您还可以通过从当前位置向上遍历来解析模块(这是 NodeJS 的一个特性)。因此,您可以使用以下方式将 thing.ts 导入到 submodule.ts 中:
import {something} from 'thing';

解析器将检查当前文件夹,然后是父文件夹,再然后是父文件夹的父文件夹...以此类推。

绝对路径与相对路径

在网页链接方面,我同意您的观点,绝对路径更易于维护,尤其是在多个级别共享资源的情况下。

但是在模块方面,我不确定是否存在相同的维护问题,因为这里的路径是“相对于出现导入语句的文件”,而不是相对于网页。我想知道这是否是一个非常明智的规则应用在错误的地方。


将注释移动到答案中。 - Fenton
你的截图展示了我想要实现的效果(路径中的 src 会在后面给我带来麻烦,但这不是本问题的一部分),但是 VS Code 在相同的设置下给我报错。我正在使用版本为 0.9.1 的 TypeScript 1.6.2;你也是吗? - KRyan
是的 - Visual Studio Code 0.9.1,TypeScript 1.6.2。你的电脑上是否还有其他版本的编译器可能被选中了? - Fenton
如果那是情况的话,我会期望它工作,仅仅因为在更新之前它曾经工作过。 我装了(几个)其他版本的tsc,但1.6绝对是在我的路径中找到的版本,由PowerShell发现并被Visual Studio 2015使用。 我将尝试删除旧版本来看看是否会使事情突然变得可行,但我持怀疑态度。 不幸的是,现在无法做到这一点。 - KRyan
1
将我的旧TypeScript编译器放进了回收站,但没有任何更改。至于你上一部分内容,正如“utilities/”名称所示,我有许多共享的常用实用程序函数在整个项目中使用。计算每个给定文件需要到达根目录的“../”数是丑陋、混乱的,并使重新组织文件变得不必要的痛苦。我坚持认为在这里使用绝对路径是必要的。对于我的文件夹或子文件夹中的内容,我可以看到相对路径的优势,但是一旦你要上下不同的分支,就不行了。 - KRyan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接