SyntaxError: 'import' and 'export' may appear only with 'sourceType: module' - Gulp
Asked Answered
D

14

92

Consider the following two files:

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';

The 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/'));
});

The error:

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'

What is this error? What am I doing wrong?

Deathless answered 13/10, 2016 at 19:13 Comment(3)
See this issue on GitHub. It seems to be a problem with using a newer version of Babel with babelify.Milden
In my case, I am not using babelify but still get this error.Sebbie
In my case, I was getting this error with browserify and babelify when trying to compile JS files that imported TypeScript files, e.g. import * as Foo from "./foo" (foo.ts). The fix was to pass --extensions ".ts,.js" to the babelify transform (so babel would include TS files in compilation) and --extension=.js --extension=.ts to browserify (so browserify could resolve the filepaths of import statements). Note that the babel --extensions option doesn't seem to be documented in the babel options - I found out about it here.Pontic
M
33

Older versions of Babel came with everything out of the box. The newer version requires you install whichever plugins your setup needs. First, you'll need to install the ES2015 preset.

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

Next, you need to tell babelify to use the preset you installed.

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

Source

Milden answered 13/10, 2016 at 19:19 Comment(7)
I totally removed this package not knowing I needed it for babel 6.17. Interesting.Thank you.Deathless
can you please show this example with webpack in angular 2Ocotillo
@Ocotillo There is a full-fledged tutorial on how to get started with Angular that will give you a development environment which supports import and export. Not to mention this question is about using Browserify, not Webpack.Milden
I also needed -- npm install babel-preset-env Then, from the command line, did: browserify src/app.js -t [ stringify --extensions [ .bpmn ] ] -g [ babelify --presets [ "es2015" ] ] -o src/app.bundled.jsOmasum
@MikeCluck could you please clarify the babelify.configure step? Your code snippet says that it returns browserify, but from what function? How can I globally cause my typescript to run in ES6?Valdez
I get this issue for shelex/allure reporting even adding babel does not fix the issueTangleberry
return browserify({ ... }) .transform(babelify.configure({ presets: ["es2015"] })) can you tell me the file pathThynne
I
40

ESLint natively doesnt support this because this is against the spec. But if you use babel-eslint parser then inside your eslint config file you can do this:

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

Also consider the Github reference doc and the answer referred from here.

Isolated answered 5/10, 2018 at 17:59 Comment(2)
Solution does not work for me. Same error message despite changing eslintrc.Husain
"parserOptions": { "sourceType": "module", "allowImportExportEverywhere": true } only with this change it worked for me.Azotize
M
33

Older versions of Babel came with everything out of the box. The newer version requires you install whichever plugins your setup needs. First, you'll need to install the ES2015 preset.

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

Next, you need to tell babelify to use the preset you installed.

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

Source

Milden answered 13/10, 2016 at 19:19 Comment(7)
I totally removed this package not knowing I needed it for babel 6.17. Interesting.Thank you.Deathless
can you please show this example with webpack in angular 2Ocotillo
@Ocotillo There is a full-fledged tutorial on how to get started with Angular that will give you a development environment which supports import and export. Not to mention this question is about using Browserify, not Webpack.Milden
I also needed -- npm install babel-preset-env Then, from the command line, did: browserify src/app.js -t [ stringify --extensions [ .bpmn ] ] -g [ babelify --presets [ "es2015" ] ] -o src/app.bundled.jsOmasum
@MikeCluck could you please clarify the babelify.configure step? Your code snippet says that it returns browserify, but from what function? How can I globally cause my typescript to run in ES6?Valdez
I get this issue for shelex/allure reporting even adding babel does not fix the issueTangleberry
return browserify({ ... }) .transform(babelify.configure({ presets: ["es2015"] })) can you tell me the file pathThynne
M
26

I came across the same error trying to import a module from node_modules that exports in ES6 style. Nothing that has been suggested on SO worked out for me. Then I found FAQ section on babelify repo. According to the insight from there, the error appears since modules from node_modules are not transpiled by default and ES6 declarations like export default ModuleName in them are not understood by node powered by Common.js-style modules.

So, I updated my packages and then used global option to run babelify as a global transform excluding all node modules but the one I was interested in as indicated on the babelify repo page:

...    
browserify.transform("babelify", 
    {
        presets: ["@babel/preset-env"], 
        sourceMaps: true, 
        global: true, 
        ignore: [/\/node_modules\/(?!your module folder\/)/]
    }).bundle()
...

Hope it helps.

Muscatel answered 15/6, 2019 at 8:44 Comment(4)
Saved the day. This is the correct answer as you should use preset-env and not the es2015Plutonium
could you explain what "your module folder" is supposed to be inside node_modules? I looked at the repo readme but it didn't make it clear either.Ora
@NikolayDyankov it is literally the folder of desired package where some kind of entry point (that exports something you need) is usually located. Typically, it is a folder where index.js and the like are placed. Kind of root of the package. Hope you get the idea.Muscatel
I tried the above and does not work for me. Can you look at this questionTangleberry
D
19

For some reason, babelify 8.0.0 didn't work for me with either the es2015 or env presents. However, as of 2018-07-10, the esmify plugin by mattdesl did work for me. My test case was exporting Spinner from spin.js as a window global. My example repo is here; key details follow.

main.js

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

Test

In an empty directory:

npm init

and accept all defaults, then:

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

Test HTML file

<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>

When loaded, it displays a spinner in the center of the page.

Note: I am not affiliated with mattdesl or esmify.

Dragonhead answered 4/9, 2018 at 14:8 Comment(2)
esmify does the job!Bores
esmify did it for me. @Dragonhead example repo works wonder!Schreibe
T
16

In .eslintrc you may have to specify the parser options, for example:

{
    "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
        }
    }
}

Please check the documentation guide from eslint.

Tuyettv answered 4/4, 2019 at 11:36 Comment(0)
C
6

For correct compiling es2015-react code you should install some node modules:

globally

npm install -g browserify

in your app directory:

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

Then create gulp task:

    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'));
    });

In ./public/dest/javascripts directory you will find compiled es5 app.js file.

Consolation answered 28/12, 2016 at 12:12 Comment(1)
I don't use babel, I just want to use browserify to bundle modules. Is that possible with import / export?Sebbie
S
4

If you want to use anything by import or require method in npm to clientside just do the following steps

  1. Run npm install browserify babelify @babel/preset-env @babel/preset-react @babel/core es2015 --save-dev to install the required presets
  2. Add this code into your package.json
"babel": {
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react"
  ] 
}
  1. Create a file named as dom_front.js inside of /app folder the file which you want to convert as clientside js.
const ReactDOM  = require('react-dom')
import React, {Component} from 'react' 
export {Component,React,ReactDOM};

This is the mixed export data of modules and require files.

Note: dont forget to install react-dom & react

  1. Using browserify api - create js file such as browserifyload.js and assets folder
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' );
  });
  1. Now the folder structure is
app
--dom_front.js
--browserifyload.js
--assets(folder)
  1. Run /node_proj/app$ node browserifyload.js or run /node_proj/app$ browserify dom_front.js --transform babelify --standalone util > ./assets/mynpmmodule.js
  2. Check the assets folder, where it now creates the file named as mynpmmodule.js
  3. Add this file into your HTML <script src="assets/mynpmmodule.js"></script>
  4. Now you can use the exported npm modules/classes or required files using the standalone key mentioned above util like
<script>
  const Component = util.Component;
  console.log(Component);
  const ReactDOM = util.ReactDOM;
</script>
Sherborn answered 2/1, 2020 at 7:40 Comment(0)
W
0

I tried all the answers above, none of them worked for me, I even tried using gulp-include / require syntax, they were neither the solution nor enough for my requirement.

Here was my requirement.

  1. Bundle all modules/files into one
  2. Keep all comments/JSDocs
  3. Keep all types ( such as const example = (parameter: string) => {} )
  4. Use import/export syntax

The reason for the listed requirements is because we need a repository to store our shared-function, shared-config, shared-types, and shared constants as an npm package ( install with URL ). In this case, we already know our projects are all using TypeScript so there is no need to compile our shared-module into .js, and we also need to keep all descriptions as other packages do ( JSDoc and Type really help ).

So far the best I can do is using browserify with tsify. I accidentally found this workaround from here.

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

I am still searching for a way to keep our inline-types and comments/JSDocs, but I believe this is enough for your need.

Wellgrounded answered 19/8, 2020 at 7:11 Comment(0)
P
0
    return browserify(jsConfig.src)
  .transform(babelify.configure({
    presets: ["@babel/preset-env"]
  }))
  .bundle()
  .on('error', function (e) {
    console.log(e.message);

    this.emit('end');
  })

Works for me.

Pedalfer answered 15/11, 2021 at 17:10 Comment(0)
S
0

Shutout to everyone pulling their hair in attempts to make typescript work in babelify. As it turns out, the 'import' and 'export' may appear only with 'sourceType: module' error also takes place if you did not add .ts to extensions of babelify options. Note that you may have to specify extensions in both browserify options and babelify options:

...
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/'));
Solothurn answered 30/8, 2023 at 18:48 Comment(0)
T
0

Maybe I have zero votes but please trust me this is the most easy job to get rid of this problem.

You can use esmify to add ES Modules support to browserify:

browserify index.js -p esmify > bundle.js

Refer to the project's readme for more usage info

"ParseError: 'import' and 'export' wont appear again

Therapeutics answered 12/2, 2024 at 14:1 Comment(0)
S
0

I see this happen a lot with embedded JavaScript, like this:

JS (Used with Construct 3)

// Extends Construct 3 'runtime'. Find the engine at https://construct.net

/* WORK IN PROGRESS, DO NOT RUN WITHOUT
- Approval
- Construct 3
*/

/**
* Construct 3 script that:
* - Gets the distance between a player and a monster ('iPlayer' and 'iMonster')
* - Kills the closest monster instance when the player attacks it with the space key
* @author Spicy Development - Gabriel Jemail
* @borrows Construct 3 Event Sheet Scripts
* @copyright Flowfront Games, LLC
* @description Construct 3 script that: Gets the distance between a player and a monster ('iPlayer' and 'iMonster'); Kills the closest monster instance when the player attacks it with the space key.
*/
// -----------------------------------------------------------

// Create an empty array to store roach data
var roachData = [];

// Export 'runtime', since modules.js have trouble with it.
export default {};

// -----------------------------------------------------------
/**
 * Calculates the Euclidean distance between two points.
 * @param {number} x1 - The X coordinate of the first point.
 * @param {number} y1 - The Y coordinate of the first point.
 * @param {number} x2 - The X coordinate of the second point.
 * @param {number} y2 - The Y coordinate of the second point.
 * @returns {number} The calculated distance between the points.
 */
 
// Log the execution
console.info("Kill action triggered");
 
// Define distance(), since the JavaScript engine doesn't know what it is.
function distance(x1, y1, x2, y2) {
    // Test if the parameters are numbers. If not, they cannot be used in the way we want to.
    if (isNaN(x1) || isNaN(y1) || isNaN(x2) || isNaN(y2)) {
        console.error("Input coordinates are not numbers. Try another method.");
        return NaN;  // Or return a specific value to indicate an error
    }
    var dx = x2 - x1;
    var dy = y2 - y1;
    return Math.sqrt(dx * dx + dy * dy);  // Calculate Euclidean distance and return it explicitly
}

// Inside the loop, for each roach:
if (runtime.objects.iMonster) {
  var currentDistance = distance(runtime.objects.iPlayer.getFirstInstance().x, runtime.objects.iPlayer.getFirstInstance().y, runtime.objects.iMonster.getFirstInstance().x, runtime.objects.iMonster.getFirstInstance().y);
  // Use currentDistance here
} 
else {
  console.error("Player or monster object not found!");
}
var roachObject = {
  distance: currentDistance,
  roachInstance: runtime.objects.iMonster.getFirstInstance()
};
roachData.push(roachObject);

// -----------------------------------------------------------

// Function to find the closest roach object in the array
function findClosestRoach(roachDataArray) {
  var closestObject = null;
  for (var i = 0; i < roachDataArray.length; i++) {
    var currentObject = roachDataArray[i];
    if (!closestObject || currentObject.distance < closestObject.distance) {
      closestObject = currentObject;
    }
  }
  return closestObject;
}

// Call the function with the roach data array
var closestRoachObject = findClosestRoach(roachData);

// Access the closest roach instance from the object
if (closestRoachObject) {
  var closestRoachInstance = closestRoachObject.roachInstance;
  // Use the closestRoachInstance for further actions (e.g., get X position)
  
  // Log the values in the console for debugging
  console.log("Distance between player and monster:", currentDistance);
  console.log("Input parameters: " + runtime.objects.iMonster.getFirstInstance().x + ", " + runtime.objects.iMonster.getFirstInstance().y);
  
  // Kill the damn roach (finally)
  closestRoachInstance.destroy();
}

If I try to export something to a script called modules.js, I will get the error

Solution

The error will describe that you can only export at the global scope. This means putting it inside HTML or embedded JavaScript won't work. You can only use an external script. If you're in a similar case to mine, you have to use a global variable and export the variable being accessed at the top. For example, another script could do this

export default {myVariable};

Or you could declare it if you are using an external library like me:

export var myVariable = runtime;

// In modules.js:

import myVariable from "./modules.js" as runtime;
Sawyere answered 21/3, 2024 at 19:14 Comment(0)
J
-1

This error can be caused by not including tsify plugin to compile typescript in the gulp task.

example

    var tsify = require('tsify');

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

See installation and usage here: https://www.npmjs.com/package/tsify

Jacob answered 7/2, 2017 at 11:58 Comment(0)
C
-6

in my case i used export instead of exports.

change export to exports.

Corvin answered 30/9, 2018 at 5:26 Comment(1)
a lot of things that work aren't correct answers. Deleting all the js, and replacing the website with a bunch of static img's and onclick page changes would also "work" but isn't an answer to the question.Neuroglia

© 2022 - 2025 — McMap. All rights reserved.