0

We are trying to organize an older package. In order to this we started to change the original "export = module" form to "export default module". This change breaks an other part of the code which uses eval(), since the "import module from 'module'" is being compiled to "module_1". The code fed to eval() arrives from an external source, whereas we want to use module, not the "module_1.default" form.

How this kind of naming convention actually works? Could you tell us the concept and how can we use the original module name instead of the compiled one? Or is there a function to get the actual name of the module after compilation?

Thanks, Adam

  • I probably don't need to tell you, but I'll say it for the sake of people visiting this question in the future: **If the answer is `eval()`, you're most probably asking the wrong question**. Using `eval()` leads to security vulnerabilities and hard-to-track bugs. There's almost always a better solution. – Madara's Ghost Feb 16 '17 at 10:41

1 Answers1

1

It's unsafe to use the name generated by the compiler. It could be changed.

A workaround

But you can do:

import myModule from 'module'
const module = myModule

The second line will be compiled to:

var module = module_1.default;

Then, you can use the variable module.

Why to use export default rather than export =

In the near future, the use of export default will become the norm. This feature is designed by ECMAScript to replace the current CommonJS use case. A member default is just better, more generic.

Here is an example. You need to export an object:

const myConfigObject = Object.freeze({
    dbHost: "",
    dbUser: "",
    // ...
})
export = myConfigObject

Then, you can import it:

import * as myConfigObject from "./myConfigObject"

Subsequently, you would like to export a small helper function toDSN that helps the module user to do something related to the exported object. How to do that? You could add the helper as a member of the configuration. But it wouldn't be elegant.

Here is the ES6 way:

export default Object.freeze({
    dbHost: "",
    dbUser: "",
    // ...
})
export function toDSN(configObj) {
    return // ...
}

Then, you can import the default object:

import myConfigObject from "./myConfigObject"

... or import toDSN:

import { toDSN } from "./myConfigObject"

... or import both:

import myConfigObject, { toDSN } from "./myConfigObject"

The only small pitfall is for current Node.js user code: a member default must be used. When Node.js will implement ES6 modules, the pitfall won't exist anymore.

Why the TS compiler generates an intermediate variable for imports?

Because it is needed by the general case of ES6 modules. The following ES6 code:

import myConfigObject, { toDSN } from "./myConfigObject"

Here, two variables are imported. But a CommonJS (or AMD) require can only import a single variable. So, the compiler imports this single variable as an intermediate variable myConfigObject_1. Then, the object myConfigObject is available through myConfigObject_1.default and toDSN is available through myConfigObject_1.toDSN.

I suggest the article from Mozilla for an introduction to ES6 modules.

Paleo
  • 21,831
  • 4
  • 65
  • 76
  • Thanks, this solved our problem. However I wonder why the name became module_1 in runtime. I created a simple project with two modules with Foo and EntryPoint. Foo exports a class named foo like this: `class Foo { } export default Foo;` EntryPpint looks like this: `import Foo from "Foo"; export function run() { var foo = new Foo(); }` EntryPoint being compiled to a function having an argument for Foo named Foo_1. What is the purpose or cause of this behavior? – Adam The Tux Feb 16 '17 at 09:43
  • Can you point to a documentation for further understanding this? – Adam The Tux Feb 16 '17 at 10:28
  • Yep. The article from Mozilla, at the last line of my answer. ;) – Paleo Feb 16 '17 at 10:30
  • Thank you so much for this detailed answer :) – Adam The Tux Feb 16 '17 at 12:16