How to inject global variables with Webpack? - node.js

I need a specific instance of Map, generated at compile-time, to be made available to the code that I'm bundling with webpack. My use cases if for an instance of Map, but the question holds for any variable, really.
webpack.DefinePlugin won't work because my instance of Map doesn't survive stringification. I could deserialize/serialize, but that seems inefficient.
options.externals won't work because I'm not requireing an external module to be ignored by the bundler.
I've been able to get this working by setting a value on global, but I'm not sure this is the best way to go about this.
Here's a pathetically-contrived example:
webpack.config.js:
const myVar = new Map([
['a test value', () => {}]
]);
// is there a better way?
global.myVar = myVar;
module.exports = {
entry: './entry.js',
output: {
filename: './output.js'
},
target: 'node',
}
entry.js:
console.log(global.myVar) //=> Map { { "a test value", [Function] } }
In my real-world app, my Map value crawls the file system and builds a mapping of regexes and handlers. This should happen at compile time and is a constant mapping, so I want to consume it in my code-to-be-bundled as a constant.
I tried building the Map inside entry.js, but got all sorts of weird "Cannot find module" errors, I think mostly because the function I'm using to build the Map in the first place heavily abuses dynamic requires in a directory tree outside webpack's purview.
Would appreciate any insight.

Related

RequireJS Map Configuration of Multiple files

I have some files, like,
test/test1,
test/test2,
test/test3
and i want to rename there path to
newtest/test1,
newtest/test2,
newtest/test3
so that if we try to require the above file, then it will point to new path.
In require, one to one mapping is present, but not sure, if something like this is achievable,
require.map = {
"test/*": "newtest/*",
}
Any help :)
The map configuration option supports mapping module prefixes. Here's an example:
require.config({
map: {
"*": {
"foo": "bar"
}
}
});
define("bar/x", function () {
return "bar/x";
})
require(["foo/x"], console.log);
The last require call that tries to load foo/x will load bar/x.
This is as good as it gets for pattern matching with map. RequireJS does not support putting arbitrary patterns in there. Using "test/*": "newtest/*" would not work. The "*" I used in map is not a pattern. It is a hardcoded value that means "in all modules", and happens to look like a glob pattern. So the map above means "in all modules, when foo is required, load bar instead".
I wonder if you really need map. You can probably just use paths. Quoting from map documentation
This sort of capability is really important for larger projects which
may have two sets of modules that need to use two different versions
of 'foo', but they still need to cooperate with each other.
Also see paths documentation
Using the above sample config, "some/module"'s script tag will be
src="/another/path/some/v1.0/module.js".
Here is how paths can be used to map the directory from test to newtest for your example
paths: {
"test": "newtest"
}

how to pass a shared variable to downstream modules?

I have a node toplevel myapp variable that contains some key application state - loggers, db handlers and some other data. The modules downstream in directory hierarchy need access to these data. How can I set up a key/value system in node to do that?
A highly upticked and accepted answer in Express: How to pass app-instance to routes from a different file? suggests using, in a lower level module
//in routes/index.js
var app = require("../app");
But this injects a hard-coded knowledge of the directory structure and file names which should be a bigger no-no jimho. Is there some other method, like something native in JavaScript? Nor do I relish the idea of declaring variables without var.
What is the node way of making a value available to objects created in lower scopes? (I am very much new to node and all-things-node aren't yet obvious to me)
Thanks a lot.
Since using node global (docs here) seems to be the solution that OP used, thought I'd add it as an official answer to collect my valuable points.
I strongly suggest that you namespace your variables, so something like
global.myApp.logger = { info here }
global.myApp.db = {
url: 'mongodb://localhost:27017/test',
connectOptions : {}
}
If you are in app.js and just want to allow access to it
global.myApp = this;
As always, use globals with care...
This is not really related to node but rather general software architecture decisions.
When you have a client and a server module/packages/classes (call them whichever way you like) one way is to define routines on the server module that takes as arguments whichever state data your client keeps on the 'global' scope, completes its tasks and reports back to the client with results.
This way, it is perfectly decoupled and you have a strict control of what data goes where.
Hope this helps :)
One way to do this is in an anonymous function - i.e. instead of returning an object with module.exports, return a function that returns an appropriate value.
So, let's say we want to pass var1 down to our two modules, ./module1.js and ./module2.js. This is how the module code would look:
module.exports = function(var1) {
return {
doSomething: function() { return var1; }
};
}
Then, we can call it like so:
var downstream = require('./module1')('This is var1');
Giving you exactly what you want.
I just created an empty module and installed it under node_modules as appglobals.js
// index.js
module.exports = {};
// package.json too is barebones
{ "name": "appGlobals" }
And then strut it around as without fearing refactoring in future:
var g = require("appglobals");
g.foo = "bar";
I wish it came built in as setter/getter, but the flexibility has to be admired.
(Now I only need to figure out how to package it for production)

r.js: Understand requirejs's r.js optimizer

im trying to figure out if its a good idea to use r.js from require.js to generate a build.js file out of my javascript files to only load one file on production.
But im wondering if this is a good idea in my case as it seems its simply loading absolutely everything into the DOM using up a lot of memory. Maybe i got it wrong.
Look at one of my backbone based views i implemented using require.js. As i know, r.js will take this file and optimize and put it into the final build.js file with all the others views, models and collections defined the same way.
define(function (require) {
"use strict";
var $ = require('jquery'),
_ = require('underscore'),
Backbone = require('backbone'),
tpl = require('text!tpl/start.html'),
Mustache = require('mustache'),
template = Mustache.compile(tpl);
return Backbone.View.extend({
initialize: function () {
},
render: function () {
this.$el.html(template());
return this;
},
events: {
'click #submit': "start"
},
start: function (event) {
// stuff to do ...
}
});
});
I guess the final build.js will simply take my code above and concat them into it, right?
So this means when i update my index.html loading require.js then my build.js file, it will simply load all the views, models and collections into the DOM. Doesn't take that up too much memory, since i don't need everything to be loaded from the beginning.
Does it make sense to call require('path/to/my/view') when its loaded already via the build.js file?
It might indeed not make sense for your application to optimize all modules into one single file. r.js supports this kind of scenario. What you have to do is use the modules option and define as many output files as you need. A generic illustration of this could be:
modules: [
{
name: 'main',
exclude: [ "viewA", "viewB" ],
},
{
name: 'viewA',
exclude: ['core']
},
{
name: 'viewB',
exclude: ['core']
}
]
The setup above assumes that the source to be optimized has modules named main, viewA and viewB. It would create 3 optimized bundles: a core that contains all core modules that would be loaded in any case, viewA which represents a group of modules to be loaded in circumstances so and so, and viewB which represents a group of modules to be loaded in other circumstances.
How you should setup your modules parameter depends on the specifics of your application.

RequireJS Dynamic Paths Replacement

I have a requirejs module which is used as a wrapper to an API that comes from a different JS file:
apiWrapper.js
define([], function () {
return {
funcA: apiFuncA,
funcB: apiFuncB
};
});
It works fine but now I have some new use cases where I need to replace the implementation, e.g. instead of apiFuncA invoke my own function. But I don't want to touch other places in my code, where I call the functions, like apiWrapper.funcA(param).
I can do something like the following:
define([], function () {
return {
funcA: function(){
if(regularUseCase){
return apiFuncA(arguments);
} else {
return (function myFuncAImplementation(params){
//my code, instead of the external API
})(arguments);
}
},
funcB: apiFuncB
};
});
But I feel like it doesn't look nice. What's a more elegant alternative? Is there a way to replace the module (apiWrapper) dynamically? Currently it's defined in my require.config paths definition. Can this path definition be changed at runtime so that I'll use a different file as a wrapper?
Well, first of all, if you use Require.js, you probably want to build it before production. As so, it is important you don't update paths dynamically at runtime or depends on runtime variables to defines path as this will prevent you from running r.js successfully.
There's a lot of tools (requirejs plugins) out there that can help you dynamically change the path to a module or conditionnaly load a dependency.
First, you could use require.replace that allow you to change parts (or all) of a module URL depending on a check you made without breaking the build.
If you're looking for polyfilling, there's requirejs feature
And there's a lot more listed here: https://github.com/jrburke/requirejs/wiki/Plugins

Global function in express.js?

How can I define a global function in express.js, that without require I can call it
"How" is simple enough:
global.fnName = function(){ return "hi"; }; // Andreas Hultgren's answer
But you don't need the global prefix; the thing about the global object is ...
fnName = function(){ return "hi"; }; // i.e. don't do: var name = function(){ ... };
console.log(fnName()); // this prints "hi"
console.log(global.fnName()); // this also prints "hi" - it was assigned to global.
"Without require" is a separate consideration: if you don't use require there is no guarantee your "globals" will have been declared by the time you need them. It enforces loading order of dependencies, among other things.
"Why am I" and "Is it correct to" are now hidden questions you should consider. It is accepted in javascript that Global Variables ...
... should be reserved for objects that have system-wide relevance and they should be named to avoid ambiguity and minimize the risk of naming collisions - Angus Croll, Namespacing in Javascript
i.e. global truly is Global: it is used by every author of every plugin or library you pull in to your application, not just you. Naming collisions between global variables break your application. This applies equally in node.js.
Global variables are also thought of as a code smell. In the detail sections below here you will see you can quickly get into trouble by using global variables, and they should really be treated as something that pushes you towards dependency injection and/or namespaces and modules.
Node.js and express - global vars and functions
Here's a good rule: if you upload it to a web server, or share it with other people, don't use global variables.
global is permissible in tiny "Saturday afternoon" apps in node.js with express.js, but tend to cause problems later if they get adopted into production. Therefore:
Modules and exports is best practice.
Injection should also be used to reduce coupling between javascript files. But in all cases you will usually need require to ensure they exist by the time you need them:
You should really consider app.locals data, and/or middleware functions, for anything that is view data related.
// call this as a function with an input object to merge
// the new properties with any existing ones in app.locals
app.locals.({
sayHello: function() { return "hi"; }
});
// now you can also use this in a template, like a jade template
=sayHello()
If you are creating global vars/functions for configuration settings purposes the below comments about namespaces still apply, and there are conventions emerging such as config.json files (still using require) for settings that are globally accessed.
Global variables - simple case
It is simple enough to declare a global variable in javascript, and for a function the process is no different. Simply omit the var keyword which would normally force a local scope on the declaration:
// app.js
blah = "boo";
sayHello = function(string toWho) { return "hello " + toWho; }
getVersion = function() { return "0.0.0.1"; }
// routes/main.js
console.log(blah); // logs: "boo"
console.log(global.blah); // logs: "boo"
console.log(sayHello("World")); // logs: "hello World"
console.log(global.sayHello("World")); // logs: "hello World"
console.log(getVersion()); // logs: "0.0.0.1"
But what if two separate plugins in your project use a global getVersion function - how do you get the right version number? Also, how do you ensure that getVersion exists before you need it, or exists at all?
Why do we need require?
To quote the nodejitsu docs the built in require function ...
... is the easiest way to include modules that exist in separate files. The basic functionality of require is that it reads a javascript file, executes the file, and then proceeds to return the exports object
"So", you may ask, "require just makes sure that a module from another file is included? Why bother?" It's better than that: you can make a whole folder a module, making your code easier to organise and test test test, it will recognise various extensions for file modules, not just .js, and it will look in various folders as well. Of course, it caches as well.
So, now that require has found your module, it ensures the code inside it is executed, and puts the objects your created into a "namespace":
// module file ./myModule.js
exports.blah = "boo";
exports.sayHello = function(string toWho) { return "hello " + toWho; }
// routes/main.js
var demoModuleReference = require('./myModule.js');
console.log(demoModuleReference.blah); // logs: "boo"
console.log(demoModuleReference.sayHello("World")); // logs: "hello World"
In that sample, demoModuleReference is an object that looks like:
{
blah: "foo",
sayHello: [Function]
}
Why modules and not global variables (a.k.a namespacing and "Global is the new private")?
Seems complicated now? Surely global variables are easier? requires ensures the following:
It ensures ordered loading of dependencies
It prevents variable name conflicts within global through the exports object.
This application at mankz.com (chrome or firefox only) is fascinating. Depending on how you use your js code, you are very likely to have variable name conflicts within the global scope. Name conflicts come from everywhere. In a browser, for instance, they can come from extensions. node.js is slightly different, but it is becoming more and more extended by compatible plugins as time goes on (you can load jquery in right now, for example). As the versions go on frameworks will get added, and name collisions in global will become more likely. My last run of that app in chrome showed over 1200 global namespace variables.
Namespaces - why?
This global namespace pollution was publicised early on by Douglas Crockford through Eric Miraglia in the article "A JavaScript Module Pattern". In summary:
All objects that need to be used between js files are really global
So, create a namespace object that will be unique
Assign the return value an anonymous function
Add private methods and variables inside that function
Do something useful with the pattern
Example:
ANDYBROWNSONICSUITE.BoomBox.SoundModule = function () {
var privateField = "can't touch this";
return {
play: function() {
console.log(privateField);
}
}
}
Why is this good?
Now you have only increased the global namespace members in the world by one, but this member contains as many items as you like.
Your application is far less likely to clash with other namespaces
It's a pattern, other frameworks expect you to use it to interact with them properly. In that reference, jQuery is a browser plugin, but you can use it with node and therefore your app, so the library interactivity policy statement is a perfect example.
It's a pattern, if we all follow it we our programs are all more likely to get along
When you read the Crockford reference along with the Croll reference (Direct Assignment section) I mentioned at the start, you see why it looks this complicated rather than just doing: sound.play = function() { ... } - ease of maintenance, refactoring the namespace etc. being just one reason.
Summary
In summary:
Can I create globals? Yes, it's simple, omit the var keyword before the declaration.
Should I create globals? You should use the module pattern, which is implicitly supported by node, and by express
Why am I creating globals? If it's for configuration, use a config namespace (e.g. How to store Node.js deployment settings/configuration files?)
You can:
global.name = function(){};
But you really should avoid using globals, even if it's possible to use them.

Resources