Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES6 target : 'import' and 'export' may appear only with 'sourceType: module' #86

Closed
cherrydev opened this issue Oct 7, 2015 · 16 comments

Comments

@cherrydev
Copy link

While using typescript 1.6.2 and the target: "ES6" option, I receive the error

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

while trying to build. There is no stack trace indicating where it came from, but the conversation in issue #73 led me to discover tsify itself to be the problem.
I think with the release of typescript 1.6 this is going to rapidly become a major problem; in the past there has been very little use for ES6 output for TSify, which is expressly designed for code targeting browsers:

  1. No major browser JS engines have supported it natively.
  2. Typescript neatly polyfilled the majority of useful features in ES6 for ES5 output.

This is no longer the case, though. To a certain extent, using ES6 natively works for newer web browsers. More importantly, though, Typescript 1.6 introduces to major features (generators and async functions) that ONLY work with ES6 targeted. For people writing browser-targeted code to be able to take advantage of it, they will need to have typescript output ES6 and then have another transpiler (Babel for example) compile it back down to ES5.

@smrq
Copy link
Member

smrq commented Oct 8, 2015

  1. Are you using Babelify? Browserify does not support ES6 at this point in time, so you can't presently get true ES6 output -- you have to transpile.
  2. Can you check whether you're running into the known Browserify bug detailed in Support External Require #60?

@smrq
Copy link
Member

smrq commented Oct 8, 2015

This is a common enough issue that I've added some details to the README.

@cherrydev
Copy link
Author

I think it's a great idea to add some detail about it, because I had seen mention of "ES6 mode" in the tsify documentation that implied that using ES6 target should 'just work'.

But... Yes, I have tried using Babelify. I've tried expressly setting {modules: "common"} or the strict version of it. I've put breakpoints inside of babelify and am certain that it's being called. I can see the output of babelify when its _flush function is being called and clearly see that my import statement is being replaced with a commonjs require() statement. ONLY the top-level file is being processed by Babelify, though, it never sees the code being imported by the top-level file.

...

And, while I was about to post some code example, I double-checked that it was really effectively the same as my actual code and discovered this surprising thing:
The order of .plugin(tsify) and .transform(babelify) are significant, even though when I was stepping through the code babelify was being passed already-transpiled JS and NOT typescript.

Additionally, the default configuration for babelify will not work and you must explicitly configure it to accept ".ts" as an extension. Therefore, a WORKING minimal configuration for babelify, tsify and browserify together using ES6 is:

browserify(browserifyConfig)
.plugin(tsify, {target: 'es6'})
.transform(babelify.configure({extensions: [".ts",".js"]});

Maybe this should have been obvious to some people, but it wasn't to me since it appeared in the debugger that the tsify was being called before babelify was being called (babelify was most definitely receiving the output of tsify and not the raw typescript). Could you please put that snippet in the documentation so that folks wanting to use ES6 output have a straightforward example? Please close afterwords, thanks!

@smrq
Copy link
Member

smrq commented Oct 8, 2015

That is very surprising! I didn't even think to check whether order-of-setup would matter, because tsify always registers its transform first in the list. I'll investigate more. Thanks for the additional details!

@basarat
Copy link
Member

basarat commented Oct 8, 2015

The order of .plugin(tsify) and .transform(babelify) are significant,

I found the same to be true (basarat/globalize-so-what-cha-want-typescript@2c60355), but I wasn't sure if it was just me. Guess its verified now 🌹

@smrq
Copy link
Member

smrq commented Oct 14, 2015

Actually, reading over the code, I was completely wrong. It's been dependent on order-of-setup since Initial commit! Definitely adding this to the README.

@smrq smrq closed this as completed Oct 14, 2015
@remojansen
Copy link

I'm trying to compile from .ts to .min.js as follows:

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

Before I was just doing:

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

I want to be able to use source maps. My tsconfig.json is the following:

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

Since I added "target": "es6" I'm getting the error:

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

My Gulp tasks is the following:

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)
                .transform(babelify.configure(babelifyConfig)) // Added this line and target es6
                .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));
});

I just added the ES6 compilation, before I was compiling TS into ES5 and everything worked fine (including source maps).

I'm using tsify before babelify before bundle so I don't know what is wrong. Do you have any ideas?

@LaurensRietveld
Copy link

I have the same problem. The documentation does not provide a solution here. I've resolve to compiling to es5 for now, but the tsify -> babelify -> bundle procedure mentions in the documentation does not work. Any suggestions on why this occurs (and possibly an update of the readme)?

@cherrydev
Copy link
Author

I'm using ts -> ES6 -> ES5 with babel without a problem. If you're using the latest versions of babel and babelify, you must be sure to specify the es2015 preset, since babel no longer, by default, has any plugins specified. I am currently only using inline sourcemaps, though. If you're still getting "'import' and 'export' may appear only with 'sourceType: module'" it means that babelify is not actually transforming your output into commonjs module form, probably because you're missing the es2015 preset.

@LaurensRietveld
Copy link

@cherrydev , could you share a repo with your config? I just made a minimal working example that reproduces this issue: https://github.com/LaurensRietveld/TsifyIssue .

@cherrydev
Copy link
Author

@LaurensRietveld, add extensions : [".js",".ts"] to your babelify configuration. That seems to fix it for your repro! I remember getting stuck on that at some point. By default babelify will only process .js and maybe .es6 files.

LaurensRietveld added a commit to LaurensRietveld/TsifyIssue that referenced this issue Dec 30, 2015
@LaurensRietveld
Copy link

excellent, thanks a bunch!

@davidstellini
Copy link

That's nice, now going one step further.... If we need to reference external modules + typings, what's the approach? tsc builds fine but tsify, using the same tsconfig.json gives me:

Cannot find module 'myLibrary'.

If I try to add typings to browserify:

var bundler = browserify({
    entries: ['src/app.ts'],
    debug: true,
    extensions: ['.js', '.json', '.ts'],
    basedir : ""})
    .add("typings/main.d.ts")
    .plugin(tsify);

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

Did anyone get tsify working with typings.json + external module refs?

Here's the tsconfig:

{
  "compilerOptions": {
    "module": "amd",
    "noImplicitAny": false,
    "declaration": false,
    "sourceMap": true,
    "target": "es6",
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "outDir": "build"
  },
  "exclude": [
    "node_modules"
  ],
  "filesGlob": [
    "src/**/*.ts",
    "typings/main.d.ts",
    "!node_modules/**/*.ts"
  ],
  "files": [
    ...
  ],

@cherrydev
Copy link
Author

@Davste93 First of all, I don't see that you're actually using babelify in your config. tsify will ignore your 'module:' configuration in your tsconfig if it sees that you're targeting es6 and will automatically output es6 modules. If browserify gets an es6 module (or anything other than commonjs) as an output from a plugin or transform it will punt with SyntaxError: 'import' and 'export' may appear only with 'sourceType: module'. Next, yes, you should be adding "typings/main.d.ts" as you show there.
So basically, if you add babelify as a transform to browserify, you should be good to go.

@davidstellini
Copy link

Thank you so much for your fast response! I'm still getting the same issue after using babelify however:

  var bundler = browserify({
      entries: ['src/app.ts'],
      debug: true,
      extensions: ['.js', '.json', '.ts'],
      basedir : ""})
      .add("typings/main.d.ts")
      .plugin("tsify")
      .transform("babelify", {presets: ['es2015', "stage-0", "react"]});

@markb-trustifi
Copy link

markb-trustifi commented Mar 14, 2022

I solved it by doing in tsconfig.json:

{
  "compilerOptions": {
    "module": "es5",
    "moduleResolution": "node",
    "target": "es5"
}

and gulpfile without babelify:

browserify('app/main.ts')
        .plugin(tsify)
        .bundle()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants