How to require plugins once and access it globally? - javascript

My app was made before the Nativescript CLI v5.x and got to a point where I needed to update CLI versions. The CLI version 5.4.2 suggests to add "tns-core-modules/" for every 'require' I have in my app since short import is deprecated in v5.2.0, since I have tons of plugins required on tons of pages, it's quite a pain in the ass changing every require line. How can I require all my plugins once and then use them on every page or anywhere I need it?

In javascript you have access to an object that always exists in the global scope, this global object provides variables and functions, the goal is to add your library to it.
You have the window object for example in a browser.
Find the global object (look post here) on your project and add your library to this object like :
var myLib = require('myLib');
var globalObject = Function('return this')();
globalObject.myLib = myLib;

Related

Why not add classes to window or global in a namespaced variable?

I am using webpack to transpile/bundle/etc my js files. Im using the import/export syntax ( as opposed to the CommonJS way of require and export.module ). This means i need to import each class and all subclasses of it however many times if i need to use them in the context of a specific script.
The question:
Even though classes arent natively supported in js, why do we need to import them all the time? Wouldnt it be easier if ( and im only speaking for classes ) they were available to all scopes?
EDIT: To avoid polluting the global scope one could do something like global.myLibs and be done with that issue. I personally prefix my classes with something unique but this method would serve even those that dont i suppose.
For example:
window.myClasses could serve as a container for all my classes. I come from an iOS background where all the classes in a main "bundle", in java i think that would be a "package" are available to everyone. Re-importing the class itself doesnt seem like it serves any purpose.
See here:
Why do i need to import modules everytime in webpack bundle?
and here: Bundling js files with webpack class undefined
Adding things in the global scope can lead you to naming conflicts. What if you created a class named Node, add it to global scope by doing window.Node = Node ? You lose the reference to the browser's global Node object.
You can argue that you will never use names that are already used for global objects. But now, what if in a year or so, a new object is added to the spec with the same name as one of yours, and you want to use it alongside your own object ? You have to make a choice, or rename your own object. This is not future proof.
Importing the same module in every module that uses it is a best practice. Because by doing it, you never pollute the global scope. Don't be afraid that it imports the code of this module n times in your final bundle. Webpack imports it only one time, then uses a reference to the module everytime you are importing it.
See these resources :
JavaScript Modules: A Beginner’s Guide by Preethi Kasireddy on Medium
Eloquent Javascript Modules chapter

Encapsulating requireJS and its modules

I'd like to use something like requireJS to modularise my javascript app, however, there's one particular requirement I'd like to meet that I haven't figured out:
I'm happy enough to have require and define in the global space, however, I don't want modules that I import with require to be accessible globally (i.e. they should be accessible to my app, but not other apps running on the same page).
It seems to me that if I call define('moduleA', function() { ... }); I can then access that module - globally - via the require function. It may not be occupying a variable in the global space itself, or be attached to window, but it still feels bad, because other apps really shouldn't be able to see my internal modules (not to mention potential naming conflicts, etc, can I use contexts to circumvent this?).
This seems to be a step back from just namespacing my modules and including them all inside of one big privatising function at build time.
I could have my own private version of require but my modules (being in different files) wouldn't be able to access define.
Am I missing something or do I just have to live with this? (or alternatively, run an optimizer to bake everything into one file - feels like I could just namespace my modules and not bother with requireJS at all if I do that though).
In your r.js build config add wrap: true and you will no longer pollute the glabal scope with require or define functions.
Edit:
You can also specify a namespace for your require and define with the namespace setting in the r.js build config. You can read more about namespacing in RequireJS's FAQ. From the example.build.js comments:
// Allows namespacing requirejs, require and define calls to a new name.
// This allows stronger assurances of getting a module space that will
// not interfere with others using a define/require AMD-based module
// system. The example below will rename define() calls to foo.define().
// See http://requirejs.org/docs/faq-advanced.html#rename for a more
// complete example.
namespace: 'foo',

How to correctly modularize a node.js project?

I'm creating a node.js project following the class constructor pattern:
function my_class(x,y){
this.x = x;
this.y = y;
}
The starting point of the project is the main.js file. Any class of the project must be able to access global objects (such as "world" and "socket") which are defined on main.js. I found 4 options:
I define my classes inside main.js. They'll have access to main.js's globals for being on it's closure, but main.js will become bloated.
I move the class to another file such as my_class.js and require() it. This doesn't work because my_class's instances will lose the closure context and no longer be able to access main.js's globals.
I move the class to another file and manually inject dependencies to it's constructor (ex: my_class(world,socket)). The problem is, code becomes much more complicated and weird semantics such as "my_instance.world" pop on the source, which is nonsense because "world" is not property of my_class.
I move the class to another file and require it using my_class = eval(fs.readFileSync(()) instead of require. This works just fine as my_class gets main.js's closure context, and is the solution I'm using, but seems hacky.
Which is the right way to modularize such node.js project?
If I understood you correctly the possible solution:
main.js:
(function(){
var global = "test"; // this you wanna have as a closure
var my_class = require('./my_class')(global);
my_class.go();
})();
my_class.js:
module.exports = function(global){
return {
go: function(){
console.log(global);
}
};
};
So it's similar to your 3. option
Your problem seems tricky because you have a circular dependency: main.js depends on the functionality of my_class and my_class depends on the data of main.js.
By putting the data of main.js into the global object you resolve the circular dependency:
main.js depends on the functionality of my_class.js
main.js depends on the data in the global object
my_class.js depends on the data in the global object
Now, to get rid of putting the data into the global object, implement a third module in let us say data.js. Then you require the sources like this:
main.js requires data.js
main.js requires my_class.js
my_class.js requires data.js
Since modules in node.js are singletons both main.js and my_class.js will get the same instance of data.js.
If you want to make variables in main.js available anywhere, then you can assign properties to the global object. See node.js global variables? for example. It would work fine as long as you don't over do it. With Neo's solution, you gain a little more flexibility for example with testing, because you can "inject" an arbitrary object into the module. Not every module has to use the same "global" per se.

"Can't find variable" error with Rails 3.1 and Coffeescript

I have views in my application that reference my application.js file which contains functions I use throughout my application.
I just installed the Rails 3.1 release candidate after having used the edge version of 3.1. Until I installed the RC I wasn't having any problems but now I'm getting this error:
ReferenceError: Can't find variable: indicator_tag
indicator_tag is a function I defined in application.js.
The only difference I notice in the javascript file is that now all my functions are wrapped in:
(function() { ... }).call(this);
I understand this is for variable scoping? But could it be preventing my pages from using those variables? And before anyone asks, I've made sure the javascript paths are correct in my include tags.
By default, every CoffeeScript file is compiled down into a closure. You cannot interact with functions from a different file, unless you export them to a global variable. I'd recommend doing something like this:
On top of every coffeescript file, add a line like
window.Application ||= {}
This will ensure that there's a global named Application present at all times.
Now, for every function that you'll have the need to call from another file, define them as
Application.indicator_tag = (el) ->
...
and call them using
Application.indicator_tag(params)
Dogbert's solution is a great way to go if you have a very sophisticated JS back-end. However, there's a much simpler solution if you only have a handful of functions you're working with. Just add them directly to the window object, like this:
window.indicator_tag = (el) ->
...
Then you can use your functions from anywhere without having to wrap them up in another object.

How to manage multiple JS files server-side with Node.js

I'm working on a project with Node.js and the server-side code is becoming large enough that I would like to split it off into multiple files. It appears this has been done client-side for ages, development is done by inserting a script tag for each file and only for distribution is something like "Make" used to put everything together. I realize there's no point in concatting all the server-side code so I'm not asking how to do that. The closest thing I can find to use is require(), however it doesn't behave quite like script does in the browser in that require'd files do not share a common namespace.
Looking at some older Node.js projects, like Shooter, it appears this was once not the case, that or I'm missing something really simple in my code. My require'd files cannot access the global calling namespace at compile time nor run time. Is there any simple way around this or are we forced to make all our require'd JS files completely autonomous from the calling scope?
You do not want a common namespace because globals are evil. In node we define modules
// someThings.js
(function() {
var someThings = ...;
...
module.exports.getSomeThings = function() {
return someThings();
}
}());
// main.js
var things = require("someThings");
...
doSomething(things.getSomeThings());
You define a module and then expose a public API for your module by writing to exports.
The best way to handle this is dependency injection. Your module exposes an init function and you pass an object hash of dependencies into your module.
If you really insist on accessing global scope then you can access that through global. Every file can write and read to the global object. Again you do not want to use globals.
re #Raynos answer, if the module file is next to the file that includes it, it should be
var things = require("./someThings");
If the module is published on, and installed through, npm, or explicitly put into the ./node_modules/ folder, then the
var things = require("someThings");
is correct.

Categories

Resources