babelify: tsify + babelify + browserify with threejs modules: SyntaxError: 'import' and 'export' may appear only with 'sourceType: module' (9:0)

Hello there,

I’m trying to use threejs with typescript for a web application. Since I would like to use modules (threejs introduced them in r105), I need to get down to es5 for browserify again for which I thought babel might be a solution. Sadly I still get the error SyntaxError: 'import' and 'export' may appear only with 'sourceType: module' (9:0)

I have the following configuration:

package.json

    "@babel/cli": "^7.4.4",
    "@babel/core": "^7.4.5",
    "@babel/preset-env": "^7.4.5",
    "babelify": "^10.0.0",
    "browserify": "^16.2.3",
    "gulp": "^4.0.2",
    "tsify": "^4.0.1",
    "typescript": "^3.5.2",

.babelrc

{
    "presets": [
        ["@babel/preset-env",
            {
                "targets": {
                    "esmodules": true
                }
            }
        ],
    ],
    "extensions": [ ".js", ".ts", ".tsx" ]
}

.tsconfig

{
    "include": [
        "./src/**/*"
    ],
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
            "*": ["types/*"] },
        "noImplicitAny": true,
        "noImplicitReturns": true,
        "noImplicitThis": true,
        "alwaysStrict": true,
        "strictNullChecks": true,
        "module": "commonjs",
        "moduleResolution": "node",
        "target": "es6"
    }
}

gulpfile.js

function buildBundle() {
    return browserify({
        debug: true
    })
        .add("./src/main.ts")
        .plugin(tsify, { target: 'es6'})
        .transform(babelify)
        .bundle()
}

File at which the error is triggered

...
import { ResizeSignal } from "../Signals/InputSignals/ResizeSignal";
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';  // this is the line
...

private loader: GLTFLoader;

What am I missing? I’m completely stuck.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 17 (8 by maintainers)

Most upvoted comments

Wow, thanks a lot. The require setting indeed solved the problem. Here is the final gulp script:

function es6Bundle() {
    log("✳️  ES6 Bundling!");
    return browserify({
        debug: true
    })
    .add("./src/main.ts")
    .require(require.resolve('three/build/three.module.js'), { expose: 'three' })
    .plugin(tsify, { noImplicitAny: true })
    .transform(
        babelify,
        {
            only: [
                "./node_modules/three/build/three.module.js",
                "./node_modules/three/examples/jsm/*"
              ],
            global: true,
            sourceType: "unambiguous",
            presets: ["@babel/preset-env"],
            plugins: ['@babel/plugin-transform-modules-commonjs']
        }
      )
    .bundle()
    .on('error', function(e) {log.error('Error when updating the Bundle: \n' + e);})
    .on('end', function() {log("➡️  Bundle created, uploading to dist")})
    .pipe(source('bundle.js'))
    .pipe(gulp.dest("dist"))
    .on('end', function() {log("✅  Bundle Updated")});
}

and the following dependencies:

"devDependencies": {
    "@babel/cli": "^7.4.4",
    "@babel/core": "^7.4.5",
    "@babel/preset-env": "^7.4.5",
    "@babel/plugin-transform-modules-commonjs": "^7.4.4",
    "babelify": "^10.0.0",
    "browserify": "^16.2.3",
    "fancy-log": "^1.3.3",
    "gltf-pipeline": "^2.1.3",
    "gulp": "^4.0.2",
    "gulp-cli": "^2.2.0",
    "gulp-sourcemaps": "^2.6.5",
    "gulp-typescript": "^5.0.1",
    "tsify": "^4.0.1",
    "typedoc": "^0.14.2",
    "typescript": "^3.5.2",
    "vinyl-buffer": "^1.0.1",
    "vinyl-source-stream": "^2.0.0",
  },
  "dependencies": {
    "three": "git://github.com/JohannesDeml/three.js.git#a2caed8481085e3fe72142f3708d77a7ed5c09d5"
  }

Sadly the build time now went up from 8 to 15 seconds for me, but at least it works now 😃

Oh, I think babel in v7 also changed how its babelrc resolution works, so a local babelrc is no longer used for modules inside node_modules(?). You might try:

b.transform(babelify, { global: true, plugins: ['@babel/plugin-transform-modules-commonjs'] })

that should not be affected by the new babelrc resolution. you can then use .babelrc only for the transforms you need in your own code.

You can also add https://www.npmjs.com/package/tfilter to optimize things a bit and only transform the three.js modules:

b.transform(
  tfilter(babelify, { include: /\/three\/examples\/jsm/ }),
  { global: true, plugins: ['@babel/plugin-transform-modules-commonjs'] }
)

you can explicitly do import 'three/build/three.module.js' to get the ESM version, or do

b.require(require.resolve('three/build/three.module.js'), { expose: 'three' })

to alias the .module.js version to the bare module name.

Wow, thanks a lot for the quick response! Sadly now it seems like there is a syntax problem, not quite sure why though: TypeError: browserify(...).add(...).plugin(...).transform(...).pipe is not a function

function buildBundle() {
    return browserify({
        debug: true
    })
        .add("./src/main.ts")
        .plugin(tsify, { target: 'es6'})
        .transform(babelify, { global: true, presets: ["@babel/preset-env"], plugins: ['@babel/plugin-transform-modules-commonjs'] })
        .pipe(source('bundle.js'))
        .pipe(buffer())
        .pipe(terser())
        .pipe(gulp.dest("dist"));
}

I tried it with and without the preset setting. Thanks also for the info with optimizing. I will do that once the pipeline works again 😃