Pass on all exports from a module object - node.js

I've got the following js file:
// db.js
export default /* ... */;
export const tableName = /* ... */;
And the following mock for it (using jest):
const MockDb = jest.genMockFromModule('../db.js');
export default MockDb.default;
export const { tableName } = MockDb;
Now, if I add an export to my original db.js file, I have to also touch the mock accordingly. I'd rather have the mock file just automatically export all exports from the MockDb object (which is a module object generated by jest holding a default key and other named properties for each export).
According to MDN, the export * from X
syntax only works, when X is a string referring to a module. Can I somehow export * from <moduleObject>?
Thanks!

Can I somehow export * from <moduleObject>?
No, you can't. The export names must be statically declared, they can't be determined at runtime from an object.
The correct approach would a module loader plugin which automatically calls Jest when you do something like import … from '../db.js!jest';.

Related

how to make some lines in index.ts not executed?

so in my index.ts I initially have code like this
export * as users from "./firestore/triggers/users/users_triggers";
export * as auth from "./firebase_authentication/triggers/firebase_auth_triggers";
and then I have another export in my index.ts, but I want this export only executed if it meets some criteria. so in my index.ts will be like this
export * as users from "./firestore/triggers/users/users_triggers";
export * as auth from "./firebase_authentication/triggers/firebase_auth_triggers";
const meetSomeCriteria = true;
if (meetSomeCriteria) return;
// if it meets some criteria, then I expect the code below won't be triggered
export * as utilities from "./utilities/emulators/http_triggers/for_testing_via_firestore_emulators";
but I will have error if I have return like that
so how to make some lines in index.ts not executed?
those export utilities is actually some functions that I will be used only for Firebase Emulators. I want to avoid those functions to be deployed in production
There are no conditional imports or exports in typescript. Ie you cannot write something like
if (acondition)
import x from "module"
But you can workaround it like this
import * as utilimport from "./your/module";
export const utilities = meetSomeCriteria
? utilimport
: undefined
;

Typescript generates properties which not exists [duplicate]

I have an external library thing.d.ts file with a global definition inside:
declare var thing: ThingStatic;
export default thing;
I reference npm module in my TypeScript:
import thing from 'thing';
...
thing.functionOnThing();
When I transpile the TS (targeting ES6) it looks something like this:
const thing_1 = require("thing");
...
thing_1.default.functionOnThing();
This then throws an error:
Cannot read property 'functionOnThing' of undefined
Why is TypeScript adding .default between thing_1 and functionOnThing()?
There is no property named default on ThingStatic, and no default property on the underlying JS object that the .d.ts file defines.
Why is TypeScript adding the property and how do I stop it?
import thing from 'thing';
This line of code means "import the default export from the module 'thing' and bind it to the local name thing".
TypeScript does as you requested and accesses the default property of the module object.
What you probably meant to write was
import * as thing from 'thing';
This appears to be a bug with global TS definitions and "module": "commonjs" in the tsconfig.json.
You can either use global TS definitions and stitch all your output into a single file, or you can use modules and directly import them.
The error here is due to the require returning the module context, and the name of the default being irrelevant - it always becomes default...
declare var thing: ThingStatic;
export thing; // Explicit export for thing
export default thing; // Default export for thing
Now require will return this context, so with commonjs modules:
import module from 'thing';
var thing = module.default; // From the default export
var alsoThing = module.thing; // From the named export
However, I've found this to be inconsistent, so switched to es6 modules:
import thing from './thing'; // Import default
import { thing } from './thing'; // Import named
const thing = (await import('path/to/thing.js')).default; // Import dynamic

What does Babel do to let me use any name to import a node module that exports a function

An example will make my question clearer, say I want to import debug module to my vuejs codes
Debug module export createDebug function like this,
module.exports = require('./browser.js');
...
exports = module.exports = createDebug.debug = createDebug['default'] = createDebug;
function createDebug(namespace) { ... }
When I use import to import debug module, I can give it any name I want, like
import debug from 'debug' // or any name I want, e.g
import debugjs from 'debug'
I understand if export default anonymous function I can then import it with any name I want, but this is not the case here.
So why can I use any name to import it?
---------------- update -----------------
One takeaway from the answer is that import "any name" work for both default export anonymous function and named function.
but this is not the case here.
It kind of is. You are trying to import a module that has no ES6 exports. You are trying to import a CommonJS module. So Babel has to make a decision how to handle that case.
There are two common ways to export something from a CommonJS module:
Assign a property to exports (or module.expoets), for example exports.answer = 42;
Overwrite the value of module.exports, e.g. module.exports = 42;.
In the second case you end up exporting only a single value from the module. That's basically what a default export is (since there can only be one) and that's what you are doing in your code.
So in other words, when importing a CommonJS module via ES6 import statements, then the value of module.exports is used as the default export value.
We can confirm that by looking at how Babel converts the code:
// import foo from 'bar'; becomes
var _bar = require('bar');
var _bar2 = _interopRequireDefault(_bar);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
// ^^^^^^^^^^^^^^^^
}

TypeScript External Node Module Declaration File For Typings

I have a Node.js module (index.js) that has been transpiled with Babel to the code as follows:
// My stuff ...
var fs = require("fs");
var path = require("path");
exports.fileContent = fs.readFileSync(
path.join(__dirname, "file.txt"),
'utf8'
);
// Babel compiler stuff ...
Object.defineProperty(
exports,
"__esModule",
{ value: true }
);
// My stuff again ...
exports.default = exports.fileContent;
Usage in Node.js would be:
var myModule = require("my-module");
doSomethingWithIt( myModule.fileContent );
As far as I understand, I need to create a .d.ts declaration file and reference it in the typings field in my package.json. And also, this declaration file has to be a module. So my first approach after reading several tutorials about this topic was:
// index.d.ts
declare module "my-module" {
export const fileContent: string;
export default fileContent;
}
But sadly, this was a fail:
[...] error TS2656: Exported external package typings file 'index.d.ts' is not a module. [...]
My next approach was to get rid of the declare module thing:
export const fileContent: string;
export default fileContent;
This works for me, but however feels wrong as I did not find any .d.ts example file that is not using the declare stuff. I also noticed that I should not use export default in a namespace/module, which leads me to the point where I don’t understand how to declare the default export of my module at all.
Here are my questions:
How do I do this the right way?
How can I make sure that TypeScript recognizes the default property?
Do I need to use the declare module stuff?
Do I need to declare the imports (fs and path)?
Edit:
After a bit more researching and fiddling, I think I have found the solution by myself. As far as I understand, the external module description/declaration has to be a module—which means that it has to import or export something: In this case, it has to export the declaration and the declared constant as the default export as well:
export declare const fileContent: string;
export default fileContent;
error TS2656: ... is not a module happens when trying to use ES6 style imports and the definition does not export a module.
I suggest changing your definition to
declare module MyModule {
export const fileContent: string;
}
declare module "my-module" {
export default MyModule
}
Since this definition is now "default exporting" a module, it can be imported using the default ES6 import syntax
import MyModule from "my-module"
Then use it
MyModule.fileContent...

How to get a variable from a file to another file in Node.js

Here is my first file:
var self = this;
var config = {
'confvar': 'configval'
};
I want this configuration variable in another file, so I have done this in another file:
conf = require('./conf');
url = conf.config.confvar;
But it gives me an error.
TypeError: Cannot read property 'confvar' of undefined
What can I do?
Edit (2020):
Since Node.js version 8.9.0, you can also use ECMAScript Modules with varying levels of support. The documentation.
For Node v13.9.0 and beyond, experimental modules are enabled by default
For versions of Node less than version 13.9.0, use --experimental-modules
Node.js will treat the following as ES modules when passed to node as the initial input, or when referenced by import statements within ES module code:
Files ending in .mjs.
Files ending in .js when the nearest parent package.json file contains a top-level field "type" with a value of "module".
Strings passed in as an argument to --eval or --print, or piped to node via STDIN, with the flag --input-type=module.
Once you have it setup, you can use import and export.
Using the example above, there are two approaches you can take
./sourceFile.js:
// This is a named export of variableName
export const variableName = 'variableValue'
// Alternatively, you could have exported it as a default.
// For sake of explanation, I'm wrapping the variable in an object
// but it is not necessary.
// You can actually omit declaring what variableName is here.
// { variableName } is equivalent to { variableName: variableName } in this case.
export default { variableName: variableName }
./consumer.js:
// There are three ways of importing.
// If you need access to a non-default export, then
// you use { nameOfExportedVariable }
import { variableName } from './sourceFile'
console.log(variableName) // 'variableValue'
// Otherwise, you simply provide a local variable name
// for what was exported as default.
import sourceFile from './sourceFile'
console.log(sourceFile.variableName) // 'variableValue'
./sourceFileWithoutDefault.js:
// The third way of importing is for situations where there
// isn't a default export but you want to warehouse everything
// under a single variable. Say you have:
export const a = 'A'
export const b = 'B'
./consumer2.js
// Then you can import all exports under a single variable
// with the usage of * as:
import * as sourceFileWithoutDefault from './sourceFileWithoutDefault'
console.log(sourceFileWithoutDefault.a) // 'A'
console.log(sourceFileWithoutDefault.b) // 'B'
// You can use this approach even if there is a default export:
import * as sourceFile from './sourceFile'
// Default exports are under the variable default:
console.log(sourceFile.default) // { variableName: 'variableValue' }
// As well as named exports:
console.log(sourceFile.variableName) // 'variableValue
You can re-export anything from another file. This is useful when you have a single point of exit (index.{ts|js}) but multiple files within the directory.
Say you have this folder structure:
./src
├── component
│   ├── index.js
│   ├── myComponent.js
│   └── state.js
└── index.js
You could have various exports from both store.js and my-component.js but only want to export some of them.
./src/component/myComponent.js:
import createState from "./state";
export function example(){ };
./src/component/state.js:
export default function() {}
./src/component/index.js
export { example as default } from "./myComponent";
export * from "./myComponent"
./src/index.js
export * from "./component"
Original Answer:
You need module.exports:
Exports
An object which is shared between all instances of the current module
and made accessible through require(). exports is the same as the
module.exports object. See src/node.js for more information. exports
isn't actually a global but rather local to each module.
For example, if you would like to expose variableName with value "variableValue" on sourceFile.js then you can either set the entire exports as such:
module.exports = { variableName: "variableValue" };
Or you can set the individual value with:
module.exports.variableName = "variableValue";
To consume that value in another file, you need to require(...) it first (with relative pathing):
const sourceFile = require('./sourceFile');
console.log(sourceFile.variableName);
Alternatively, you can deconstruct it.
const { variableName } = require('./sourceFile');
// current directory --^
// ../ would be one directory down
// ../../ is two directories down
If all you want out of the file is variableName then
./sourceFile.js:
const variableName = 'variableValue'
module.exports = variableName
./consumer.js:
const variableName = require('./sourceFile')
File FileOne.js:
module.exports = { ClientIDUnsplash : 'SuperSecretKey' };
File FileTwo.js:
var { ClientIDUnsplash } = require('./FileOne');
This example works best for React.

Resources