SyntaxError: 'import' and 'export' may appear only with 'sourceType: module' - Gulp
JavascriptGulpEcmascript 6BrowserifyBabeljsJavascript Problem Overview
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?
Javascript Solutions
Solution 1 - Javascript
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"]
}))
...
Solution 2 - Javascript
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
}
}
Doc ref: https://github.com/babel/babel-eslint#configuration
Answer referred from here : https://stackoverflow.com/questions/39158552/ignore-eslint-error-import-and-export-may-only-appear-at-the-top-level
Solution 3 - Javascript
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.
Solution 4 - Javascript
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.
Solution 5 - Javascript
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.
Solution 6 - Javascript
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.
Solution 7 - Javascript
If you want to use anything by import
or require
method in npm to clientside just do the following steps
- Run
npm install browserify babelify @babel/preset-env @babel/preset-react @babel/core es2015 --save-dev
to install the required presets - Add this code into your
package.json
"babel": {
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
- 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
- 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' );
});
- Now the folder structure is
app
--dom_front.js
--browserifyload.js
--assets(folder)
- Run
/node_proj/app$ node browserifyload.js
or run/node_proj/app$ browserify dom_front.js --transform babelify --standalone util > ./assets/mynpmmodule.js
- Check the assets folder, where it now creates the file named as
mynpmmodule.js
- Add this file into your HTML
<script src="assets/mynpmmodule.js"></script>
- 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>
Solution 8 - Javascript
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.
- Bundle all modules/files into one
- Keep all comments/JSDocs
- Keep all types ( such as
const example = (parameter: string) => {}
) - 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.
Solution 9 - Javascript
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.
Solution 10 - Javascript
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
Solution 11 - Javascript
in my case i used export instead of exports.
change export to exports.