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

Can't use default import with Babel #36

Closed
dandv opened this issue May 4, 2019 · 6 comments
Closed

Can't use default import with Babel #36

dandv opened this issue May 4, 2019 · 6 comments

Comments

@dandv
Copy link

dandv commented May 4, 2019

Thanks for the module! I'm trying to use it via default imports with Babel (for interop within my project, and because Jest doesn't yet support .esm files natively).

Boiling the problem down to Babel, here's an index.mjs including qs by comparison, whose default import works fine with both --experimental-modules and Babel:

import qs from 'qs';
import faast from 'faastjs';
console.log(qs.stringify({ foo: 'bar'}));
console.log(faast.log.gc);

This works fine with node --experimental-modules index.mjs but fails like this with Babel:

$ ./node_modules/.bin/babel-node ./index.mjs 
foo=bar
/home/dandv/prg/v12/a/index.mjs:12
console.log(_faastjs.default.log.gc);
                             ^

TypeError: Cannot read property 'log' of undefined

babel.config.js is only this:

module.exports = {
  plugins: [
    '@babel/plugin-transform-modules-commonjs',
  ],
};

I tried rebuilding with Babel 7 directly and the TypeScript preset, but the codebase uses outdated namespaces. Also tried tsc --target es5 and got error TS1252: Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'. Modules are automatically in strict mode..

esModuleInterop: true resulted in many TS2349 errors, a few TS7006, and one TS2351.

@acchou
Copy link
Collaborator

acchou commented May 5, 2019

I put together an example with babel that seems to work with named imports:
https://github.com/faastjs/examples/tree/master/babel

Faast.js doesn't have a default export; I'm unsure why that's a necessary use case given that the named import syntax seems to work fine with babel 7.4.4, per the example above. Maybe I'm missing something?

@dandv
Copy link
Author

dandv commented May 5, 2019

Named imports work fine with Babel or esm. The reason I'm looking for the default import is because I'm trying to minimize the number of transpilers in my toolchain, and experimental modules work great for the vast majority of my .mjs codebase. For example, in my index.mjs, I have import faast from 'faast' and that works just fine with node --experiemental-modules.

The problem is with jest. Since it can't read .mjs files natively, it uses babel-jest. Babel(-jest) fails to import faast from 'faast' as I've shown above.

One workaround is to edit my code and replace the default import with named imports only for testing (because Node can't use named imports with CommonJS modules). That kind of edit is not really acceptable, so I was wondering if there's a way to have the same "import faast" code work both with --experimental-modules and babel-jest. import qs from 'qs'; works like that, but 've found that a number of modules authored in TypeScript don't have a default export.

@acchou
Copy link
Collaborator

acchou commented May 6, 2019

Let me take a crack at enabling esModuleInterop.

acchou added a commit that referenced this issue May 7, 2019
This change helps future proof faast.js in anticipation of ES2015 module support coming to node.js.

re #36
@acchou
Copy link
Collaborator

acchou commented May 7, 2019

The esm branch turns on esModuleInterop but I don't think it's going to do what you want, because while this option allows TypeScript code to consume commonjs modules with default imports, it produces output that is like babel, a es2015 module commonjs format that uses a special __esModule property, which prevents a default export from working in consumers of faast.js. Unless I deliberately add a default export. But that has implications -- I'm not sure it's a good idea to have both a default export and named exports for the same thing. When es2015 modules are fully supported, this will be an awkward interface.

@dandv
Copy link
Author

dandv commented May 7, 2019

Thanks for working on this. Might using Babel directly be a better option?

@acchou
Copy link
Collaborator

acchou commented May 7, 2019

You'll probably solve your problems if you use babel directly, but only if you use a named import for faast.js. The reason can be found here: http://2ality.com/2015/12/babel-commonjs.html#why-mark-transpiled-es6-modules-with-the-flag-esmodule:

The flag enables Babel to treat non-ES6 CommonJS modules that have single exports as if they were ES6 modules with default exports. How that is done is examined in the next section.

The gist of it is, the reason qs works is because it's a non-es6 commonjs module and Babel treats such modules as if they had a default export when imported into an es6 module.

However, faast.js is compiled into a es6 commonjs module, which does include the __esModule tag. This is deliberate, and is intended to prevent accidental usage of the default import.

What I'd suggest for you is to use babel to introduce an explicit build step, then use Jest on the compiled .js outputs. This way Jest is not involved in invoking Babel and you have full control over how Babel is configured.

As for using Node's experimental modules flag... well it's experimental. It's hard to live in the future when you have only today's tools available.

@acchou acchou closed this as completed May 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants