语法错误:在Gulp + Babel + TypeScript + Source Maps中,“import”和“export”只能与“sourceType:module”一起使用。

11

我正在尝试将.ts编译为.min.js,如下所示:

TS --> ES6 ---> ES5 ---> .min.js + .map

之前我只是按照以下步骤操作,一切都正常:

TS ---> ES5 --->  .min.js + .map

我希望能够使用源代码映射。我的tsconfig.json文件如下:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "moduleResolution": "node",
    "isolatedModules": false,
    "jsx": "react",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "declaration": false,
    "noImplicitAny": false,
    "removeComments": true,
    "noLib": false,
    "preserveConstEnums": true,
    "suppressImplicitAnyIndexErrors": true
  }
}

自从我添加了"target": "es6",我就遇到了以下错误:

SyntaxError: 'import' and 'export' may appear only with 'sourceType: module'

tsify文档中指出:

当TypeScript文件在通过Browserify打包器运行之前未被编译为JavaScript时,会发生此错误。你可能会遇到几个已知的原因。

但是在我的Gulp任务中,我先运行tsify再运行babelify:

gulp.task("bundle", function() {

  var mainTsFilePath = "src/main.ts";
  var outputFolder   = "bundle/src/";
  var outputFileName = settings.projectName + ".min.js";
  var pkg            = require("./package.json");

  var banner = [
    "/**",
    " * <%= pkg.name %> v.<%= pkg.version %> - <%= pkg.description %>",
    " * Copyright (c) 2015 <%= pkg.author %>",
    " * <%= pkg.license %>",
    " */", ""
  ].join("\n");

  var bundler = browserify({
    debug: true,
    standalone : settings.projectName
  });

  var babelifyConfig = { extensions: ['.js','.jsx','.ts','.tsx'] };

  // TS compiler options are in tsconfig.json file
  return bundler.plugin(tsify)
                // Added this line and target es6
                .transform(babelify.configure(babelifyConfig)) 
                .add(mainTsFilePath)
                .bundle()
                .pipe(source(outputFileName))
                .pipe(buffer())
                .pipe(sourcemaps.init({ loadMaps: true }))
                .pipe(uglify())
                .pipe(header(banner, { pkg : pkg } ))
                .pipe(sourcemaps.write("."))
                .pipe(gulp.dest(outputFolder));
});

我刚刚添加了ES6编译,之前我将TS编译成ES5,一切都运行良好(包括源映射)。

我不知道出了什么问题。你有任何想法吗?提前感谢!


你为什么要先用typescript生成ES6,然后再用babelify转换成ES5呢?这样做有什么特别的原因吗?你的babelifyConfig是怎么样的呢? - FlorianTopf
计划是让 Babel 处理 polyfills,因为它比 TypeScript 更擅长这项工作,所以我可以从 TS 中获得字符串类型的好处,从 Babel 中获得 polyfills 的好处。我的 babelify 配置仅设置了一些扩展名:var babelifyConfig = { extensions: ['.js','.jsx','.ts','.tsx'] }; - Remo H. Jansen
@RemoH.Jansen 你解决了吗? - James M
1
解决了自己的问题。我将授予奖励,以获得有关gulp、tsify和babelify如何协同工作的良好解释。 - James M
3个回答

2
似乎 browserify 存在解析符号链接变换的问题。然而,自从这个提交(this commit)开始使用了 fs.realpathSync 方法,该方法返回规范化的绝对路径名,这个问题应该已经被解决了。并且这个修复已经在 node-browserify10.2.5 版本中发布了。
正如 James 所提到的,如果你无法升级到更新的版本,你可以查看他的答案,使用 realpathify 来解决相同的问题。详见fixes Gulp和Browerify如何协同工作是相当有趣的,因为它是少数几个实际上不需要相关gulp插件的工具之一(甚至曾经blacklisted过,以强制用户直接使用browserify包)。这不需要插件的原因是由于@substack,他是browserify和tape的创建者,非常熟悉(我假设他喜欢)在这两个项目中使用的node-streams。鉴于这个前提,以及99%的gulp插件只是将他们想要使用的工具与流连接起来,因此不需要gulp插件,因为browserify已经在使用你可以在任务中返回的流。

小小的侧记,他还写了一本关于在node中进行流处理的handbook,如果您想更多地了解gulp内部工作原理,那么它值得一看。

关于tsify,它的工作方式与任何其他插件相同,编译typescript文件并将输出传递给流以供browserify进程继续。


2
您遇到错误的原因在Aperçu的回答中有很好的描述。如已提到,更新应该会修复此问题,但如果无法更新,请参考James的回答
Gulp、Babelify和TSify共同作用于将您的代码从TypeScript ES2015转换为浏览器兼容的纯ES5模块化代码。以下是它们的基本介绍:
  • Gulp - 任务运行器,使用流来允许您组合并执行某些较小的任务以提高效率和简化构建过程

  • Babelify - Browserify转换器,将您的文件就地转换为纯JavaScript,然后根据您的预设和插件与浏览器兼容;Babel适用于Browserify

  • TSify - Browserify插件,将您的TypeScript编译为浏览器可用的JavaScript

使用 Gulp,您可以设置 Browserify 插件,将 TypeScript 文件转换为 ECMAScript 2015 文件,并在一个简单的任务中完成。不要使用被列入黑名单的 gulp-browserify,而是直接使用 browserify 包,因为它已经使用了流,这正是 Gulp 所期望的,所以不需要额外的 Gulp 插件。
现在让我们来看看它们如何一起工作。把 Gulp 想象成一个制作苹果派的工厂,而您的 Gulp 任务则是工厂执行的某些任务,以便它可以创建最终产品:制作面团、制作馅料、烘焙派等。假设我想制作馅料,我需要先:
- 挑选一些苹果并导入它们 - 使用柠檬汁调味处理苹果 - 加热然后添加所有配料 - 让它煨煮并冷却,直到准备好进行下一阶段
这些就像您在 Gulp 任务中的某些部分。如果我想从 TypeScript 创建可在浏览器中运行的 JavaScript,我会类似地:
  • 选择要转译的目标文件
  • 使用插件(TSify)转换目标文件并将其编译为ES2015(在这种情况下)
  • 使用转换器(Babelify)转换目标文件,将它们从TSify的ES2015转译为浏览器的ES5

应用到实际代码中,我们得到:

  1. 创建一个新的Gulp任务,将我们的代码从TypeScript ES2015转译为纯ES5
  2. 使用 browserify 实例和流来选择代码将被转译的入口文件,然后将它们传递到流中
  3. 继续处理流中的文件,通过注册一个名为 tsify 的插件,将 TypeScript 文件转换为 ES2015(如果目标是 ES2015),然后将它们传递到流中
  4. 将流中的新ES2015文件交给 babelify 处理,使用预设的 es2015 将 ES2015 转换为浏览器友好的 ES5,然后将它们传递到流中以继续管道的处理
所有部分协同工作,使您能够完成多项任务,并最终将您的TypeScript转换为ES5。

1
你基本上只是指向我们的答案,复制粘贴了一个段落,加上了它们各自的描述列表和 gulp 的基本解释(完全超出范围)。下次请尝试更有创意一些。 - Preview
@Aperçu 如果你发现有任何抄袭行为,请随时标记我的回答。悬赏海报说对Gulp、TSify和Babelify进行深入解释以及它们如何共同工作将是符合悬赏要求的,而这正是我所做的。另外,为了未来读者的利益,请恢复你的回答,它真的很有价值。 - Andrew Li
2
不,他绝对没有要求解释它们分别是什么,请重新阅读。您还必须了解,即使有赏金,您也必须尝试保持与初始OP的主题相关。此外,我认为您并不真正觉得它有价值,否则您会投票支持它,对吗? - Preview
1
@Aperçu 你说得对,我想我被赏金冲昏了头脑。我会在我的答案中加上一个标记,使其成为社区维基。我强烈建议你恢复你的答案,因为它实际上回答了问题,而我的则没有像你提到的那样。 - Andrew Li
我不认为这会改变什么,但感谢您的认可。 - Preview

0

我曾经遇到过同样的问题,这是由于在我的node_modules中有符号链接引起的。我通过将realpathify插件添加到browserify中来解决它。

var gulp = require("gulp")
var browserify = require("browserify")
var babelify = require("babelify")
var source = require('vinyl-source-stream')
var tsify = require("tsify")
var sourcemaps = require('gulp-sourcemaps')
var buffer = require('vinyl-buffer');
var realpathify = require('realpathify')

gulp.task("default", function () {

    browserify({
        basedir: '.',
        debug: true,
        cache: {},
        packageCache: {},
        entries: [ 'app/browser.ts' ]
    })
    .plugin(tsify)
    .plugin(realpathify)
    .transform(babelify, {extensions: ['.js', '.ts'], presets: ['es2015']})
    .bundle()
    .on('error', function (error) { report(error) })
    .pipe(source('bundle.js'))
    .pipe(buffer())
    .pipe(sourcemaps.init({loadMaps: true}))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest("dist"))
})

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