Require behaves differently in Angular project - node.js

If to write something like const theoretically = require('jasmine-theories');, require returns the content of the file.
But if to set declare var require: any;, then next **require** executions steps inside webpack bootstrap function __webpack_require__(moduleId) and return real file path with hash, not content (for example 'file.65465436547.js').
I've found out that file-loader has such behavior https://www.npmjs.com/package/file-loader .
I may assume that depending on declare var require: any; require is taken from NodeJS or from File-loader.
Is that correct? And is there more obvious way how and when to use each of them?
And how can I config File-loader to behave another way in case of Angular application? Angular CLI doesn't provide webpack.config, therefore loaders just get installed without any configuration possible.
Overall the question can be shortened to:
Why require returns content in one case and file name in another case?

Don't use require, use
import { theoretically } from 'jasmine-theories';
This is webpack tree shakable.

It looks that before declare var require: any; default method is used from Node JS. But after explicit declaring FileLoader's method becomes visible. And as it has default exporting - require usage is switched to FileLoader's one.

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

Brunch config file: what is the difference between exports.config and module.exports = config?

In the guide of the Brunch website, they start the config file as following module.exports = config:, however most of the skeletons you can find on the same website use another syntax exports.config =.
What is the difference between them? Are both javascript CommonJS Module?
I had a look directly at the doc: module node documentation. Something I should have done at first :)
The exports variable that is available within a module starts as a reference to module.exports. As with any variable, if you assign a new value to it, it is no longer bound to the previous value.
If you want the root of your module's export to be a function (such as a constructor) or if you want to export a complete object in one assignment instead of building it one property at a time, assign it to module.exports instead of exports.
Finally, they said:
As a guideline, if the relationship between exports and module.exports seems like magic to you, ignore exports and only use module.exports.
Et voilĂ !

Using node module in angularjs?

What's the best practice for using external code, e.g. code found in node modules, in angular?
I'd like to use this https://www.npmjs.com/package/positionsizingcalculator node module in my angular app. I've created an angular service intended to wrap the node module, and now I want to make the service use the node module.
'use strict';
angular.module('angularcalculator')
.service('MyService', function () {
this.calculate = function () {
return {
//I want to call the node module here, whats the best practice?
};
}
});
To do this, I would crack open the package and grab the .js out of it. This package is MIT license, so we can do whatever we want. If you navigate to /node_modules/positionsizingcalculator/ you'll find an index.js. Open that up and you'll see the moudle export, which takes a function that returns an object.
You'll notice this is an extremely similar pattern to .factory, which also takes a function that returns an object (or constuctor, depending on your pattern). So I'd do the following
.factory('positionsizingcalculator', function(){
basicValidate = function (argument) {
... //Insert whole declaration in here
return position;
})
and the inject it where you need it:
.controller('AppController', function(positionsizingcalculator){
//use it here as you would in node after you inject it via require.
})
--
Edit: This is good for one off grabs of the JS, but if you want a more extensible solution, http://browserify.org/ is a better bet. It allows you to transform your requirements into a single package. Note that this could result in pulling down a lot more code that you might otherwise need, if you make one require bundle for your whole site, as this is not true AMD, and you need to to load everything you might want one the client, unless you make page specific bundles.
You'd still want to do the require in a factory and return it, to keep it in angular's dependency injection framework.

Why does accessing variables declared without `var` work without having to use `require` in other files?

Here's an example
$ cat main.js
App = {
version : 1.1
};
require('./mymod.js');
$ cat mymod.js
console.log(App.version);
$ node main.js
1.1
Note how I declared App in main.js without var. This allowed me to access App from mymod.js without having to call require. If I declare App with a var, this won't work.
I want to understand why this happens? Is it the intended behaviour for node.js or a bug? Is this behavior consistent with ECMAScript or CommonJS standards?
This trick gives a powerful mechanism to circumvent the require module system of node.js. In every file define your objects and add them to the top level App namespace. Your code in other files will be automatically have access to those objects. Did I miss something?
If you assign a variable without using var, it is automatically a global variable. That's just the way JavaScript works. If you put 'use strict'; (quotes required) at the top of your js file, this becomes an error instead.
All has to do with local scope vs global scope.
You can even do this (which is much neater):
app.js:
exports = {
version : 1.1
};
main.js:
var App = require('./app.js');
console.log(App.version);
Defining a variable without a preceding var will place it into the global namespace which is visible to all of your JavaScript code.
While this may seem a useful feature, it is generally considered bad practice to "pollute" the global namespace and can lead to subtle, hard-to-locate bugs when two non-related files both rely upon or define variables with the same name.
In nodeJS environment there is a global scope referenced by 'global' , just like the way we have 'window' in browser environments. In effect every javascript host enviroments always start with creating a global object.
When require('main.js') is executed, there is this following function that is created and executed against the global scope 'global'.
(function(exports,...){
//content of main.js
App = {
version : 1.1
};
})(module.exports,..);
When the above function is executed and since there is no var declaration for App , a property with name 'App' is created on global object and assigned the value.This behavior is according to ECMA spec.
That is how the App gets into global scope and is accessible across all modules.
require has been introduced to standardize development of modules that can be ported and used.

Making modules global for use in other files in node.js

I read in another question that i can not find now that it was a bad idea to make modules in node.js global, then he changed his answer because of changes in node.js
The examples for express.js on github does now show an example.
https://github.com/visionmedia/express/tree/master/examples
So what if i need the same module in multiple files, like sequelize or async?
app.js:
var document = require('./routes/document')
async = require('async');
/routes/document.js:
async.series([...]);
OR
app.js:
var document = require('./routes/document')
var async = require('async');
/routes/document.js:
var async = require('async');
async.series([...]);
Should i require the async module again in document.js, or just make async global so that i can use it without require it in new files?
Do not use globals to access modules. Always use require and only require() the modules you need in that .js file. Require will only load your module once and hold a reference to it.
Only requiring what you need, even if it's several modules, is good because it makes it clear what the dependencies of your code are and might help you restructure your code later.
Only requiring() what you need can also help at the point where you want to replace one module with another. For example, you might want to replace knox(S3) with the new aws-sdk module. When you remove the knox npm module, require will immediately blow up in the files that use/require knox. If it was a global variable, you would need to find all references to that global reference and rely on your IDE or text editor to find it.
In short, include it in each file. The file is cached after the first require, so the content is really only run once (you can test this by putting a log statement in the require; it'll only show once).
What I do is make one file which requires all the others I need, and exports them all. Then you only need to require the one file. This can be really handy when you have many modules that you're including.
There is nothing wrong with requiring a module more than once. Internally require only executes the required file once and then caches the result. See the Node.js Modules documentation for more information.

Resources