带有文件扩展名的 TypeScript 模块的 Visual Studio 2022 构建错误

Gup*_*R4c 6 visual-studio typescript gulp visual-studio-2022

我正在重建我的 Gulp 实现,以使用最新版本的 Rollup 来编译、缩小 TypeScript 文件并将其压缩为单个包。新的实现已经完成并且正在运行,我可以从任务运行程序或使用 Gulp 的文件系统观察器触发它,它完全按照我需要的方式执行。

我遇到的问题是,为了让 Rollup 查看模块导入,我必须将“.ts”扩展名附加到导入中:

import { something } from "./Module.ts";
Run Code Online (Sandbox Code Playgroud)

这导致 Visual Studio 出现此错误:

TS2691:(TS) 导入路径不能以“.ts”扩展名结尾。考虑导入“./Module.js”。

TypeScript 编译器似乎忽略了该错误,因为当我运行 Gulp 任务时,它会按预期编译 TypeScript 文件。阅读有关“.ts”扩展名的 GitHub 讨论,似乎最新版本 TypeScript 的推荐解决方案是向文件添加几个属性tsconfig.json

{
  "allowImportingTsExtensions": true,
  "moduleResolution": "bundler",
  "noEmit": true
}
Run Code Online (Sandbox Code Playgroud)

这导致 Visual Studio 给出更多错误:

(TS) 未知的编译器选项“allowImportingTsExtensions”。

(TS) “--moduleResolution”选项的参数必须是:“node”、“classic”、“node16”、“nodenext”。

所有这一切最终导致我根本无法构建该项目。现在,我只是在一个实验项目中,在弄清楚新的 Gulp 实现后我将扔掉它,但如果我将这些更改应用到我的实际项目中,那么我将永远无法编译它们。

我需要做什么来解决这些错误?我尝试在项目属性中抑制TS2691,但没有效果。我还尝试从 NuGet TypeScript 包切换到 npm TypeScript 包,但也没有效果。作为参考,我使用的是 Visual Studio 2022、TypeScript 4.9.5 和 Rollup 3.17.3。

T.J*_*der 5

如果您使用的是现代捆绑程序,请删除allowImportingTsExtensions、设置moduleResolution"node",并在导入中保留文件扩展名。现代捆绑程序知道文件扩展名不存在。


如果您没有使用捆绑器,那么答案将是(在我看来很奇怪)您必须.jsimport语句中使用,即使您的源文件是.ts文件。这是因为 TypeScript 不会重写模块说明符(作为策略决定)。因此,如果你有index.tsimport from mod.ts,你必须import { something } from "./mod.js";这样编写,以便它像编译器生成的 JavaScript 中那样,并且浏览器可以正确处理它。


Gup*_*R4c 4

TypeScript 5 发布后更新

TypeScript 5 发布后,我决定尝试一个没有作弊的干净解决方案,现在它可以按预期工作。我必须在 tsconfig.json 中设置以下内容:

{
  "compilerOptions": {
    "allowImportingTsExtensions": true,
    "moduleResolution": "bundler"
  }
}
Run Code Online (Sandbox Code Playgroud)

我还删除了gulp-replacegulp 任务并将其减少为:

gulp.task(taskTsRollup, () => rollup.rollup({
    input: inputTs,
    plugins: [
        rollupTypeScript,
        rollupTerser()
    ]
}).then(
    _ => _.write({
        file: targetJs,
        format: "iife",
        sourcemap: false
    })));
Run Code Online (Sandbox Code Playgroud)

更多信息请参阅发布 TypeScript 5.0帖子。


最后我用欺骗的方式绕过了它。由于 Rollup 需要扩展而 TypeScript 不需要扩展,因此我决定为他们提供所需的内容。

为此,我首先有一个 gulp 任务来复制输入文件,因此从Default.tsDefault.ts-copy. 然后,gulp-replace我使用正则表达式来匹配导入模式并重写该值以包含扩展名。然后复制和修改的文件被传递到 Rollup,它完成它的事情,最后我删除复制文件。

这样我就可以让 TypeScript 对没有扩展名感到满意,并且 Rollup 会收到带有扩展名的修改后的文件。大家都很高兴。这是最终的 Gulp 任务:

gulp.task(taskTsRollup, gulp.series(
    () => gulp
        .src(inputTs)
        .pipe(gulpRename(`${inputTs}-copy`))
        .pipe(gulpReplace(/from\s+\".\/([a-zA-Z0-9_-]+)\"\;/g, "from \".\/$1.ts\";"))
        .pipe(gulp.dest(`${rootResources}/Scripts`)),
    () => rollup.rollup({
        input: `${inputTs}-copy`,
        plugins: [
            rollupTypeScript,
            rollupTerser()
        ]
    }).then(
        _ => _.write({
            file: targetJs,
            format: "iife",
            sourcemap: false
        })),
    () => del([
        `${rootResources}/Scripts/${inputTs}-copy`
    ])
));
Run Code Online (Sandbox Code Playgroud)

也许将来 TypeScript 语言服务会追随编译器的脚步并支持所有配置选项。