使用TypeScript和Babel的Gulp源映射

7

我正在编写一个副业项目,以便更深入地学习TypeScript和ES6(使用babel)。

我想在TypeScript中使用ES6,因此采用了以下工作流程。

Typescript (ES6) -> Babel (ES6) -> ES5

现在我正在使用Gulp自动化所有这些内容,但我很难正确生成sourcemaps。需要提到的是,这种风格是/r/typescript上的用户建议给我的,因此我甚至不确定它是否可行。

不管怎样,这里是我当前的gulp任务:

var server = $.typescript.createProject('src/server/tsconfig.json');
gulp.task('build', ['vet'], function () {
  var sourceRoot = path.join(__dirname, 'src/server/**/*.ts');
  return gulp.src('src/server/**/*.ts')
    .pipe($.sourcemaps.init())
      .pipe($.typescript(server))
      .pipe($.babel())
    .pipe($.sourcemaps.write('.', { sourceRoot: sourceRoot}))
    .pipe(gulp.dest('build/server'));
});

我尝试了许多不同的方法,但都没有成功。当我在VSCode中进行调试时,我的应用程序入口点: build/server/index.js 正确加载并找到源文件 src/server/index.ts
然而,当VSCode尝试步入另一个文件,比如 build/server/utils/logger/index.js 时,它会查找 src/server/utils/logger/index.js ,但是它找不到应该寻找 *.ts 文件。
所以我做错了什么?或者这是否可能?已经盯着它看了大约 5 小时。所以任何见解都很好。
此外,VSCode 0.9.x 显示 '.../.js' 文件未找到 ,而 VSCode 1.0 只是默默失败。
这是我的 tsconfig.json,它由 $.typescript.createProject() 传递。
{
  "compilerOptions": {
    "module": "commonjs",
    "noImplicitAny": true,
    "removeComments": true,
    "preserveConstEnums": true,
    "target": "ES6",
    "sourceMap": true,
    "outDir": "build/server"
  }
}

.babelrc

{
  "presets": ["es2015"]
}

这里是相关的npm包

"devDependencies": {
    "babel-polyfill": "^6.2.0",
    "babel-preset-es2015": "^6.1.18",
    "gulp-babel": "^6.1.0",
    "gulp-sourcemaps": "^1.6.0",
    "gulp-typescript": "^2.9.2"
}

编辑:我对gulp-sourcemaps进行了一些调查,发现在不使用babel的情况下,sourcemaps可以正常工作。(删除了所有无关信息)

src/server/up/up2/four.ts - 无Babel

{
  "history": [ "/home/user/code/test/src/server/up/up2/four.js" ],
  "base": "/home/user/code/test/src/server/",
  "sourceMap": {
    "sources": ["up/up2/four.ts"],
    "file": "up/up2/four.js"
  }
}

注意,sourceMap.sources 中列出了正确的源文件 up/up2/four.ts

现在这里有一个示例,当我将 gulp-babel 添加到任务中时。

src/server/up/up2/four.ts - 使用 Babel

{
  "history": [ "/home/user/code/test/src/server/up/up2/four.js" ],
  "base": "/home/user/code/test/src/server/",
  "sourceMap": {
    "sources": ["four.js"],
    "file": "up/up2/four.js"
  },
  "babel": {
    "...": "..."
  }
}

请注意,sourceMap.sources 现在错误地显示了 four.js 而不是 typescript 文件。
有趣的是,只要 typescript 文件位于根目录下的 src/server,它们就可以很好地构建源映射。 src/server/two.ts - 使用 Babel
{
  "history": [ "/home/user/code/test/src/server/two.js" ],
  "base": "/home/user/code/test/src/server/",
  "sourceMap": {
    "sources": ["two.ts"],
    "file": "two.js"
  },
  "babel": {
    "...": "..."
  }
}

你能否编辑问题并附上你的TypeScript和Babel配置? - Igor Raush
我已经添加了我的tsconfig.json、相关的package.json和.babelrc。这是我第一次使用babel,根据文档,这就是我想到的。 - jordond
谢谢,请看下面我的回答。你不想只针对ES5使用TypeScript并完全跳过Babel的原因是什么?我知道在TS中,特性支持和规范兼容性都比较差,但在过去的一些相当复杂的项目中,这种方式已经行之有效了。 - Igor Raush
我想我只是想尝试一下ES6,这并不是必要的,但我认为学习它会很有趣。 - jordond
Typescript是ES6的超集。您可以将其编译为纯ES6(基本上只需删除类型),然后使用Babel编译为ES5,就像现在所做的那样。或者,您可以直接将其编译为ES5(跳过中间步骤)。后者将让您跳过构建步骤,但输出的ES5兼容性会较低。 - Igor Raush
1个回答

3

更新

看起来这个问题与Babel生成源映射不正确有关,这些文件不在工作目录中。已经在这里提出了一个问题。

对于vinyl文件对象,例如:

new File({
  cwd: '.',
  base: './test/',
  path: './test/some/file.js'
  ...
});

生成的源映射应该有类似以下内容:
{
  ...
  "sources": ["some/file.js"]
  ...
}

但是gulp-babel提供了
{
  ...
  "sources": ["file.js"]
  ...
}

这会导致Typescript源映射和Babel源映射在文件深度超过工作目录时被错误合并。

在解决此问题之前,我建议使用Typescript以ES5为目标,并完全绕过Babel。这将产生正确的源映射。

gulp.task('build', function () {
  return gulp.src('src/server/**/*.ts')
    .pipe(sourcemaps.init())
    .pipe(typescript({
      noImplicitAny: true,
      removeComments: true,
      preserveConstEnums: true,
      target: 'es5',
      module: 'commonjs'
    }))
    .pipe(sourcemaps.write('.', { sourceRoot: 'src/server' }))
    .pipe(gulp.dest('build/server'));
});

之前的回答

你很接近了,但我注意到你的配置中有几个错误:

  1. "module": "commonjs""target": "es6" 不兼容。请使用Typescript输出ES6模块,并使用Babel将其转换为CommonJS。
  2. 使用Gulp时不需要"outDir",因为你正在使用流。中间结果(即Typescript的结果)根本不会写入磁盘。
  3. "sourceMap": true 不需要与 Gulp的 sourcemaps 一起使用。

我创建了一个项目,该项目对我来说编译成功了,使用的是babel@6.1.18和typescript@1.6.2。

目录结构

.
├── gulpfile.js
└── src
    └── server
        ├── one.ts
        └── two.ts

one.ts

export class One {};

two.ts

import { One } from './one';

export class Two extends One {}

gulpfile.js

我已经将所有配置内联以简洁明了,但你同样可以轻松使用配置文件。

var gulp = require('gulp');

var sourcemaps = require('gulp-sourcemaps');
var typescript = require('gulp-typescript');
var babel = require('gulp-babel');

gulp.task('build', function () {
  return gulp.src('src/server/**/*.ts')
    .pipe(sourcemaps.init())
    .pipe(typescript({
      noImplicitAny: true,
      removeComments: true,
      preserveConstEnums: true,
      target: 'es6'
    }))
    .pipe(babel({
      presets: [ 'es2015' ]
    }))
    .pipe(sourcemaps.write('.', { sourceRoot: 'src/server' }))
    .pipe(gulp.dest('build/server'));
});

我已经设置了一个与您提供的示例程序类似的示例程序。我从未遇到编译该程序的问题。但当我使用sourcemaps进行调试时遇到了问题。我已经做了更多的研究,并将我的发现添加到第一篇帖子中。 - jordond
你是如何调试你的程序的?我已经使用这个模块做了一个快速检查,看起来生成的源映射正确地映射了回溯信息。 - Igor Raush
有趣的是,我也能够重现这个问题。这个链接可能会有所帮助。 - Igor Raush
我进一步研究了一下。看起来 gulp-babel 没有遵循这些说明,特别是关于 file.relative 的第二个要点。他们总是使用基本名称。他们生成的源映射无法应用于现有的 TypeScript 映射之上。我将在接下来的一两天内编写一个可运行的示例并提交问题。 - Igor Raush
原来已经有一个问题被提交了。我已经编辑了我的答案。你可以暂时放弃Babel,使用Typescript生成的ES5输出和源映射。它们似乎是正确的。 - Igor Raush
显示剩余3条评论

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