How to make a globally accessible variable? - javascript

How can I make a globally accessible variable in nightwatch.js? I'm using a variable to store a customized url (dependent on which store is loaded in our online product), but I need it to be accessible across several javascript functions. It appears the value of it resets after each function ends, despite it being declared outside of the function at the head of the file.

It's been some time since you asked your question and support for what you requested might not have been (natively) available before. Now it is.
In the developer guide two methods are provided for creating global variables accessible from any given test, depending on your needs. See here for good reading.
Method 1:
For truly global globals, that is, for all tests and all environments. Define an object, or pass a file, at the "globals_path" section of your nightwatch.json file, i.e.
"globals_path": "./lib/globals.js",
You will need to export the variables, however, so brushing up on Node is a good idea. Here is a basic globals.js file example:
var userNames = {
basicAuth: 'chicken',
clientEmail: 'SaddenedSnail#domain.com',
adminEmail: 'admin#domain.com',
};
module.exports = {
userNames: userNames
}
This object/file will be used for all of your tests, no matter the environment, unless you specify a different file/object as seen in method 2 below.
To access the variables from your test suite, use the mandatory browser/client variable passed to every function (test), i.e:
'Account Log In': function accLogin(client) {
var user = client.globals.userNames.clientEmail;
client
.url(yourUrl)
.waitForElementVisible('yourUserNameField', 1000)
.setValue('yourUserNameField', user)
.end();
}
Method 2:
For environment based globals, which change depending on the environment you specify. Define an object, or pass a file, at the "globals" section of your nightwatch.json file, nested under your required environment. I.e.
"test_settings" : {
"default" : {
"launch_url" : "http://localhost",
"selenium_port" : 4444,
"selenium_host" : "localhost",
"globals": {
"myGlobal" : "some_required_global"
}
}
}
Please note that at the time of writing, there seems to be a bug in nightwatch and thus passing a file using Method 2 does not work (at least in my environment). More info about said bug can be found here.

To expand on Tricote's answer, Nightwatch has built-in support for this. See the documentation.
You can either specify it in the nightwatch.json file as "globals": {"myvar": "whatever"} or in a globals.js file that you reference within nightwatch.json with "globals": "path/to/globals.js". In the latter case, globals.js could have:
module.exports = {
myvar: 'whatever'
};
In either case, you can access the variable within your tests as Tricote mentioned:
module.exports = {
"test": function(browser) {
console.log(browser.globals.myvar); // "whatever"
}
};

I'll probably get down-voted for this, but another option that I have been using successfully to store and retrieve objects and data is to do a file write as key value pairs to an existing file.
This allows me to, at the end of a test run, see any data that was randomly created. I create this file in my first test script using all of the data I will use to create the various accounts for the test. In this way, if I see a whole lot of failures, I can take a look at the file and see what data was used, then say, log in as that user and go to that location manually.
In custom commands I have a file that exports the following function:
saveToFile : function(path, filename, data) {
this.yfs = fs;
buffer = new Buffer(data);
console.log("Note: About to update the configuration with test data" )
fs.open(path, 'w', function(err, fd) {
if (err) {
throw 'error opening file: ' + err;
}
fs.write(fd, buffer, 0, buffer.length, null, function(err) {
if (err) throw 'error writing file: ' + err;
return fs.close(fd, function() {
console.log('File write: ' + path + ' has been updated.' );
})
});
})
},
In this file, 'data' is key value pairs like "username" : "Randy8989#mailinator.com". As a result I can use that data in later scripts, if so desired.
This being true, I'll be exploring GrayedFox's answer immediately.

Not sure it's the best way, but here is how I do it : you can define a variable in the browser.globals and access it in your different tests
For instance :
module.exports = {
before: function(browser) {
console.log("Setting up...");
// initialize global variable state
browser.globals.state = {};
},
"first test": function(browser) {
var settings = browser.globals,
state = browser.globals.state;
state.my_shared_var = "something";
browser.
// ...
// use a shared variable
.setValue('input#id', state.my_shared_var)
// ...
// ...
// save something from the page in a variable
.getText("#result", function(result) {
state.my_shared_result = result.value;
})
// ...
},
"second test": function(browser) {
var settings = browser.globals,
state = browser.globals.state;
browser.
// ...
// use the variables
.url("http://example.com/" + state.my_shared_result + "/show")
.assert.containsText('body', state.my_shared_var)
// ...
}
}

An alternative of globals.json if you need read data with complex procedure, is just to create a function in the same test file.
In the following example, I needed simple values and data from csv.
So I created getData() function and I can invoke directly from inside:
let csvToJson = require('convert-csv-to-json');
function getData(){
let users = csvToJson.getJsonFromCsv("/../users.csv");
return {
"users:": users,
"wordToSearch":"JRichardsz"
}
}
module.exports = {
"login": function(browser) {
//data is loading here
var data = getData();
browser
.url('https://www.google.com')
.waitForElementVisible('input[name="q"]', 4000)
.setValue('input[name="q"]', data.wordToSearch)
.keys(browser.Keys.ENTER)
.waitForElementVisible('#result-stats', 4000)
.end();
}
};

generaly it is a bad practice, but you can assign it as field of window class.
window.someGlobalVar = 'http://example.org/'
and window object is accessible globally

Related

Dynamically import functions into an ES5 JS file?

This might seem a little convoluted, so I apologize in advance if it does.
I'm attempting to create a build tool in Node.js for Chrome Extensions, so the final JS file has to be ES5 compliant.
I have separate JS files for each setting within the extension that export an object, the function within this object needs to be imported into the contentScript.js file and placed within it's own settings object.
I've put together a basic screenshot that shows how this should flow, but I'm not sure of how to approach this issue. I've considered some type of string interpolation within the contentScript which Node would then replace, but that seems more of a workaround than a solution.
Say we have a folder called settings, within those settings are two JavaScript files, each with a different name, type, and function, they'd look like this.
// settingName1.js
module.exports = {
name: 'Setting Name 1',
type: 'switch',
function: () => {
console.log('Setting 1 initialized');
}
}
Ideally, both of these files would have their respective functions imported into the contentScript, under a settings object, for example.
// contentScript.js
// Settings Functions Go Here
const settings = {
settingName1: function() {
console.log('Setting 1 initialized')
},
settingName2: function() {
console.log('Setting 2 initialized')
}
}
});
Basically cutting/copying the function from the source setting file itself, and pasting it under a function (named using the file's name) within the contentScript's settings object.
Here's an idea for the generated file:
// header on the file
const capturedExports = [];
// insert this prologue before each inserted file
(function() {
// =============================
// insert settingName1.js here
module.exports = {
name: 'Setting Name 1',
type: 'switch',
function: () => {
console.log('Setting 1 initialized');
}
}
// =============================
// insert this epilogue after each inserted file
})();
capturedExports.push(module.exports);
// insert this prologue before each inserted file
(function() {
// =============================
// insert settingName2.js here
module.exports = {
name: 'Setting Name 2',
type: 'switch',
function: () => {
console.log('Setting 2 initialized');
}
}
// =============================
// insert this epilogue after each inserted file
})();
capturedExports.push(module.exports);
// insert code that builds the settings object
const settings = {};
for (let exportItem of capturedExports) {
let name = exportItem.name.replace(/\s/, "");
name = name.slice(0, 1).toLowerCase() + name.slice(1);
settings[name] = exportItem.function;
}
You do the following steps to output a new file that is collection of all the settingNamex.js files.
Create the new file.
Write a header to it with the const capturedExports = []; line and the start of the IIFE.
For each settingNameX.js file, write that file to it.
Then write the close of the IIFE and the capturedExports.push(module.exports); after it. This will grab whatever the previous code assigned to module.exports and add it to the caputuredExports array.
Repeat this process for each settingNameX.js file.
Then, insert the code that builds the settings object from the capturedExports array.
Enclosing each inserted module in its own IIFE, gives it its own scope so it doesn't create symbol conflicts with the other inserted modules.
This makes the following assumptions.
It assumes that the code from each of the settingNameX.js files assigns the appropriate object to module.exports like your examples show. In the real world, you probably want to add a bunch of tests to see if the right thing is assigned to module.exports (proper defensive coding).
It assumes that the inserted modules are not assigning conflicting things to the global object.
It assumes your own module doesn't need the module.exports or can overwrite it at the end after the inserted modules have used it. If this assumption isn't OK, then you'd have to manually change module.exports = to something else that you define in your master module.

Where does AWS-SDK Javascript code find its includes? [duplicate]

I'm trying to get JavaScript to read/write to a PostgreSQL database. I found this project on GitHub. I was able to get the following sample code to run in Node.
var pg = require('pg'); //native libpq bindings = `var pg = require('pg').native`
var conString = "tcp://postgres:1234#localhost/postgres";
var client = new pg.Client(conString);
client.connect();
//queries are queued and executed one after another once the connection becomes available
client.query("CREATE TEMP TABLE beatles(name varchar(10), height integer, birthday timestamptz)");
client.query("INSERT INTO beatles(name, height, birthday) values($1, $2, $3)", ['Ringo', 67, new Date(1945, 11, 2)]);
client.query("INSERT INTO beatles(name, height, birthday) values($1, $2, $3)", ['John', 68, new Date(1944, 10, 13)]);
//queries can be executed either via text/parameter values passed as individual arguments
//or by passing an options object containing text, (optional) parameter values, and (optional) query name
client.query({
name: 'insert beatle',
text: "INSERT INTO beatles(name, height, birthday) values($1, $2, $3)",
values: ['George', 70, new Date(1946, 02, 14)]
});
//subsequent queries with the same name will be executed without re-parsing the query plan by postgres
client.query({
name: 'insert beatle',
values: ['Paul', 63, new Date(1945, 04, 03)]
});
var query = client.query("SELECT * FROM beatles WHERE name = $1", ['John']);
//can stream row results back 1 at a time
query.on('row', function(row) {
console.log(row);
console.log("Beatle name: %s", row.name); //Beatle name: John
console.log("Beatle birth year: %d", row.birthday.getYear()); //dates are returned as javascript dates
console.log("Beatle height: %d' %d\"", Math.floor(row.height/12), row.height%12); //integers are returned as javascript ints
});
//fired after last row is emitted
query.on('end', function() {
client.end();
});
Next I tried to make it run on a webpage, but nothing seemed to happen. I checked on the JavaScript console and it just says "require not defined".
So what is this "require"? Why does it work in Node but not in a webpage?
Also, before I got it to work in Node, I had to do npm install pg. What's that about? I looked in the directory and didn't find a file pg. Where did it put it, and how does JavaScript find it?
So what is this "require?"
require() is not part of the standard JavaScript API. But in Node.js, it's a built-in function with a special purpose: to load modules.
Modules are a way to split an application into separate files instead of having all of your application in one file. This concept is also present in other languages with minor differences in syntax and behavior, like C's include, Python's import, and so on.
One big difference between Node.js modules and browser JavaScript is how one script's code is accessed from another script's code.
In browser JavaScript, scripts are added via the <script> element. When they execute, they all have direct access to the global scope, a "shared space" among all scripts. Any script can freely define/modify/remove/call anything on the global scope.
In Node.js, each module has its own scope. A module cannot directly access things defined in another module unless it chooses to expose them. To expose things from a module, they must be assigned to exports or module.exports. For a module to access another module's exports or module.exports, it must use require().
In your code, var pg = require('pg'); loads the pg module, a PostgreSQL client for Node.js. This allows your code to access functionality of the PostgreSQL client's APIs via the pg variable.
Why does it work in node but not in a webpage?
require(), module.exports and exports are APIs of a module system that is specific to Node.js. Browsers do not implement this module system.
Also, before I got it to work in node, I had to do npm install pg. What's that about?
NPM is a package repository service that hosts published JavaScript modules. npm install is a command that lets you download packages from their repository.
Where did it put it, and how does Javascript find it?
The npm cli puts all the downloaded modules in a node_modules directory where you ran npm install. Node.js has very detailed documentation on how modules find other modules which includes finding a node_modules directory.
Alright, so let's first start with making the distinction between Javascript in a web browser, and Javascript on a server (CommonJS and Node).
Javascript is a language traditionally confined to a web browser with a limited global context defined mostly by what came to be known as the Document Object Model (DOM) level 0 (the Netscape Navigator Javascript API).
Server-side Javascript eliminates that restriction and allows Javascript to call into various pieces of native code (like the Postgres library) and open sockets.
Now require() is a special function call defined as part of the CommonJS spec. In node, it resolves libraries and modules in the Node search path, now usually defined as node_modules in the same directory (or the directory of the invoked javascript file) or the system-wide search path.
To try to answer the rest of your question, we need to use a proxy between the code running in the the browser and the database server.
Since we are discussing Node and you are already familiar with how to run a query from there, it would make sense to use Node as that proxy.
As a simple example, we're going to make a URL that returns a few facts about a Beatle, given a name, as JSON.
/* your connection code */
var express = require('express');
var app = express.createServer();
app.get('/beatles/:name', function(req, res) {
var name = req.params.name || '';
name = name.replace(/[^a-zA_Z]/, '');
if (!name.length) {
res.send({});
} else {
var query = client.query('SELECT * FROM BEATLES WHERE name =\''+name+'\' LIMIT 1');
var data = {};
query.on('row', function(row) {
data = row;
res.send(data);
});
};
});
app.listen(80, '127.0.0.1');
I noticed that whilst the other answers explained what require is and that it is used to load modules in Node they did not give a full reply on how to load node modules when working in the Browser.
It is quite simple to do. Install your module using npm as you describe, and the module itself will be located in a folder usually called node_modules.
Now the simplest way to load it into your app is to reference it from your html with a script tag which points at this directory. i.e if your node_modules directory is in the root of the project at the same level as your index.html you would write this in your index.html:
<script src="node_modules/ng"></script>
That whole script will now be loaded into the page - so you can access its variables and methods directly.
There are other approaches which are more widely used in larger projects, such as a module loader like require.js. Of the two, I have not used Require myself, but I think it is considered by many people the way to go.
It's used to load modules. Let's use a simple example.
In file circle_object.js:
var Circle = function (radius) {
this.radius = radius
}
Circle.PI = 3.14
Circle.prototype = {
area: function () {
return Circle.PI * this.radius * this.radius;
}
}
We can use this via require, like:
node> require('circle_object')
{}
node> Circle
{ [Function] PI: 3.14 }
node> var c = new Circle(3)
{ radius: 3 }
node> c.area()
The require() method is used to load and cache JavaScript modules. So, if you want to load a local, relative JavaScript module into a Node.js application, you can simply use the require() method.
Example:
var yourModule = require( "your_module_name" ); //.js file extension is optional
Necromancing.
IMHO, the existing answers leave much to be desired.
At first, it's very confusing.
You have a (nowhere defined) function "require", which is used to get modules.
And in said (CommonJS) modules, you can use require, exports and module, WITHOUT THEM EVER BEING DEFINED.
Not that it would be new that you could use undefined variables in JS, but you couldn't use an undefined function.
So it looks a little like magic at first.
But all magic is based on deception.
When you dig a little deeper, it turns out it is really quite simple:
Require is simply a (non-standard) function defined at global scope.
(global scope = window-object in browser, global-object in NodeJS).
Note that by default, the "require function" is only implemented in NodeJS, not in the browser.
Also, note that to add to the confusion, for the browser, there is RequireJS, which, despite the name containing the characters "require", RequireJS absolutely does NOT implement require/CommonJS - instead RequireJS implements AMD, which is something similar, but not the same (aka incompatible).
That last one is just one important thing you have to realize on your way to understanding require.
Now, as such, to answer the question "what is require", we "simply" need to know what this function does.
This is perhaps best explained with code.
Here's a simple implementation by Michele Nasti, the code you can find on his github page.
Let's call our minimalisc implementation of the require function "myRequire":
function myRequire(name)
{
console.log(`Evaluating file ${name}`);
if (!(name in myRequire.cache)) {
console.log(`${name} is not in cache; reading from disk`);
let code = fs.readFileSync(name, 'utf8');
let module = { exports: {} };
myRequire.cache[name] = module;
let wrapper = Function("require, exports, module", code);
wrapper(myRequire, module.exports, module);
}
console.log(`${name} is in cache. Returning it...`);
return myRequire.cache[name].exports;
}
myRequire.cache = Object.create(null);
window.require = myRequire;
const stuff = window.require('./main.js');
console.log(stuff);
Now you notice, the object "fs" is used here.
For simplicity's sake, Michele just imported the NodeJS fs module:
const fs = require('fs');
Which wouldn't be necessary.
So in the browser, you could make a simple implementation of require with a SYNCHRONOUS XmlHttpRequest:
const fs = {
file: `
// module.exports = \"Hello World\";
module.exports = function(){ return 5*3;};
`
, getFile(fileName: string, encoding: string): string
{
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests
let client = new XMLHttpRequest();
// client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
// open(method, url, async)
client.open("GET", fileName, false);
client.send();
if (client.status === 200)
return client.responseText;
return null;
}
, readFileSync: function (fileName: string, encoding: string): string
{
// this.getFile(fileName, encoding);
return this.file; // Example, getFile would fetch this file
}
};
Basically, what require thus does, is it downloads a JavaScript-file, evals it in an anonymous namespace (aka Function), with the parameters "require", "exports" and "module", and returns the exports, meaning an object's public functions and properties.
Note that this evaluation is recursive: you require files, which themselfs can require files.
This way, all "global" variables used in your module are variables in the require-wrapper-function namespace, and don't pollute the global scope with unwanted variables.
Also, this way, you can reuse code without depending on namespaces, so you get "modularity" in JavaScript. "modularity" in quotes, because this is not exactly true, though, because you can still write window.bla/global.bla, and hence still pollute the global scope... Also, this establishes a separation between private and public functions, the public functions being the exports.
Now instead of saying
module.exports = function(){ return 5*3;};
You can also say:
function privateSomething()
{
return 42:
}
function privateSomething2()
{
return 21:
}
module.exports = {
getRandomNumber: privateSomething
,getHalfRandomNumber: privateSomething2
};
and return an object.
Also, because your modules get evaluated in a function with parameters
"require", "exports" and "module", your modules can use the undeclared variables "require", "exports" and "module", which might be startling at first. The require parameter there is of course a pointer to the require function saved into a variable.
Cool, right ?
Seen this way, require looses its magic, and becomes simple.
Now, the real require-function will do a few more checks and quirks, of course, but this is the essence of what that boils down to.
Also, in 2020, you should use the ECMA implementations instead of require:
import defaultExport from "module-name";
import * as name from "module-name";
import { export1 } from "module-name";
import { export1 as alias1 } from "module-name";
import { export1 , export2 } from "module-name";
import { foo , bar } from "module-name/path/to/specific/un-exported/file";
import { export1 , export2 as alias2 , [...] } from "module-name";
import defaultExport, { export1 [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";
And if you need a dynamic non-static import (e.g. load a polyfill based on browser-type), there is the ECMA-import function/keyword:
var promise = import("module-name");
note that import is not synchronous like require.
Instead, import is a promise, so
var something = require("something");
becomes
var something = await import("something");
because import returns a promise (asynchronous).
So basically, unlike require, import replaces fs.readFileSync with fs.readFileAsync.
async readFileAsync(fileName, encoding)
{
const textDecoder = new TextDecoder(encoding);
// textDecoder.ignoreBOM = true;
const response = await fetch(fileName);
console.log(response.ok);
console.log(response.status);
console.log(response.statusText);
// let json = await response.json();
// let txt = await response.text();
// let blo:Blob = response.blob();
// let ab:ArrayBuffer = await response.arrayBuffer();
// let fd = await response.formData()
// Read file almost by line
// https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader/read#Example_2_-_handling_text_line_by_line
let buffer = await response.arrayBuffer();
let file = textDecoder.decode(buffer);
return file;
} // End Function readFileAsync
This of course requires the import-function to be async as well.
"use strict";
async function myRequireAsync(name) {
console.log(`Evaluating file ${name}`);
if (!(name in myRequireAsync.cache)) {
console.log(`${name} is not in cache; reading from disk`);
let code = await fs.readFileAsync(name, 'utf8');
let module = { exports: {} };
myRequireAsync.cache[name] = module;
let wrapper = Function("asyncRequire, exports, module", code);
await wrapper(myRequireAsync, module.exports, module);
}
console.log(`${name} is in cache. Returning it...`);
return myRequireAsync.cache[name].exports;
}
myRequireAsync.cache = Object.create(null);
window.asyncRequire = myRequireAsync;
async () => {
const asyncStuff = await window.asyncRequire('./main.js');
console.log(asyncStuff);
};
Even better, right ?
Well yea, except that there is no ECMA-way to dynamically import synchronously (without promise).
Now, to understand the repercussions, you absolutely might want to read up on promises/async-await here, if you don't know what that is.
But very simply put, if a function returns a promise, it can be "awaited":
"use strict";
function sleep(interval)
{
return new Promise(
function (resolve, reject)
{
let wait = setTimeout(function () {
clearTimeout(wait);
//reject(new Error(`Promise timed out ! (timeout = ${timeout})`));
resolve();
}, interval);
});
}
The promise would then normally be used like this:
function testSleep()
{
sleep(3000).then(function ()
{
console.log("Waited for 3 seconds");
});
}
But when you return a promise, you can also use await, which means we get rid of the callback (sort of - actually, it is being replaced with a state-machine in the compiler/interpreter).
This way, we make asynchronous code feel like synchronous, so we now can use try-catch for error-handling.
Note that if you want to use await in a function, that function must be declared async (hence async-await).
async function testSleep()
{
await sleep(5000);
console.log("i waited 5 seconds");
}
And also please note that in JavaScript, there is no way to call an async function (blockingly) from a synchronous one (the ones you know). So if you want to use await (aka ECMA-import), all your code needs to be async, which most likely is a problem, if everything isn't already async...
An example of where this simplified implementation of require fails, is when you require a file that is not valid JavaScript, e.g. when you require css, html, txt, svg and images or other binary files.
And it's easy to see why:
If you e.g. put HTML into a JavaScript function body, you of course rightfully get
SyntaxError: Unexpected token '<'
because of Function("bla", "<doctype...")
Now, if you wanted to extend this to for example include non-modules, you could just check the downloaded file-contents for code.indexOf("module.exports") == -1, and then e.g. eval("jquery content") instead of Func (which works fine as long as you're in the browser). Since downloads with Fetch/XmlHttpRequests are subject to the same-origin-policy, and integrity is ensured by SSL/TLS, the use of eval here is rather harmless, provided you checked the JS files before you added them to your site, but that much should be standard-operating-procedure.
Note that there are several implementations of require-like functionality:
the CommonJS (CJS) format, used in Node.js, uses a require function and module.exports to define dependencies and modules. The npm ecosystem is built upon this format. (this is what is implemented above)
the Asynchronous Module Definition (AMD) format, used in browsers, uses a define function to define modules. (basically, this is overcomplicated archaic crap that you wouldn't ever want to use). Also, AMD is the format that is implemented by RequireJS (note that despite the name containing the characters "require", AMD absolutely is NOT CommonJS).
the ES Module (ESM) format. As of ES6 (ES2015), JavaScript supports a native module format. It uses an export keyword to export a module’s public API and an import keyword to import it. This is the one you should use if you don't give a flying f*ck about archaic browsers, such as Safari and IE/EdgeHTML.
the System.register format, designed to support ES6 modules within ES5. (the one you should use, if you need support for older browsers (Safari & IE & old versions of Chrome on mobile phones/tablets), because it can load all formats [for some, plugins are required], can handle cyclic-dependencies, and CSS and HTML - don't define your modules as system.register, though - the format is rather complicated, and remember, it can read the other easier formats)
the Universal Module Definition (UMD) format, compatible to all the above mentioned formats (except ECMA), used both in the browser and in Node.js. It’s especially useful if you write modules that can be used in both NodeJS and the browser. It's somewhat flawed, as it doesn't support the latest ECMA modules, though (maybe this will get fixed) - use System.register instead.
Important sidenote on the function argument "exports":
JavaScript uses call-by-value-sharing - meaning objects are passed as a pointer, but the pointer-value itselfs is passed BY VALUE, not by reference. So you can't override exports by assigning it a new object. Instead, if you want to override exports, you need to assign the new object to module.exports - because hey, module is the pointer passed by value, but exports in module.exports is the reference to the original exports pointer.
Important sidenote on module-Scope:
Modules are evaluated ONCE, and then cached by require.
That means all your modules have a Singleton scope.
If you want a non-singleton scope, you have to do something like:
var x = require("foo.js").createInstance();
or simply
var x = require("foo.js")();
with appropriate code returned by your module.
If you need CommonJS-support for the browser (IE5+, Chrome, Firefox),
check out my code in my comment on Michele Nasti's project
You know how when you are running JavaScript in the browser, you have access to variables like "window" or Math? You do not have to declare these variables, they have been written for you to use whenever you want.
Well, when you are running a file in the Node.js environment, there is a variable that you can use. It is called "module" It is an object. It has a property called "exports." And it works like this:
In a file that we will name example.js, you write:
example.js
module.exports = "some code";
Now, you want this string "some code" in another file.
We will name the other file otherFile.js
In this file, you write:
otherFile.js
let str = require('./example.js')
That require() statement goes to the file that you put inside of it, finds whatever data is stored on the module.exports property. The let str = ... part of your code means that whatever that require statement returns is stored to the str variable.
So, in this example, the end-result is that in otherFile.js you now have this:
let string = "some code";
or -
let str = ('./example.js').module.exports
Note:
the file-name that is written inside of the require statement: If it is a local file, it should be the file-path to example.js. Also, the .js extension is added by default, so I didn't have to write it.
You do something similar when requiring node.js libraries, such as Express. In the express.js file, there is an object named 'module', with a property named 'exports'.
So, it looks something like along these lines, under the hood (I am somewhat of a beginner so some of these details might not be exact, but it's to show the concept:
express.js
module.exports = function() {
//It returns an object with all of the server methods
return {
listen: function(port){},
get: function(route, function(req, res){}){}
}
}
If you are requiring a module, it looks like this:
const moduleName = require("module-name");
If you are requiring a local file, it looks like this:
const localFile = require("./path/to/local-file");
(notice the ./ at the beginning of the file name)
Also note that by default, the export is an object .. eg module.exports = {} So, you can write module.exports.myfunction = () => {} before assigning a value to the module.exports. But you can also replace the object by writing module.exports = "I am not an object anymore."
Two flavours of module.exports / require:
(see here)
Flavour 1
export file (misc.js):
var x = 5;
var addX = function(value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
other file:
var misc = require('./misc');
console.log("Adding %d to 10 gives us %d", misc.x, misc.addX(10));
Flavour 2
export file (user.js):
var User = function(name, email) {
this.name = name;
this.email = email;
};
module.exports = User;
other file:
var user = require('./user');
var u = new user();

What is the better practice for sharing variables across Node.js modules

So I'm writing a multiplayer game with Socket.io and most of the socket calls are handled in the main file (app.js) including storing usernames and the sockets they're connected to.
But I'd like to create a separate file (game.js) that handles all the game code including socket emissions to certain rooms. However to do that I'll need access to my array with the users/sockets stored in it (which is in app.js)
So I'm wondering what the best way to share the variable would be? Should I pass the the array reference through every function that I need it in?
Or should I write a function that is called once and creates a global variable (or the scope that I need it in) with a reference to the array?
Also If I should ever need to share the same dependency across multiple files should I call require in each one of them?
About Modules and the use Global/Shared State
An interesting aspect of modules is the way they are evaluated. The module is evaluated the first time it is required and then it is cached. This means that after it has been evaluated no matter how many times we require it again, we will always get the same exported object back.
This means that, although Node provides a global object, it is probably better to use modules to store shared stated instead of putting it directly into the global object. For instance, the following module exposes the configuration of a Mongo database.
//module config.js
dbConfig = {
url:'mongodb://foo',
user: 'anakin',
password: '*******'
}
module. exports = dbConfig;
We can easily share this module with as many other modules as we want, and every one of them will get the same instance of the configuration object since the module is evaluated only once, and the exported object is cached thereon.
//foo.js
var dbConfig1 = require('./config');
var dbConfig2 = require('./config');
var assert = require('assert');
assert(dbConfig1==dbConfi2);
So, for your specific problem, the shared state that you want to share can reside in a singleton object exposed by whatever module you have. Just make sure your singleton object is the one being exposed in your module and you will always get a reference back to it every time you require it.
If by 'variable' you mean reference to the socket - you may want to consider passing a callback or module to game.js which handles the emission - but that game.js calls when necessary.
Like Edwin Dalorzo mentioned, having a separate file for all your variables seems the best.
I've had a similar problem for a few hours now because I didn't know that variables were persistent. The scenario that I had was:
I have two files cli.ts and main-lib.ts. cli.ts reads user input, and depending on the input, runs functions in main-lib.ts. While main-lib.ts is busy validating the input, cli.ts uses some global variables that main-lib.ts generates when a test passes. The only limitation is that I can't mix the main-lib.ts code with the cli.ts, I can only share the function callValidateFunction.
The issue that I had originally thought of was: if I were to make a global-vars.ts file, the variables' data will still be different for each call of require (i.e., calling setVar(...) will only change the variable value that was imported.
However, thanks to Edwin's answer, I managed to implement a bridge:
// cli.ts
import { setVar, getVar } from "./var-bridge";
import { callValidateFunction } from "./main-lib";
function run(args: string[]): void {
// ...
if (arg == "--email") {
// Set the test status.
setVar("testStatus", "pending");
// Validate the input email address.
callValidateFunction("validateEmail", nextArg());
// Get the testStatus.
const testStatus: string = getVar("testStatus");
}
// ...
}
// main-lib.ts
import { setVar, getVar } from "./var-bridge";
const funcs: {name: string, func: (arg: string) => boolean} = {};
funcs.validateEmail = function(arg: string): boolean {
let passed: boolean = false;
// ...
return passed;
};
function callValidateFunction(functionName: string, arg: string): void {
// ...
const passed = funcs[functionName](arg);
if (passed) setVar("testStatus", "passed");
}
// ...
// var-bridge.ts
const variables: {name: string, value: any} = {
"testStatus": "",
// ...
};
function setVar(varName: string, varValue: any): void {
variables[varName] = varValue;
}
function getVar(varName: string): any {
return variables[varName];
}
export { setVar, getVar };

Global variables in Karma test runner

I have a global variable defined in my main template, which I use to store information bits from the back end, such as the environment context path. I can't move that variable inside a service.
How can I expose that variable to Karma when I run the unit tests?
You either declare that global variable within your test file:
var global = "something";
describe('Your test suit', function() {
...
});
or add a Javascript file where it's defined to your karma.conf.js file:
// list of files / patterns to load in the browser
files: [
...,
'file-containing-the-global-variable.js'
],
If you are coming from Angular 2+ the only way I found that works is to create the variable or object globally using window:
Google Recapthca Loaded from a script:
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
In this example a call to the google Recaptcha will create a global variable called grecaptcha.
In our component we decide to render a new Google Recaptcha. Of course since we do not declare grecaptcha we need to use declare var to say hey I promise it is declared somewhere:
declare var grecaptcha;
private CreateGoogleCaptcha() {
grecaptcha.render('recaptcha', {
sitekey: this.siteKey,
callback: this.GoogleCaptchaCallback,
badge: 'inline'
});
}
private GoogleCaptchaCallback(token) {
// Handle Callback Logic
}
Now that our function works we decide to run a test but of course we would like to mock our grecaptcha as we don't have control over it.
So we name our global variable we would like to create and add the functions we would like:
beforeEach(() => {
fixture = TestBed.createComponent(GoogleRecaptchaComponent);
component = fixture.componentInstance;
window['grecaptcha'] = {
render() {
console.log('mocked global variable and function');
}
}
}
Update:
Creating the global variable in the beforeEach is fine but what about when it has some sort of callback function such as above that calls a function from your component? Easy enough we just move the login to our test and in our mock we set it to our components function:
it('should ', () => {
window['grecaptcha'] = {
render: function() { GoogleRecaptchaComponent['GoogleCaptchaCallback']('token'); }
};
spyOn<any>(GoogleRecaptchaComponent, 'GoogleCaptchaCallback');
GoogleRecaptchaComponent['CreateGoogleCaptcha']();
expect(GoogleRecaptchaComponent['GoogleCaptchaCallback']).toHaveBeenCalled();
});
Note: spyOn<any>: The <any> is used so we can refence without error the function because it is private, otherwise we will get a typescript error;
The first solution didn't work for me in Angular 2.1.x. It simply would not recognize the variable in my imported service. What I had to do was put my environment variable in my karma-test-shim.js file and remove var so it would be globally available.
Mine looks like this:
Error.stackTraceLimit = Infinity;
require('core-js/es6');
require('reflect-metadata');
require('zone.js/dist/zone');
require('zone.js/dist/long-stack-trace-zone');
require('zone.js/dist/proxy'),
require('zone.js/dist/sync-test'),
require('zone.js/dist/jasmine-patch');
require('zone.js/dist/async-test');
require('zone.js/dist/fake-async-test');
// Add environment variables here so that tests will inject them in source code
API_URL = 'http://localhost:8080/api/';
var appContext = require.context('../src', true, /\.spec\.ts/);
appContext.keys().forEach(appContext);
var testing = require('#angular/core/testing');
var browser = require('#angular/platform-browser-dynamic/testing');
testing.TestBed.initTestEnvironment(
browser.BrowserDynamicTestingModule,
browser.platformBrowserDynamicTesting()
);
I was trying to integrate angular v13 with google-place-autocomplete without any npm package, just vanilla google-place-autocomplete. When i tried to test, karma said: '"google" is not defined'.
So i found the awswers above, and it worked for me like this:
Created a file in root directory (in my case, i named: google-place.js)
Added a mock object with the instructions that is used in component.
class Autocomplete {
constructor(input, options) {
const addListener = (eventName, callback) => { }
const getPlace = () => { }
return { addListener, getPlace }
}
}
var google = {
maps: {
places: {
Autocomplete: Autocomplete
}
}
};
Added in karma.conf.js a property called "files", and end up like this:
files: [
"./google-place.js"
]
And it was not necessary to add a declare var google in every spec. Is global now.

What is this JavaScript "require"?

I'm trying to get JavaScript to read/write to a PostgreSQL database. I found this project on GitHub. I was able to get the following sample code to run in Node.
var pg = require('pg'); //native libpq bindings = `var pg = require('pg').native`
var conString = "tcp://postgres:1234#localhost/postgres";
var client = new pg.Client(conString);
client.connect();
//queries are queued and executed one after another once the connection becomes available
client.query("CREATE TEMP TABLE beatles(name varchar(10), height integer, birthday timestamptz)");
client.query("INSERT INTO beatles(name, height, birthday) values($1, $2, $3)", ['Ringo', 67, new Date(1945, 11, 2)]);
client.query("INSERT INTO beatles(name, height, birthday) values($1, $2, $3)", ['John', 68, new Date(1944, 10, 13)]);
//queries can be executed either via text/parameter values passed as individual arguments
//or by passing an options object containing text, (optional) parameter values, and (optional) query name
client.query({
name: 'insert beatle',
text: "INSERT INTO beatles(name, height, birthday) values($1, $2, $3)",
values: ['George', 70, new Date(1946, 02, 14)]
});
//subsequent queries with the same name will be executed without re-parsing the query plan by postgres
client.query({
name: 'insert beatle',
values: ['Paul', 63, new Date(1945, 04, 03)]
});
var query = client.query("SELECT * FROM beatles WHERE name = $1", ['John']);
//can stream row results back 1 at a time
query.on('row', function(row) {
console.log(row);
console.log("Beatle name: %s", row.name); //Beatle name: John
console.log("Beatle birth year: %d", row.birthday.getYear()); //dates are returned as javascript dates
console.log("Beatle height: %d' %d\"", Math.floor(row.height/12), row.height%12); //integers are returned as javascript ints
});
//fired after last row is emitted
query.on('end', function() {
client.end();
});
Next I tried to make it run on a webpage, but nothing seemed to happen. I checked on the JavaScript console and it just says "require not defined".
So what is this "require"? Why does it work in Node but not in a webpage?
Also, before I got it to work in Node, I had to do npm install pg. What's that about? I looked in the directory and didn't find a file pg. Where did it put it, and how does JavaScript find it?
So what is this "require?"
require() is not part of the standard JavaScript API. But in Node.js, it's a built-in function with a special purpose: to load modules.
Modules are a way to split an application into separate files instead of having all of your application in one file. This concept is also present in other languages with minor differences in syntax and behavior, like C's include, Python's import, and so on.
One big difference between Node.js modules and browser JavaScript is how one script's code is accessed from another script's code.
In browser JavaScript, scripts are added via the <script> element. When they execute, they all have direct access to the global scope, a "shared space" among all scripts. Any script can freely define/modify/remove/call anything on the global scope.
In Node.js, each module has its own scope. A module cannot directly access things defined in another module unless it chooses to expose them. To expose things from a module, they must be assigned to exports or module.exports. For a module to access another module's exports or module.exports, it must use require().
In your code, var pg = require('pg'); loads the pg module, a PostgreSQL client for Node.js. This allows your code to access functionality of the PostgreSQL client's APIs via the pg variable.
Why does it work in node but not in a webpage?
require(), module.exports and exports are APIs of a module system that is specific to Node.js. Browsers do not implement this module system.
Also, before I got it to work in node, I had to do npm install pg. What's that about?
NPM is a package repository service that hosts published JavaScript modules. npm install is a command that lets you download packages from their repository.
Where did it put it, and how does Javascript find it?
The npm cli puts all the downloaded modules in a node_modules directory where you ran npm install. Node.js has very detailed documentation on how modules find other modules which includes finding a node_modules directory.
Alright, so let's first start with making the distinction between Javascript in a web browser, and Javascript on a server (CommonJS and Node).
Javascript is a language traditionally confined to a web browser with a limited global context defined mostly by what came to be known as the Document Object Model (DOM) level 0 (the Netscape Navigator Javascript API).
Server-side Javascript eliminates that restriction and allows Javascript to call into various pieces of native code (like the Postgres library) and open sockets.
Now require() is a special function call defined as part of the CommonJS spec. In node, it resolves libraries and modules in the Node search path, now usually defined as node_modules in the same directory (or the directory of the invoked javascript file) or the system-wide search path.
To try to answer the rest of your question, we need to use a proxy between the code running in the the browser and the database server.
Since we are discussing Node and you are already familiar with how to run a query from there, it would make sense to use Node as that proxy.
As a simple example, we're going to make a URL that returns a few facts about a Beatle, given a name, as JSON.
/* your connection code */
var express = require('express');
var app = express.createServer();
app.get('/beatles/:name', function(req, res) {
var name = req.params.name || '';
name = name.replace(/[^a-zA_Z]/, '');
if (!name.length) {
res.send({});
} else {
var query = client.query('SELECT * FROM BEATLES WHERE name =\''+name+'\' LIMIT 1');
var data = {};
query.on('row', function(row) {
data = row;
res.send(data);
});
};
});
app.listen(80, '127.0.0.1');
I noticed that whilst the other answers explained what require is and that it is used to load modules in Node they did not give a full reply on how to load node modules when working in the Browser.
It is quite simple to do. Install your module using npm as you describe, and the module itself will be located in a folder usually called node_modules.
Now the simplest way to load it into your app is to reference it from your html with a script tag which points at this directory. i.e if your node_modules directory is in the root of the project at the same level as your index.html you would write this in your index.html:
<script src="node_modules/ng"></script>
That whole script will now be loaded into the page - so you can access its variables and methods directly.
There are other approaches which are more widely used in larger projects, such as a module loader like require.js. Of the two, I have not used Require myself, but I think it is considered by many people the way to go.
It's used to load modules. Let's use a simple example.
In file circle_object.js:
var Circle = function (radius) {
this.radius = radius
}
Circle.PI = 3.14
Circle.prototype = {
area: function () {
return Circle.PI * this.radius * this.radius;
}
}
We can use this via require, like:
node> require('circle_object')
{}
node> Circle
{ [Function] PI: 3.14 }
node> var c = new Circle(3)
{ radius: 3 }
node> c.area()
The require() method is used to load and cache JavaScript modules. So, if you want to load a local, relative JavaScript module into a Node.js application, you can simply use the require() method.
Example:
var yourModule = require( "your_module_name" ); //.js file extension is optional
Necromancing.
IMHO, the existing answers leave much to be desired.
At first, it's very confusing.
You have a (nowhere defined) function "require", which is used to get modules.
And in said (CommonJS) modules, you can use require, exports and module, WITHOUT THEM EVER BEING DEFINED.
Not that it would be new that you could use undefined variables in JS, but you couldn't use an undefined function.
So it looks a little like magic at first.
But all magic is based on deception.
When you dig a little deeper, it turns out it is really quite simple:
Require is simply a (non-standard) function defined at global scope.
(global scope = window-object in browser, global-object in NodeJS).
Note that by default, the "require function" is only implemented in NodeJS, not in the browser.
Also, note that to add to the confusion, for the browser, there is RequireJS, which, despite the name containing the characters "require", RequireJS absolutely does NOT implement require/CommonJS - instead RequireJS implements AMD, which is something similar, but not the same (aka incompatible).
That last one is just one important thing you have to realize on your way to understanding require.
Now, as such, to answer the question "what is require", we "simply" need to know what this function does.
This is perhaps best explained with code.
Here's a simple implementation by Michele Nasti, the code you can find on his github page.
Let's call our minimalisc implementation of the require function "myRequire":
function myRequire(name)
{
console.log(`Evaluating file ${name}`);
if (!(name in myRequire.cache)) {
console.log(`${name} is not in cache; reading from disk`);
let code = fs.readFileSync(name, 'utf8');
let module = { exports: {} };
myRequire.cache[name] = module;
let wrapper = Function("require, exports, module", code);
wrapper(myRequire, module.exports, module);
}
console.log(`${name} is in cache. Returning it...`);
return myRequire.cache[name].exports;
}
myRequire.cache = Object.create(null);
window.require = myRequire;
const stuff = window.require('./main.js');
console.log(stuff);
Now you notice, the object "fs" is used here.
For simplicity's sake, Michele just imported the NodeJS fs module:
const fs = require('fs');
Which wouldn't be necessary.
So in the browser, you could make a simple implementation of require with a SYNCHRONOUS XmlHttpRequest:
const fs = {
file: `
// module.exports = \"Hello World\";
module.exports = function(){ return 5*3;};
`
, getFile(fileName: string, encoding: string): string
{
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests
let client = new XMLHttpRequest();
// client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
// open(method, url, async)
client.open("GET", fileName, false);
client.send();
if (client.status === 200)
return client.responseText;
return null;
}
, readFileSync: function (fileName: string, encoding: string): string
{
// this.getFile(fileName, encoding);
return this.file; // Example, getFile would fetch this file
}
};
Basically, what require thus does, is it downloads a JavaScript-file, evals it in an anonymous namespace (aka Function), with the parameters "require", "exports" and "module", and returns the exports, meaning an object's public functions and properties.
Note that this evaluation is recursive: you require files, which themselfs can require files.
This way, all "global" variables used in your module are variables in the require-wrapper-function namespace, and don't pollute the global scope with unwanted variables.
Also, this way, you can reuse code without depending on namespaces, so you get "modularity" in JavaScript. "modularity" in quotes, because this is not exactly true, though, because you can still write window.bla/global.bla, and hence still pollute the global scope... Also, this establishes a separation between private and public functions, the public functions being the exports.
Now instead of saying
module.exports = function(){ return 5*3;};
You can also say:
function privateSomething()
{
return 42:
}
function privateSomething2()
{
return 21:
}
module.exports = {
getRandomNumber: privateSomething
,getHalfRandomNumber: privateSomething2
};
and return an object.
Also, because your modules get evaluated in a function with parameters
"require", "exports" and "module", your modules can use the undeclared variables "require", "exports" and "module", which might be startling at first. The require parameter there is of course a pointer to the require function saved into a variable.
Cool, right ?
Seen this way, require looses its magic, and becomes simple.
Now, the real require-function will do a few more checks and quirks, of course, but this is the essence of what that boils down to.
Also, in 2020, you should use the ECMA implementations instead of require:
import defaultExport from "module-name";
import * as name from "module-name";
import { export1 } from "module-name";
import { export1 as alias1 } from "module-name";
import { export1 , export2 } from "module-name";
import { foo , bar } from "module-name/path/to/specific/un-exported/file";
import { export1 , export2 as alias2 , [...] } from "module-name";
import defaultExport, { export1 [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
import "module-name";
And if you need a dynamic non-static import (e.g. load a polyfill based on browser-type), there is the ECMA-import function/keyword:
var promise = import("module-name");
note that import is not synchronous like require.
Instead, import is a promise, so
var something = require("something");
becomes
var something = await import("something");
because import returns a promise (asynchronous).
So basically, unlike require, import replaces fs.readFileSync with fs.readFileAsync.
async readFileAsync(fileName, encoding)
{
const textDecoder = new TextDecoder(encoding);
// textDecoder.ignoreBOM = true;
const response = await fetch(fileName);
console.log(response.ok);
console.log(response.status);
console.log(response.statusText);
// let json = await response.json();
// let txt = await response.text();
// let blo:Blob = response.blob();
// let ab:ArrayBuffer = await response.arrayBuffer();
// let fd = await response.formData()
// Read file almost by line
// https://developer.mozilla.org/en-US/docs/Web/API/ReadableStreamDefaultReader/read#Example_2_-_handling_text_line_by_line
let buffer = await response.arrayBuffer();
let file = textDecoder.decode(buffer);
return file;
} // End Function readFileAsync
This of course requires the import-function to be async as well.
"use strict";
async function myRequireAsync(name) {
console.log(`Evaluating file ${name}`);
if (!(name in myRequireAsync.cache)) {
console.log(`${name} is not in cache; reading from disk`);
let code = await fs.readFileAsync(name, 'utf8');
let module = { exports: {} };
myRequireAsync.cache[name] = module;
let wrapper = Function("asyncRequire, exports, module", code);
await wrapper(myRequireAsync, module.exports, module);
}
console.log(`${name} is in cache. Returning it...`);
return myRequireAsync.cache[name].exports;
}
myRequireAsync.cache = Object.create(null);
window.asyncRequire = myRequireAsync;
async () => {
const asyncStuff = await window.asyncRequire('./main.js');
console.log(asyncStuff);
};
Even better, right ?
Well yea, except that there is no ECMA-way to dynamically import synchronously (without promise).
Now, to understand the repercussions, you absolutely might want to read up on promises/async-await here, if you don't know what that is.
But very simply put, if a function returns a promise, it can be "awaited":
"use strict";
function sleep(interval)
{
return new Promise(
function (resolve, reject)
{
let wait = setTimeout(function () {
clearTimeout(wait);
//reject(new Error(`Promise timed out ! (timeout = ${timeout})`));
resolve();
}, interval);
});
}
The promise would then normally be used like this:
function testSleep()
{
sleep(3000).then(function ()
{
console.log("Waited for 3 seconds");
});
}
But when you return a promise, you can also use await, which means we get rid of the callback (sort of - actually, it is being replaced with a state-machine in the compiler/interpreter).
This way, we make asynchronous code feel like synchronous, so we now can use try-catch for error-handling.
Note that if you want to use await in a function, that function must be declared async (hence async-await).
async function testSleep()
{
await sleep(5000);
console.log("i waited 5 seconds");
}
And also please note that in JavaScript, there is no way to call an async function (blockingly) from a synchronous one (the ones you know). So if you want to use await (aka ECMA-import), all your code needs to be async, which most likely is a problem, if everything isn't already async...
An example of where this simplified implementation of require fails, is when you require a file that is not valid JavaScript, e.g. when you require css, html, txt, svg and images or other binary files.
And it's easy to see why:
If you e.g. put HTML into a JavaScript function body, you of course rightfully get
SyntaxError: Unexpected token '<'
because of Function("bla", "<doctype...")
Now, if you wanted to extend this to for example include non-modules, you could just check the downloaded file-contents for code.indexOf("module.exports") == -1, and then e.g. eval("jquery content") instead of Func (which works fine as long as you're in the browser). Since downloads with Fetch/XmlHttpRequests are subject to the same-origin-policy, and integrity is ensured by SSL/TLS, the use of eval here is rather harmless, provided you checked the JS files before you added them to your site, but that much should be standard-operating-procedure.
Note that there are several implementations of require-like functionality:
the CommonJS (CJS) format, used in Node.js, uses a require function and module.exports to define dependencies and modules. The npm ecosystem is built upon this format. (this is what is implemented above)
the Asynchronous Module Definition (AMD) format, used in browsers, uses a define function to define modules. (basically, this is overcomplicated archaic crap that you wouldn't ever want to use). Also, AMD is the format that is implemented by RequireJS (note that despite the name containing the characters "require", AMD absolutely is NOT CommonJS).
the ES Module (ESM) format. As of ES6 (ES2015), JavaScript supports a native module format. It uses an export keyword to export a module’s public API and an import keyword to import it. This is the one you should use if you don't give a flying f*ck about archaic browsers, such as Safari and IE/EdgeHTML.
the System.register format, designed to support ES6 modules within ES5. (the one you should use, if you need support for older browsers (Safari & IE & old versions of Chrome on mobile phones/tablets), because it can load all formats [for some, plugins are required], can handle cyclic-dependencies, and CSS and HTML - don't define your modules as system.register, though - the format is rather complicated, and remember, it can read the other easier formats)
the Universal Module Definition (UMD) format, compatible to all the above mentioned formats (except ECMA), used both in the browser and in Node.js. It’s especially useful if you write modules that can be used in both NodeJS and the browser. It's somewhat flawed, as it doesn't support the latest ECMA modules, though (maybe this will get fixed) - use System.register instead.
Important sidenote on the function argument "exports":
JavaScript uses call-by-value-sharing - meaning objects are passed as a pointer, but the pointer-value itselfs is passed BY VALUE, not by reference. So you can't override exports by assigning it a new object. Instead, if you want to override exports, you need to assign the new object to module.exports - because hey, module is the pointer passed by value, but exports in module.exports is the reference to the original exports pointer.
Important sidenote on module-Scope:
Modules are evaluated ONCE, and then cached by require.
That means all your modules have a Singleton scope.
If you want a non-singleton scope, you have to do something like:
var x = require("foo.js").createInstance();
or simply
var x = require("foo.js")();
with appropriate code returned by your module.
If you need CommonJS-support for the browser (IE5+, Chrome, Firefox),
check out my code in my comment on Michele Nasti's project
You know how when you are running JavaScript in the browser, you have access to variables like "window" or Math? You do not have to declare these variables, they have been written for you to use whenever you want.
Well, when you are running a file in the Node.js environment, there is a variable that you can use. It is called "module" It is an object. It has a property called "exports." And it works like this:
In a file that we will name example.js, you write:
example.js
module.exports = "some code";
Now, you want this string "some code" in another file.
We will name the other file otherFile.js
In this file, you write:
otherFile.js
let str = require('./example.js')
That require() statement goes to the file that you put inside of it, finds whatever data is stored on the module.exports property. The let str = ... part of your code means that whatever that require statement returns is stored to the str variable.
So, in this example, the end-result is that in otherFile.js you now have this:
let string = "some code";
or -
let str = ('./example.js').module.exports
Note:
the file-name that is written inside of the require statement: If it is a local file, it should be the file-path to example.js. Also, the .js extension is added by default, so I didn't have to write it.
You do something similar when requiring node.js libraries, such as Express. In the express.js file, there is an object named 'module', with a property named 'exports'.
So, it looks something like along these lines, under the hood (I am somewhat of a beginner so some of these details might not be exact, but it's to show the concept:
express.js
module.exports = function() {
//It returns an object with all of the server methods
return {
listen: function(port){},
get: function(route, function(req, res){}){}
}
}
If you are requiring a module, it looks like this:
const moduleName = require("module-name");
If you are requiring a local file, it looks like this:
const localFile = require("./path/to/local-file");
(notice the ./ at the beginning of the file name)
Also note that by default, the export is an object .. eg module.exports = {} So, you can write module.exports.myfunction = () => {} before assigning a value to the module.exports. But you can also replace the object by writing module.exports = "I am not an object anymore."
Two flavours of module.exports / require:
(see here)
Flavour 1
export file (misc.js):
var x = 5;
var addX = function(value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX;
other file:
var misc = require('./misc');
console.log("Adding %d to 10 gives us %d", misc.x, misc.addX(10));
Flavour 2
export file (user.js):
var User = function(name, email) {
this.name = name;
this.email = email;
};
module.exports = User;
other file:
var user = require('./user');
var u = new user();

Categories

Resources