When should I use require() and when to use define()? - require

I have being playing around with requirejs for the last few days. I am trying to understand the differences between define and require.
Define seems to allow for module separation and allow for dependency ordering to be adhere. But it downloads all the files it needs to begin with. Whilst require only loads what you need when you need it.
Can these two be used together and for what purposes should each of them be used?

With define you register a module in require.js that you can then depend on in other module definitions or require statements.
With require you "just" load/use a module or javascript file that can be loaded by require.js.
For examples have a look at the documentation
My rule of thumb:
Define: If you want to declare a module other parts of your application will depend on.
Require: If you just want to load and use stuff.

From the require.js source code (line 1902):
/**
* The function that handles definitions of modules. Differs from
* require() in that a string for the module should be the first argument,
* and the function to execute after dependencies are loaded should
* return a value to define the module corresponding to the first argument's
* name.
*/
The define() function accepts two optional parameters (a string that represent a module ID and an array of required modules) and one required parameter (a factory method).
The return of the factory method MUST return the implementation for your module (in the same way that the Module Pattern does).
The require() function doesn't have to return the implementation of a new module.
Using define() you are asking something like "run the function that I am passing as a parameter and assign whatever returns to the ID that I am passing but, before, check that these dependencies are loaded".
Using require() you are saying something like "the function that I pass has the following dependencies, check that these dependencies are loaded before running it".
The require() function is where you use your defined modules, in order to be sure that the modules are defined, but you are not defining new modules there.

General rules:
You use define when you want to define a module that will be reused
You use require to simply load a dependency
//sample1.js file : module definition
define(function() {
var sample1 = {};
//do your stuff
return sample1;
});
//sample2.js file : module definition and also has a dependency on jQuery and sample1.js
define(['jquery', 'sample1'], function($,sample1) {
var sample2 = {
getSample1:sample1.getSomeData();
};
var selectSomeElement = $('#someElementId');
//do your stuff....
return sample2;
});
//calling in any file (mainly in entry file)
require(['sample2'], function(sample2) {
// sample1 will be loaded also
});
Hope this helps you.

"define" method for facilitating module definition
and
"require" method for handling dependency loading
define is used to define named or unnamed modules based on the proposal using the following signature:
define(
module_id /*optional*/,
[dependencies] /*optional*/,
definition function /*function for instantiating the module or object*/
);
require on the other hand is typically used to load code in a top-level JavaScript file or within a module should you wish to dynamically fetch dependencies
Refer to https://addyosmani.com/writing-modular-js/ for more information.

require() and define() both used to load dependencies.There is a major difference between these two method.
Its very Simple Guys
Require() : Method is used to run immediate functionalities.
define() : Method is used to define modules for use in multiple locations(reuse).

Related

Node.js Globalize es6 modules to act like ImportScripts

The question is simple, how do we make es6 modules act like the ImportScript function used on the web browser.
Explanation
The main reason is to soften the blow for developers as they change their code from es5 syntax to es6 so that the transition does not blow up your code the moment you make the change and find out there are a thousand errors due to missing inclusions. It also give's people the option to stay as is indefinitely if you don't want to make the full change at all.
Desired output
ImportScript(A file path/'s); can be applied globally(implicitly) across subsequently required code and vise-verse inside a main file to avoid explicit inclusion in all files.
ES6 Inclusion
This still does not ignore the fact that all your libraries will depend on modules format as well. So it is inevitable that we will still have to include the export statement in every file we need to require. However, this should not limit us to the ability to have a main file that interconnects them all without having to explicitly add includes to every file whenever you need a certain functionality.
DISCLAIMER'S
(Numbered):
(Security) I understand there are many reasons that modules exist and going around them is not advisable for security reasons/load times. However I am not sure about the risk (if any) of even using a method like "eval()" to include such scripts if you are only doing it once at the start of an applications life and to a constant value that does not accept external input. The theory is that if an external entity is able to change the initial state of your program as is launched then your system has already been compromised. So as it is I think the whole argument around Globalization vs modules boils down to the project being done(security/speed needed) and preference/risk.
(Not for everyone) This is a utility I am not implying that everyone uses this
(Already published works) I have searched a lot for this functionality but I am not infallible to err. So If a simple usage of this has already been done that follows this specification(or simpler), I'd love to know how/where I can attain such code. Then I will promptly mark that as the answer or just remove this thread entirely
Example Code
ES5 Way
const fs = require('fs');
let path = require('path');
/* only accepts the scripts with global variables and functions and
does not work with classes unless declared as a var.
*/
function include(f) {
eval.apply(global, [fs.readFileSync(f).toString()])
}
Main file Concept example:
ImportScript("filePath1");loaded first
ImportScript("filePath2");loaded second
ImportScript("filePath3");loaded third
ImportScript("filePath4");loaded fourth
ImportScript("filePath5");loaded fifth
ImportScript("someExternalDependency");sixth
/* where "functionNameFromFile4" is a function defined in
file4 , and "variableFromFile2" is a global dynamic
variable that may change over the lifetime of the
application.
*/
functionNameFromFile4(variableFromFile2);
/* current context has access to previous scripts contexts
and those scripts recognize the current global context as
well in short: All scripts should be able to access
variables and functions from other scripts implicitly
through this , even if they are added after the fact
*/
Typical exported file example (Covers all methods of export via modules):
/*where "varFromFile1" is a dynamic variable created in file1
that may change over the lifetime of the application and "var" is a
variable of type(varFromFile4) being concatenated/added together
with "varFromFile4".
*/
functionNameFromFile4(var){
return var+varFromFile1;
}
//Typical export statement
exportAllHere;
/*
This is just an example and does not cover all usage cases , just
an example of the possible functionality
*/
CONCLUSION
So you still need to export the files as required by the es6 standard , however you only need to import them once in a main file to globalize their functionality across all scripts.
I'm not personally a fan of globalizing all the exports from a module, but here's a little snippet that shows you how one ESM module's exports can be all assigned to the global object:
Suppose you had a simple module called operators.js:
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
You can import that module and then assign all of its exported properties to the global object with this:
import * as m from "./operators.js"
for (const [prop, value] of Object.entries(m)) {
global[prop] = value;
}
// can now access the exports globally
add(1, 2);
FYI, I think the syntax:
include("filePath1")
is going to be tough in ESM modules because dynamic imports in an ESM module using import (which is presumably what you would have to use to implement the include() function you show) are asynchronous (they return a promise), not synchronous like require().
I wonder if a bundler or a transpiler would be an option?
There is experimental work in nodejs related to custom loaders here: https://nodejs.org/api/esm.html#hooks.
If you can handle your include() function returning a promise, here's how you put the above code into that function:
async function include(moduleName) {
const m = await import(moduleName);
for (const [prop, value] of Object.entries(m)) {
global[prop] = value;
}
return m;
}

Check if the required module is a built-in module

I need to check if the module that is going to be loaded is a built-in or an external module. For example, suppose that you have a module named fs inside the node_modules directory. If you do require("fs") the built-in module will be loaded instead of the module inside node_modules, so I'm sure that this question has a solution.
Example:
var loadModule = function (moduleName){
if (isCoreModule (moduleName)){
...
}else{
...
}
};
loadModule ("fs");
process.binding('natives'); returns an object that provides access to all built-in modules, so getting the keys of this object will get you the module names. So you could simply do something like:
var nativeModules = Object.keys(process.binding('natives'));
function loadModule(name) {
if (~nativeModules.indexOf(name)) {
// `name` is a native module name
} else {
// ...
}
};
loadModule('fs');
you can use require.resolve.paths(str):
1- if str is core module the call will return null.
2- if str is not core module you will get an array of strings.
My first attempt would be: require.resolve(moduleName).indexOf('/') <= 0. If that is true, it's a core module. Might not be portable to windows as implemented, but you should be able to use this idea to get going in the right direction.
Aside: beware require.resolve does synchronous filesystem IO. Be careful about using it within a network server.
Aside: Careful with the term "native" which generally means a native-code compiled add-on, or a C/C++ implementation. Both "core" and community modules can be either pure JS or native.
I think "core" is the most accurate term for built-in modules.
Aside: best not to shadow global variable names, so moduleName instead of just module which can be confusing with the global of the same name.
Module.isBuiltin Added in: v18.6.0, v16.17.0
import { isBuiltin } from 'node:module';
isBuiltin('node:fs'); // true
isBuiltin('fs'); // true
isBuiltin('fs/promises'); // true
isBuiltin('wss'); // false

Returning a module in RequireJS

I'm refactoring a large javascript codebase to use RequireJS. Unfortunately, many of the files I'm dealing with are not object-oriented, and cannot return an object without significant modification. Is there a more efficient way to give 'dependent' modules access to the functions and variables contained in a module (without returning an object) ?
I have read about using the exports syntax for defining modules, but it is very unclear whether that would be a valid solution for this situation.
In a defined module, the exports object is what gets exported from the module and passed to whatever module requires it.
Consider this:
define(["exports"], function(exports){
exports.myCustomFunction = function(){};
exports.myCustomObject = {};
exports.myCustomVariable = true;
})
This module will place all the disparate functions and/or objects that you want made public onto the exports object.
At this point RequireJS will use that exports object to pass to a module that requires it:
require(["nameOfCustomModule|filename"], function(myCustomModule){
//evaluates to true
console.log(myCustomModule.myCustomVariable);
})
Here's a simple fiddle. Just bring up your console and you will see the value logged there. http://jsfiddle.net/xeucv/
Hope this clears it up a bit!

Directly calling a function bound to the exports object

I'm reading the cluster.js file of the cluster package and this part confuses me:
fs.readdirSync(__dirname + '/plugins').forEach(function(plugin){
plugin = plugin.replace('.js', '');
exports.__defineGetter__(plugin, function(){
return require('./plugins/' + plugin);
});
});
I know that you can bind objects or functions to the exports object to expose them to different files, but it seems that it is calling a function already bound to the object. However, I always thought you needed to require the file and access functions that way. What is going on here?
This is realization of lazy loading for plugins. Plugin will be loaded only after first access to module property with his name. __defineGetter__ is the 'syntax sugar' not presented in ECMAScript standard. It binds an object's property to a function to be called when that property is looked up.
If a module sets exports to a single function rather than an arbitrary object, then the result of require will be a function reference which can be called directly (note that a function is actually a type of object and as such can have properties, which can also be functions).
That's not what's going on here, though. At the time the code you've shown is executed, a function called __defineGetter__ has already been defined and attached to exports. Here it's simply being called as a method of exports (presumably because the author didn't feel the need to create a redundant local name for it).
i.e. somewhere along the line there's something like
exports.__defineGetter__ = function(propname, getter) {
...
}
Since it doesn't have a local name, the only way to call it is through exports.
Obviously the purpose of the code here is to allow you to call cluster.nameOfPlugin.method(...) without having to manually require each plugin, while not requiring all the possible plugins to be preloaded; instead only the ones you actually use get loaded.

RequireJS - Using both define and require under same function scope

Would like to know is it possible to use both define and require under same function scope. Usually is either require or define, how do I have both under same scope?
define(["my/cart", "my/inventory"],
function(cart, inventory) {
//Define foo/title object in here.
}
);
require(["some/module", "a.js", "b.js"], function(someModule) {
//This function will be called when all the dependencies
//listed above are loaded. Note that this function could
//be called before the page is loaded.
//This callback is optional.
});
The define function is for "defining" modules with dependencies using AMD style, and require is mostly used to call those modules previously defined with define function.
The recommended practice is to define only one module per file, but you can add more than one define if you pass the name of the module as the first argument to that function.
If you pass the name explicitly to the define function you can nest define inside a require call, but it will make no sense, because all the dependencies passed to the require can be passed to the define directly, which is faster an clearer than nesting defines inside requires.
Maybe, nesting a require inside a define could be more useful, perhaps if you have a module with dependencies that are only required under certain conditions, it could make sense to add the common dependencies on the define function, and the more specific ones with a require inside a conditional statement.
In my opinion the important concept is to understand that basically define is for defining AMD modules, and require is for calling them. (you can use non AMD files as dependencies but this is other matter.)

Resources