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

Importing commonJS modules with es6 imports #11179

Closed
testerez opened this issue Sep 27, 2016 · 13 comments
Closed

Importing commonJS modules with es6 imports #11179

testerez opened this issue Sep 27, 2016 · 13 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@testerez
Copy link

I'm trying to convert a Babel project with typescript and I realize that I need to change some of the imports from import module from 'module' to import * as module from 'module' to make it work.
I understand that the modules I try to import has no "default" export but Babel deals with it by wrapping the import with _interopRequireDefault.

For example

import myModule from 'module';
console.log(myModule);

Is converted like this by Babel

'use strict';

var _module = require('module');

var _module2 = _interopRequireDefault(_module);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

console.log(_module2.default);

and like this by Typescript

"use strict";
var module_1 = require('module');
console.log(module_1.default);

Which logs undefined when importing a classic commonJS module.

Maybe Typescript is right here but the glue Babel provides appends to be pretty convenient. And overall, the difference in the typescript behaviour makes the conversion of an existing Babel project very painful.

Do you have any suggestion to make it easier?

@testerez testerez changed the title Consuming commonJS modules with es6 imports Importing commonJS modules with es6 imports Sep 27, 2016
@aluanhaddad
Copy link
Contributor

Try SystemJS, it handles this elegantly with both TypeScript and Babel.

@testerez
Copy link
Author

@aluanhaddad it seams like SystemJS requires that I rewrite all my imports. But I would like to avoid that, change as less code as possible and convert the project progressively.

@ghost
Copy link

ghost commented Sep 27, 2016

Here's my suggestion to make it super easy.

You just first do like you say:

|import * as myModule from 'module';|

Now forget about all that default stuff and use myModule directly like so:

|console.log('myModule', myModule);
|

I setup my first TypeScript recently and had to go through some of these
issues when importing a classic CJS module. It turns out that it is not
as bad as you think but it is somewhat unintuitive.

Have a look at the file cowarray-test.ts in the test folder in this
mini-project of mine. I was importing to CJS modules 'benchmark' and
'tape' and sounds like your problem is exactly the same as mine.

cowarray: Implementation of copy-on-write for JavaScript arrays using
ES2015 Proxy Objects

Project on GitHub: https://github.com/johanssj/cowarray

NPMJS: https://www.npmjs.com/package/cowarray

Be interested if this does indeed solve your problem.

Cheers, Justin Johansson.

On 27/09/16 23:54, Tom Esterez wrote:

I'm trying to convert a Babel project with typescript and I realize
that I need to change some of the imports from |import module from
'module'| to |import * as module from 'module'| to make it work.

@testerez
Copy link
Author

@johanssj I would agree with you for a new project. But when it comes to converting an existing Babel project, It means that I have to review all the imports and modify the ones that are broken. Which is painful and error prone...

@testerez
Copy link
Author

testerez commented Sep 27, 2016

Why not a --module babel tsc option that would mimic the babel output for es6 modules?
So with the allowJs option, we would not have to modify the JS files. But once we convert the file to .ts, the has no default export error would force us to use the import * as syntax.

@blakeembrey
Copy link
Contributor

@testerez I believe the behaviour you point to is an older Babel 5 behaviour anyway. Babel 6 has been doing the same thing as TypeScript as far as I know, but there is a plugin for Babel that emits the interop still. See https://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact%2Cstage-2&code=export%20default%20function%20test%20()%20%7B%7D.

I didn't quite understand the situation though - are you converting a full project or does your dependency still use the old Babel output? If it's the former, then everything should just work with updated emits. If it's the later, are you updating the dependencies? If not, you can use the CommonJS import style of TypeScript which is import x = require().

@blakeembrey
Copy link
Contributor

blakeembrey commented Sep 27, 2016

@testerez Thanks. I missed that. Babel 5 used export magic, it seems Babel 6 uses import magic, so I interpreted the issue wrong. I still think the advice is correct, you should use the appropriate styles. Using import m from 'module' might not even be correct ES6 when proper ES6 module support lands with interop for CommonJS, so I think it's best to stick with CommonJS-style imports for CommonJS-style code (import x = require()).

@testerez
Copy link
Author

testerez commented Sep 27, 2016

So there is no solution that does not imply that I rewrite all my imports?
I think that it could be a big friction for people trying to migrate existing projects from Babel to Typescript.
Offering a solution to make the transition easier could be a good idea IMO: #11179 (comment)

@aluanhaddad
Copy link
Contributor

@testerez SystemJS allows import module from 'module' and it is supported with plugin-typescript

@testerez
Copy link
Author

I finaly did it the hard way:

  1. renaming all files to .tsx

  2. gathering definitions from npm when available

  3. writing minimal definitions for other modules.

    I found that node -e "console.log(Object.keys(require('cookie-dough')))" can help discovering the actual shape of modules. In this case it prints [] that means that the module as no named export. So I write this definition:

    declare module 'cookie-dough' {
      const content: any;
      export = content;
    }
    
  4. fixing errors reported by typescript

I found that this is still very difficult to convert an existing project to typescript gradually.
IMHO addressing the pain points that makes this process difficult would be a major factor in typescript adoption. I myself gave up multiple times when I wanted to convert real life projects.

Regarding the current issue, a solution could be to make the same emit as Babel when compiling js files. Or offer another module strategy in tsc config.

@mhegazy mhegazy added the Question An issue which isn't directly actionable in code label Apr 27, 2017
@mhegazy
Copy link
Contributor

mhegazy commented Apr 27, 2017

I would recommend changing one file at a time instead of changing the whole project in one shoot. by default you should get no error for importing an existing .js file, it just converts to any. once a file is error free move to the next; when they are all changed, switch --noImplicitAny on and fix the errors.

@mhegazy
Copy link
Contributor

mhegazy commented May 22, 2017

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

4 participants