How to make sure a module is loaded in NodeJS - javascript

This is a problem I faced more than one. Here is an example file structure:
app.js
folder
-- index.js
-- module1.js
-- module2.js
From app.js, the entry point of my application, I require folder/index.js. This file itself is just a loader who requires all the other files in the directory. module1.js and module2.js both define some methods I want to use eventually. They are never directly required by app.js since index.js takes care of that and adds common helper utilities and applies some transformations to these modules.
All works well if I then use some methods defined in those files from app.js after I required them. But the problem comes when a method defined in module2.js wants to use a method defined in method1.js (or vice-versa). Sometimes it will work, sometimes not (in folders with multiple files I didn't get to find out when precisely it works and when it doesn't yet).
If, from module2.js I require ./index.js and then use methods in it defined by module1.js, I sometimes get Cannot read property 'myMethod' of undefined. I assume it has to do with the order the modules are required by index.js, but I can't seem to find a solution to this common problem (other than duplicating code or not using methods of these other modules).
Is there a common solution to this problem? I tried doing something like this :
var modules = require(./index.js);
exports.myMethod = function() {
if(!modules.module1 || !modules.module1.myOtherMethod) {
modules = require('./index.js');
}
modules.module1.myOtherMethod();
};
But it doesn't to do anything, modules.module1 is still undefined.

It just sounds like module should require module2. That's the solution to module1 needing to call methods in module2.
If you're worried about many calls to require, don't. That's standard practice in every programming language I've used (in particular look at the import statements in any Java program. Java is verbose, I know, but this is correct practice.)
It's definitely bad practice to look at code in one module and have no idea where anything comes from, because the require statements are missing.

You have a circular dependency problem. Try moving some of the common functions to a third file and have module1 and module2 require it, or make sure that one of them requires the other in one way only.
Never ever require a file that requires the current file back.

Related

Importing from outside webpack (runtime importing)

This is just something I thought today and I didn't see a lot of information so I'm going to share this weird cases and how I personally solved them (if there's a better way please comment, but meanwhile this might help others ^^)
In a webpack bundle, every import/require you do, is managed by webpack using their internal require function. That means you cannot use anymore the original NodeJS global require if you are inside a webpack bundle.
See also: Exporting from outside webpack bundle
There's a workaround provided by webpack actually:
A variable called __non_webpack_require__ which is the original require so, in your code, you can do this:
const internalModule = require('internal/module');
// or import internalModule from 'internal/module'; in the ES6 way
const externalModule = __non_webpack_require__('external/module');
If you are using TypeScript, you can add this line in your global.d.ts file to avoid syntax errors:
declare const __non_webpack_require__: NodeRequireFunction;
Fact 1: Actually after the build, you can see how your commonly used require (webpack's) has been renamed to __webpack_require__, and that __non_webpack_require__ has been preserved as the original require.
Fact 2: Webpack also use the original require to import modules from the system (not bundled with the code), such as net, events, fs, etc.

how to import a standalone module build with browserify?

My question is how do I achieve importing a standalone module obtained with browserify, inside another javascript file. Here are some specific details:
I created a standalone module with browserify like this:
browserify module.js --s module_name > output.js
The file module.js contains at the end the line
module.exports = module_name;
Inside a file "use_module.js", I can now use the module module_name, with this code in some html file:
<sctipt src="output.js">
<sctipt src="use_module.js">
But what I would like is to specify just the script "use_module.js" in my html file, and somehow import "output.js" inside "use_module.js" directly in the javascript code. I tried two different approaches :
I tried javascript import module_name from './output.js' inside use_module.js, but then it cannot find the module module_name. Somehow I'm not sure module.exports is the same as export, neither with what browserify does with my module.exports anyway. (I'm very confused about all that).
I tried with require(./output.js) and then re-using browserify, but I then get a lot of weird errors with browserify, about tons of missing modules. Maybe I should specify some module informations in a file next to "output.js", that browserify can process, but I don't know really.
I understood what was failing in both approaches :
As I thought, import works only with export and not modules.exports. Also I read that browserify cannot work with the import/export syntax which is still too new.
More interestingly : a browserified file contains plenty of require(...) calls, which refers to a function created by browserify, and not to the CommonJS require keyword. Of course browserify does not know the difference, and thus look for tons a module to import a second time. All that needs to be done is to rename the word "require" into something else, and browserify can be applied a second time...
I however do not find my answer completely satisfactory : there must be a proper way to do this...

RequireJS: Cannot find module 'domReady'

I have quite an annoying, but probably simple, problem that I just cannot figure out.
In a TypeScript file I have defined the following line:
import test1 = require('domReady');
This "domReady" module is defined in a main.js file that is loaded as the entry point for RequireJS. The definition is as followed:
require.config({
paths: {
'domReady': '../domReady',
}
However... in my TypeScript file I simply get a "cannot find module 'domReady'" and it is driving me insane, as I have double checked the pathing to the file and it is indeed in the correct location with the correct name. Additionally, I am fairly certain that the domReady.js file IS AMD compatible, so it should define an external module just fine! (domReady GitHub Link).
I seriously can't understand why the module can't be found in the import statement. Does anyone have any ideas to what the problem may be?
EDIT 1
The directory structure is as follows:
.
+--App
| +--main.js
| +--dashboard.js
+--domReady.js
The import statement takes place in the "dashboard.js" file, and the config for require.js happens in "main.js".
In order for TypeScript to find a module, you must actually provide module information to TypeScript.
TypeScript doesn’t yet support AMD-style paths configuration, it doesn’t ever use calls within your JavaScript code (like require.config()) to configure itself, and it won’t treat JavaScript files on disk as modules when compiling. So right now, you aren’t doing anything to actually give the compiler the information it needs to successfully process the import statement.
For your code to compile without error, you have to explicitly declare an ambient declaration for the module you’re importing within the compiler, in a separate d.ts file:
// in domReady.d.ts
declare module 'domReady' {
function domReady(callback: () => any): void;
export = domReady;
}
Then, include this d.ts in the list of files you pass to the compiler:
tsc domReady.d.ts App/main.ts App/dashboard.ts
Any other third party JavaScript code that you import also needs ambient declarations to compile successfully; DefinitelyTyped provides d.ts files for many of these.
I've had problems before when the path key and the directory name or file name are the same (in your case, domReady). Might not work, but worth giving it a quick try, i.e.
either
'domReadyModule': '../domReady',
require('domReadyModule')
or rename domReady.js to e.g. domReady-1.0.js and use
'domReady': '../domReady-1.0',
require('domReady')
If that doesn't work, I'd check the relative directories between main.js and the file that is doing the require, or else try importing another library in the same fashion, or finally compare with other libraries that you are importing successfully.
Good luck, hope you resolve the problem!

RequireJS module detection

In my project, I use a few RequireJS modules. I have used the Require JS optimizer (r.js)to package them further into various modules. So, if we have require modules like a.js, b.js, c.js and d.js after packaging we get this :
abc.js ( which is a combination of a.js and b.js)
a.js,
b.js
def.js ( which is a combination of c.js and d.js)
c.js,
d.js
We have made these modules abc.js and def.js available over CDN and end users use it. Is there a way to find out who is using a.js and who is using b.js? I mean, can we detect who downloaded which module in their application. This becomes a little tricky because sometimes it will be loaded from browser cache also. At least can we do it at the level of abc.js and def.js?
The problem is if you're distributing both modules in the same file then you need some way to track the usage of each module (right?) and to complicate thing further, browsers cache static files, other users could download your modules and self host, etc etc.
I think this is a slightly offside solution but it should work. You could grab a JavaScript analytics library like Segment.IO:
https://segment.com
and in your definition for module A (inside it's "factory" or definition block) you could track it's usage:
analytics.track('module A was required');
likewise in module B's definition:
analytics.track('module B was required');
and that way even though they're defined in the same file and could be cached, only when the user requires the individual module do you fire the tracking call, so you'll know exactly when a certain module of yours is used.

Substitude one module for another in node.js

If I have a node.js application that has hundreds of files that reference a module (say underscore) and I want to replace that module with another (say lodash) then the obvious way to do this substitution would be a global name replace and switch out the modules in the package.json file.
Is there anyway to just change the module that a name refers to so that when node.js sees require('moduleA') it actually loads 'moduleB' instead? Now I know that this would cause naming hell because anyone working on the project would see require('moduleA') and wouldn't know that the real module being loaded was 'moduleB' so ultimately you'd probably want to go with the first solution. The use case that I'm thinking of is if you want to try a few alternatives for API compatible modules to measure your application's performance (for example) with each module.
If this is an on-going thing and you want to maintain the ability to programmatically switch between the options often, such as in tests:
Instead of using require("underscore"); throughout your codebase, require a local file instead like require("./lib/underscore");, and have that file conditionally re-export underscore or a different library:
if (global.USE_LODASH) {
module.exports = require("lodash");
} else {
module.exports = require("underscore");
}
If this is a one-off thing to try out an alternative library before making the decision to switch, and you want to do this test quickly first without find-and-replacing in all of your files:
Go inside your node_modules folder, delete or rename the underscore folder, and make a symlink named underscore to the replacement module's folder. I don't recommend this as a long-term solution: running npm install again will likely undo this hack, and most projects choose to avoid checking the node_modules folder into their source repository.
Try to use mock-require module.

Categories

Resources