requireJS in a reporting tool - need to understand standard behavior - requirejs

I have to use a reporting tool (IBM Cognos analytics), which provides the ability to inserts custom scripts in HTML reports created by this reporting tool. So, we are supposed to be able to reference JS libraries like jQuery, jQueryUI, and work with them, etc..
This functionality in the reporting tool is official, and it is stated that they are using requirejs to handle this.
The model of code we need to respect in this case (from IBM "api") is the following:
define(['https://our_site/someFolder/someResource.js'], function() {
/*
A) - Here, I would expected that any code writtne here is executed only when "someResource.js" has been loaded
*/
function monModule() { };
monModule.prototype.setData= function() {
/*
B) - some code here
*/
};
monModule.prototype.draw= function(o) {
/*
C) - some code here
*/
};
return myObject;});
My questions are the following:
1) My current understanding of the behavior within a "define" block is that the JS code will be executed only once the resources mentioned in the "define" instruction are loaded/available. Is it correct?
In the example above, the part mentioned in A) or C) would be "evaluated" / executed only when the resource "someResource.js" is loaded. Do I understand correctly?
2) the RequireJs library used by IBM Cognos analytics shows the following:
/** vim: et:ts=4:sw=4:sts=4
* #license RequireJS 2.1.14 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
* Available via the MIT or new BSD license.
* see: http://github.com/jrburke/requirejs for details
*/
Can I assume then that the RequireJS library used by IBM Cognos analytics is the "common" / "standard" and not a derived one, and so that all functionalities and behavior of RequireJS should be available in IBM Cognos analytics?
I'm asking all this because we are facing issues where some piece of JS code seems to be executed before the resource is loaded; we get error like ' "$" doesn't exist ..etc..'.
Any help / advice is welcome.
Thanks!

1). The callback of define() is only executed once, to define your module.So in your example, only A) will be executed, but B) and C) are the code of methods in the prototype of monModule
Here are steps which RequireJS is doing under the hood when you execute define() function:
It loads async module's dependencies
When dependencies are loaded, it executes the callback, injecting loaded dependencies as arguments. The callback should returns a value which is defined module.
It stores internally the returned value, so when other module require just defined module it will be injected as argument.
2) You can calculate md5 checksum for that file and validate it against the "official" RequireJS library
About errors you are get. Maybe you need to setup shim to make sure that jQuery is loaded before the module which needs jQuery?

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;
}

How do I find what files use a specific function or file in a Node project, using VSCode?

I'm working with a Node project using VSCode. I'd like to be able to follow the tree upwards from functions/files at a lower level. That is, if I have an exported function doSomething in file dosomething.js, I'd like to see what code calls this function, and/or see what code requires this file.
// index.js
const { doSomething } = require('./tricky-stuff')
// tricky-stuff.js
const doSomething = function() {}
module.exports = {doSomething}
If I'm browsing tricky-stuff.js, is there a built-in feature to VSCode that allows me to see usages of either the function doSomething or where the file tricky-stuff.js is required/imported, so that it would show me the file index.js in this case (as well as perhaps other files where tricky-stuff is used)? Is there any extension? I seem to recall that WebStorm could do this, but I can't remember. (I know I could search for strings, but that seems inelegant).
I think it largely depends on how much VScode knows about your code, via the TypeScript language service or JSDoc comments etc...
Typically you can right click on a function and select the peek all references or find all references options:
In this case, it will show you all the places where that function is called or referenced.

How do the core modules in node.js work? (https://github.com/nodejs/node/blob/master/lib)

Does the node interpreter look for core modules (let's say "fs") within the node binary? If yes, are these modules packaged as js files. Are the core modules that are referenced within our code converted to c/c++ code first and then executed? For example, I see a method in the _tls_common.js (https://github.com/nodejs/node/blob/master/lib/_tls_common.js) file called "loadPKCS12" and the only place that I see this method being referenced/defined is within the "node_crypto.cc" file (https://github.com/nodejs/node/blob/master/src/node_crypto.cc). So how does node link a method in javascript with the one defined in the c/c++ file?
here is the extract from the _tls_common.js file that makes use of the "loadPKCS12" method:
if (passphrase) {
c.context.loadPKCS12(buf, toBuf(passphrase));
} else {
c.context.loadPKCS12(buf);
}
}
} else {
const buf = toBuf(options.pfx);
const passphrase = options.passphrase;
if (passphrase) {
c.context.loadPKCS12(buf, toBuf(passphrase));
} else {
c.context.loadPKCS12(buf);
There are two different (but seemingly related) questions asked here. The first one is: "How the core modules work?". Second one being "How does NodeJS let c++ code get referenced and executed in JavaScript?". Let's take them one by one.
How the core modules work?
The core modules are packaged with NodeJS binary. And, while they are packaged with the binary, they are not converted to c++ code before packaging. The internal modules are loaded into memory during bootstrap of the node process. When a program executes, lets say require('fs'), the require function simply returns the already loaded module from cache. The actual loading of the internal module obviously happens in c++ code.
How does NodeJS let c++ code get referenced in JS?
This ability comes partly from V8 engine which exposes the ability to create and manage JS constructs in C++, and partly from NodeJS / LibUV which create a wrapper on top of V8 to provide the execution environment. The documentation about such node modules can be accessed here. As the documentation states, these c++ modules can be used in JS file by requiring them, like any other ordinary JS module.
Your example for use of c++ function in JS (loadPKCS12), however, is more special case of internal c++ functionality of NodeJS. loadPKCS12 is called on a object of SecureContext imported from crypto c++ module. If you follow the link to SecureContext import in _tls_common.js above, you will see that the crypto is not loaded using require(), instead a special (global) method internalBinding is used to obtain the reference. At the last line in node_crypto.cc file, initializer for internal module crypto is registered. Following the chain of initialization, node::crypto::Initialize calls node::crypto::SecureContext::Initialize which creates a function template, assigns the appropriate prototype methods and exports it on target. Eventually these exported functionalities from C++ world are imported and used in JS-World using internalBinding.

Lazy loading boilerplate modules

in boilerplatejs it looks like modules are pre-loaded
(Refer to code below)
return [
require('./baseModule/module'),
require('./sampleModule2/module'),
require('./customerModule/module'),
require('./orderSearchModule/module'),
require('./orderListModule/module'),
require('./mainMenuModule/module')
];
what is the impact on this when it comes to large scale web applications (module heavy web applications) . Is there any way to lazy load modules in boilerplatejs?
Java script has no reflection type of mechanism to load things. Any module that needs to be loaded has to be registered somewhere. This is why modules (sub contexts) are loaded as below:
appContext.loadChildContexts(moduleContexts);
(in src/application.js)
But code you have above is about requirejs AMD modules. This is basically the import of different JS scripts (each representing code for modules). With requireJS AMD, scripts (your source code) are not lazy loaded, but pre loaded. This make sense since your application source code should be available in the browser for execution. On the other hand, when you do JS optimization, we anyway create a single script containing all your source code. Then there is no meaning of having separate script files, or lazy loading of the source code.
But lazy loading should be applied to the behaviors (not to load code). This is why the UI components (ViewTemplate) are only created at the 'activate()' method. These are created only when users demands for it. That is a lazy loading of behavior, so that application rendering time is less.
this.activate = function(parent, params) {
// if panel is not created, lets create it and initiate bindings
if (!panel) {
panel = new Boiler.ViewTemplate(parent, template, nls);
...
}
vm.initialize(params.name);
panel.show();
}

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

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).

Resources