语法错误:'import'和'export'只能与'sourceType: module'一起使用 - Gulp

89

考虑以下两个文件:

app.js

import Game       from './game/game';
import React      from 'react';
import ReactDOM   from 'react-dom';

export default (absPath) => {
  let gameElement = document.getElementById("container");

  if (gameElement !== null) {
      ReactDOM.render(
          <Game mainPath={absPath} />,
          gameElement
      );
  }
}

index.js

import App from './src/app';

gulpfile.js

var gulp        = require('gulp');
var source      = require('vinyl-source-stream');
var browserify  = require('browserify');
var babelify    = require("babelify");
var watch       = require('gulp-watch');

gulp.task('make:game', function(){
  return browserify({
    entries: [
      'index.js'
    ]
  })
  .transform('babelify')
  .bundle()
  .pipe(source('index.js'))
  .pipe(gulp.dest('app/'));
});

错误:

gulp make:game
[13:09:48] Using gulpfile ~/Documents/ice-cream/gulpfile.js
[13:09:48] Starting 'make:game'...

events.js:154
      throw er; // Unhandled 'error' event
      ^
SyntaxError: 'import' and 'export' may appear only with 'sourceType: module'

这是什么错误?我做错了什么?


1
请查看GitHub上的此问题。使用较新版本的Babel和babelify似乎存在问题。 - Mike Cluck
1
在我的情况下,我没有使用babelify,但仍然遇到了这个错误。 - Kokodoko
在我的情况下,当我尝试编译导入TypeScript文件的JS文件时(例如import * as Foo from "./foo" (foo.ts)),我使用browserify和babelify遇到了这个错误。解决方法是将--extensions ".ts,.js"传递给babelify转换器(这样babel就会包含TS文件进行编译),并将--extension=.js --extension=.ts传递给browserify(这样browserify可以解析导入语句的文件路径)。请注意,babel的--extensions选项似乎没有在babel选项中记录 - 我在这里找到了它。 - Galen Long
12个回答

38

ESLint本身不原生支持这一点,因为这违反了规范。但是,如果你使用babel-eslint解析器,那么在你的eslint配置文件中可以这样做:

{
    "parser": "babel-eslint",
    "parserOptions": {
        "sourceType": "module",
        "allowImportExportEverywhere": true
    }
}

还请参考Github参考文档这里的答案引用


解决方案对我无效。尽管更改了eslintrc,但仍然出现相同的错误消息。 - Julius Goddard
2
"parserOptions": { "sourceType": "module", "allowImportExportEverywhere": true } 只有这个更改才对我起作用。 - prasun

33

旧版本的Babel带有一切必要的内容。新版本需要您安装任何设置所需的插件。首先,您需要安装ES2015预设。

npm install babel-preset-es2015 --save-dev

接下来,你需要告诉babelify使用你安装的预设。

return browserify({ ... })
  .transform(babelify.configure({
    presets: ["es2015"]
  }))
  ...

来源


2
我完全删除了这个包,不知道我需要它来支持babel 6.17。有趣。谢谢。 - TheWebs
请问您能否用Webpack在Angular 2中展示这个例子? - sainu
@sainu 在Angular官网上有一个全面的教程,可以帮助你入门Angular,并提供支持importexport的开发环境。更不用说这个问题是关于使用Browserify,而不是Webpack。 - Mike Cluck
1
我还需要执行-- npm install babel-preset-env命令。然后,从命令行中执行以下操作: browserify src/app.js -t [ stringify --extensions [ .bpmn ] ] -g [ babelify --presets [ "es2015" ] ] -o src/app.bundled.js - George Beier
@MikeCluck,能否请您澄清babelify.configure步骤?您的代码片段中说它会返回browserify,但是是从哪个函数返回呢?我该如何全局地让我的TypeScript在ES6中运行? - emery
我在使用shelex/allure报告时遇到了这个问题,即使添加了babel也无法解决该问题。 - Ashok kumar Ganesan

25
我在尝试从“ node_modules” 导入以 ES6 风格导出的模块时遇到了相同的错误。 SO 上提出的所有建议都没有起作用。后来我在 babelify repo 的 FAQ 部分找到了相关信息。根据那里的见解,该错误是由于默认情况下不对来自“ node_modules”的模块进行转译,并且其中类似于export default ModuleName的 ES6 声明无法被使用 Common.js 风格模块的node所理解。
因此,我更新了我的包,并使用global选项运行 babelify 作为全局转换,排除了除我感兴趣的模块之外的所有节点模块,如 babelify 存储库页面所示:
...    
browserify.transform("babelify", 
    {
        presets: ["@babel/preset-env"], 
        sourceMaps: true, 
        global: true, 
        ignore: [/\/node_modules\/(?!your module folder\/)/]
    }).bundle()
...

希望这可以帮助到你。


6
完成拯救。这是正确答案,因为你应该使用 preset-env 而不是 es2015 - Mist
1
你能解释一下在node_modules里面"your module folder"应该是什么吗?我看了repo的readme文件,但也没有明确说明。 - Nikolay Dyankov
1
@NikolayDyankov,这实际上是所需软件包的文件夹,通常会放置某种入口点(导出您需要的内容)。通常情况下,它是一个包含index.js等文件的文件夹,相当于软件包的根目录。希望你明白了。 - curveball
我尝试了上述方法,但对我无效。你能看一下这个问题吗? - Ashok kumar Ganesan

19
由于某些原因,babelify 8.0.0 对我来说无法使用 es2015 或 env。然而,截至2018-07-10mattdeslesmify 插件对我有用。我的测试案例是将 Spinnerspin.js 导出为 window 全局变量。我的示例代码库在 here;下面是关键细节。

main.js

import {Spinner} from 'spin.js';
window.Spinner = Spinner;

测试

在一个空目录中:

npm init

并接受所有默认值,然后:

npm install --save spin.js
npm install --save-dev browserify esmify
npx browserify -p esmify main.js -o main-packed.js

测试HTML文件

<html><head>
    <link rel="stylesheet" href="node_modules/spin.js/spin.css" />
    <script src="main-packed.js"></script>    <!-- <== the browserify output -->
</head>
<body>
    <div id="x"></div>
    <script>
    var target = document.getElementById('x');
    var spin = new Spinner().spin(target);
    </script>
</body></html>

加载时,在页面中央显示旋转的图标。

注:本人与mattdesl或esmify无关联。


6
"esmify"可以胜任这项工作! - Marinos An
esmify为我做到了。@cxw的示例仓库效果非常好! - Yazid

16

.eslintrc文件中,您可能需要指定解析器选项,例如:

{
    "rules": {
        "indent": [
            2,
            4
        ],
        "linebreak-style": [
            2,
            "unix"
        ],
        "semi": [
            2,
            "always"
        ]
    },
    "env": {
        "es6": true,
        "browser": true,
        "node": true,
        "mocha": true
    },
    "extends": "eslint:recommended",
    "parserOptions": {
        "ecmaVersion": 6,
        "sourceType": "module",
        "ecmaFeatures": {
            "jsx": true
        }
    }
}
请查看来自eslint的文档指南:eslint

6

为了正确编译es2015-react代码,您需要安装一些节点模块:

全局安装

npm install -g browserify

在您的应用程序目录中:

npm install --save-dev browserify babelify babel-preset-es2015 babel-preset-stage-0 babel-preset-react

然后创建gulp任务:
    var browserify = require("browserify");
    var babelify = require("babelify");

    gulp.task('es6-compile', function() {
      browserify({ debug: true })
        .transform(babelify.configure({ presets: ["es2015","react", "stage-0"] }))
        .require("./public/src/javascripts/app.js", { entry: true })
        .bundle()
        .pipe(gulp.dest('./public/dest/javascripts'));
    });

在./public/dest/javascripts目录中,您将找到编译后的es5 app.js文件。

14
我不使用Babel,我只想使用Browserify来捆绑模块。使用import / export这种方式可以实现吗? - Kokodoko

4
如果想要将npm中通过import或require方法使用到客户端上,只需要按照以下步骤进行操作:
1. 运行命令"npm install browserify babelify @babel/preset-env @babel/preset-react @babel/core es2015 --save-dev"来安装所需的预设。 2. 将以下代码添加到你的package.json文件中。
"babel": {
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ] 
}
  1. /app文件夹中创建一个名为dom_front.js的文件,该文件将被转换为客户端js。
const ReactDOM  = require('react-dom')
import React, {Component} from 'react' 
export {Component,React,ReactDOM};

这是模块和require文件的混合导出数据。

注意:不要忘记安装react-dom和react

  1. 使用browserify api - 创建js文件,例如browserifyload.js和assets文件夹。
const browserify = require("browserify")
const fs = require('fs')
browserify("./dom_front.js", {
  debug : true,
  standalone: "util"
}).transform(['babelify', { compact: false }], {
  global: true,                                  
  ignore: [/\/node_modules\/(?!@vizuaalog\/)/],     
  presets: [ 
    "@babel/preset-env",
    "@babel/preset-react"] 
  }).bundle().on('error', function (err) {
    console.log(err);  
  }).pipe(fs.createWriteStream('assets/mynpmmodule.js')).on('end', function(){
    console.log( 'finished writing the browserify file' );
  });

现在文件夹结构如下:
app
--dom_front.js
--browserifyload.js
--assets(folder)
  1. 运行命令/node_proj/app$ node browserifyload.js或者运行命令/node_proj/app$ browserify dom_front.js --transform babelify --standalone util > ./assets/mynpmmodule.js
  2. 检查assets文件夹,现在它会创建一个名为mynpmmodule.js的文件。
  3. 将该文件添加到HTML中<script src="assets/mynpmmodule.js"></script>
  4. 现在您可以使用导出的npm模块/类或使用上述"util"单独键所需的文件。
<script>
  const Component = util.Component;
  console.log(Component);
  const ReactDOM = util.ReactDOM;
</script>

0
给那些为了让TypeScript在babelify中工作而抓狂的人点个赞。事实证明,如果你没有在babelify选项的extensions中添加.ts,那么'import'和'export'只能与'sourceType: module'一起出现的错误也会发生。请注意,你可能需要在browserifyoptionsbabelifyoptions中都指定extensions
...
const babelify = require('babelify');

var appBundler = browserify({
  entries: ["./index.ts"],
  debug: true,
  extensions: [".js", ".jsx", ".ts", ".tsx"],
})
  .transform(babelify.configure({
    "presets": [
      "@babel/preset-env",
      "@babel/preset-react",
      ["@babel/preset-typescript", { isTSX: true, allExtensions: true }],
    ],
    extensions: [".js", ".jsx", ".ts", ".tsx"], // <============= fix here
  }))
  .bundle()
  .pipe(source("index.js"))
  .pipe(gulp.dest('app/'));

0
    return browserify(jsConfig.src)
  .transform(babelify.configure({
    presets: ["@babel/preset-env"]
  }))
  .bundle()
  .on('error', function (e) {
    console.log(e.message);

    this.emit('end');
  })

对我来说可行。


0

我尝试了以上所有的答案,但它们都对我无效。 我甚至尝试使用gulp-include/require语法,但它们都不是我要求的解决方案或不足以满足我的需求。

这是我的要求:

  1. 将所有模块/文件捆绑成一个文件。
  2. 保留所有注释/JSDocs。
  3. 保留所有类型(例如 const example = (parameter: string) => {} )。
  4. 使用 import/export 语法。

列出这些要求的原因是因为我们需要一个存储共享函数、共享配置、共享类型和共享常量的仓库作为 npm 包(使用 URL 进行安装)。在这种情况下,我们已经知道我们的项目都在使用 TypeScript,因此没有必要将我们的共享模块编译为.js文件,并且我们还需要像其他包一样保留所有描述(JSDoc 和 Type 确实有帮助)。

到目前为止,我能做到的最好的是使用 browserifytsify。我偶然在这里发现了这个解决方法。

browserify()
    .plugin(tsify, { target: 'es6' })
    .transform(babelify, { extensions: [ '.tsx', '.ts' ] })

我仍在寻找一种方法来保留我们的内联类型和注释/JSDocs,但我相信这对您的需求已足够。


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