In CommonJS, one can get all exported properties like so:
module.exports.foo = 1234;
module.exports.bar = 5678;
console.log(module.exports); // <-- The variable `exports`/`module.exports` holds an object
// :)
How can I do the equivalent with ES6 module syntax?
export const foo = 1234;
export const bar = 5678;
console.log(module.exports); // <-- Correctly holds the keys/export names, but not their values
// :(
ES modules have
import * as ModuleObj from "./foo";
to import a namespace object containing all of the exports of a module.
For the usecase of module.exports, you can have the module import itself.
Related
So, in my webpack src, I tried
import {Papa} from "papaparse"
export {Papa}
and
import Papa from "papaparse"
export {Papa}
Notice on the second one, the import doesnt use curly braces. The one without curly braces (default import?) works when I call like this:
import {Papa} from "papaparse-webpack-generated.js"
Papa.parse(...)
and this is inside papaparse.js I downloaded using npm:
(function(root, factory)
{
/* globals define */
if (typeof define === 'function' && define.amd)
{
// AMD. Register as an anonymous module.
define([], factory);
}
else if (typeof module === 'object' && typeof exports !== 'undefined')
{
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory();
}
else
{
// Browser globals (root is window)
root.Papa = factory();
}
// in strict mode we cannot access arguments.callee, so we need a named reference to
// stringify the factory method for the blob worker
// eslint-disable-next-line func-name
}(this, function moduleFactory()
{
'use strict';
var Papa = {};
Papa.parse = CsvToJson;
Papa.unparse = JsonToCsv;
//a bunch of functions and variables here
return Papa;
}));
I'm just wondering what's the difference between the two? why is the js generated by webpack would fail if I use curly braces? if I generated using webpack using the named import (curly braces), the Papa.parse would give me Papa is undefined
EDIT: we can see from the papaparse.js snippet above, there's no export statement for the variable Papa. Am I missing anything? So, how do we tell if it's named or default export?
Thanks
In the file you're importing from, you'll notice Papa is exported as "export default". A module can have a singular default export and any number of named exports.
Default exports are imported with the syntax without the curly braces, and can have any name in the imported file (since the ambiguity isn't resolved by the name, but by the fact that the module can only have on default export).
Named exports, on the other hand, have to be referenced by their specific name, and must be placed inside the curly braces, as to signal they're a named export. You can import multiple named exports, with the following syntax:
import {NamedA, NamedB} from x
Or even import both:
import DefaultExport, {NamedA, NamedB} from x
Read further here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
It all boils down to the way papaparse is exposing/exporting its modules.
If it's doing:
const Papa = ...;
export default Papa;
you'll need to import it this way (you don't need curly braces for importing the default exported member):
import Papa from "papaparse"
// or you can call it whatever you want
import Mama from "papaparse"
However, in case it's a named export like:
const Papa = ...;
const Mama = ...;
export { Papa, Mama };
You will need to import it with its name:
import { Papa } from "papaparse";
// or call it something else within your module from now on:
import { Papa as Mama } from "papaparse";
I have in my website a class named classPerson which is in dir /foo. I need to use it in dir ./bar, but since /bar is not allowed to import from /foo i do the following:
/foo:
const classPerson = new classPerson();
Object.assign(window, { classPerson });
/bar:
const person = window.classPerson.
I need to achieve a similar thing in node.js. How can i do it (having no window)
Depending on your project setup, you can use either the built-in require() method or the es6 import module syntax.
in /foo.js
export class ClassPerson { ... } // add the export keyword to the class definition
export const classPersonInstance = new classPerson(); // add the export keyword to the class instance if you want to use the same instance
in /bar.js
const foo = require('./foo.js');
const instance = foo.classPersonInstance;
// or
import { classPersonInstance } from './foo.js';
NOTE
To be able to use the import syntax, you should do some additional configuration
Here is the nodejs documentation for ECMAScript Modules
I am trying to configure rollup to build commonjs module from existing esm.
I have set of separate standalone methods, exported with default and available to import directly from package like:
import method1 from 'lib/method1'
And I have single entry point for all of them standalone.js to let user code import them separately using destructuring or at once as lib.
import _method1 from './method1'
import _method2 from './method2'
import _method3 from './method3'
export const method1 = _method1;
export const method2 = _method2;
export const method3 = _method3;
export default {method1,method2,method3};
So this is usage example:
import method1 from 'lib/method1'
//or
import { method1 } from 'lib/standalone'
//or
import standalone from 'lib/standalone'
//standalone.method1();
All this works fine for esm and I want similar experience for cjs.
Rollups do everything almost correct but it's complaining about mixed named/default export and adding extra module.exports.default field:
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var condense$1 = require('./condense.js');
var condenseDeep$1 = require('./condenseDeep.js');
var eachDeep$1 = require('./eachDeep.js');
// ...
var condense = condense$1;
var condenseDeep = condenseDeep$1;
var eachDeep = eachDeep$1;
//...
var standalone = {
condense: condense$1,
condenseDeep: condenseDeep$1,
eachDeep: eachDeep$1,
//...
};
exports.condense = condense;
exports.condenseDeep = condenseDeep;
exports.default = standalone; // <-- this one, how to remove it?
exports.eachDeep = eachDeep;
//...
so in commionjs usage looks like:
const method1 = require('lib/method1');
//or
const { method1 } = require ('lib/standalone');
//or
const standalone = require('lib/standalone');
//standalone.method1();
//standalone.default <--- this is redundant and confusing
I tried output.exports: 'named' rollup option - other entry points which are using default only also started having module.exports.default = .. instead of expected module.exports = ..
I tried output.exports: 'default' - it's not working with mixed default/named exports, throwing error.
A default export is a named export, it's just named default. ESM is built so that if you don't specify a name, it uses the export named default from the JS file.
Using CJS, there's no concept of default exports, everything is named.
The point is, nothing is wrong here. You can't mix named and default exports and use them without specifying .default in CJS.
Maybe this gist thread will help you out.
EDIT: You could always hack it as this answer suggests, but it is a hack, and then you'll lose named exports.
How do I export/import a variable in nodejs?
I've tried export and import but it says that its supposed to be a module and when I change the type to module in the json file it says that require is not defined.
with CommonJS modules (the Node.js default) you can export a variable by assigning to exports, and import it via require():
// bar.js
exports.variable = 'value';
// foo.js
const { variable } = require('./bar');
if you're using ECMAScript modules, the keywords import and export do these:
// bar.js
export const variable = 'value';
// foo.js
import { variable } from './bar';
I've been reading about ES modules and experimenting and stumbled upon a case I couldn't explain:
// settings.js
export const FOO = 42;
export const BAR= 5;
// main1.js
import * as settings from './settings';
settings.FOO = 1;
//main2.js
import {FOO, BAR} from './settings'
FOO = 1;
In main1.js I'm able to override the const value through the settings variable, but in main2.js I can't (as expected).
The (theoretical) question is why in the first case it's possible to override the const value? Does creating a "read only view" simply creates properties on a regular object and breaks the original structure?
The practical question would be what's the most effective way to return a collection of constants (or read only properties) from a module? What I had in mind is this:
// settings.js
export default Object.freeze({
FOO: 42,
BAR: 5
});
Any thoughts?
EDIT: I'm using Babel.
The other answer is incorrect.
The (theoretical) question is why in the first case it's possible to override the const value?
This is actually entirely independent of const. With ES6 module syntax, you are not allowed to reassign the exported value of a module, from outside the module. The same would be true with export let FOO; or export var FOO;. Code inside the module is the only thing that is allowed to change exports.
Doing settings.FOO = 1 technically should throw an exception, but most compilers don't handle this particular edge case currently.
As an example, you could do
export var FOO;
export function setFoo(value){
FOO = value;
}
and given this, this is when const becomes useful because it's the same as any other normal JS code. FOO = value would fail if it was declared as export const FOO, so if your module is exporting a bunch of constants, doing export const FOO = 1, FOO2 = 2; is a good way to export constants, it's just that Babel doesn't actually make them immutable.
In this code
import * as settings from './settings';
settings.FOO = 1;
In the above code, you are not assigning directly to the constant variable but a cloned copy in settings.
import * as settings from './settings';
^^^^^^^^^^^^
settings.FOO = 1;
But it is not the case in the next code
import {FOO, BAR} from './settings'
FOO = 1;
Here FOO and BAR are constants and you can't assign to it.