Sharing global variables between javascript files loaded to Meteor - javascript

I have a javascript file that I place in the client/lib folder within my Meteor app. As the file grew bigger, I decided to split it into 3 files and define an object 'App' in the global namespace in order for the 3 files to share the data.
Each file starts with
var app = app || {};
(function () {
'use strict';
app.object1 = {
This way, file2 and file3 can still use app.object1, and so on.
The problem is when Meteor loads the files, it seems to automatically wraps it with function(){}, and this makes app.object1 not accessible from files loaded subsequently.
(function(){
var app = app || {};
(function () {
'use strict';
app.object1 = {
What is the best way to avoid this issue? Thanks.
EDIT: I referred to this posting [Link:][1]Global variables in Meteor which suggests defining the variable without "var". I replaced the code in file1 to app = {}, but my app is now crashing in file2 in the following line of code, with the message from the Meteor console pasted below.
app.ALL_LIST = 'all'
=> Your application is crashing. Waiting for file change.
ReferenceError: app is not defined

omit var in your variable declaration ;) then it will be scoped globally.

Related

creating a global object in nodejs accessible by .js modules

My nodejs project requires memory tables accessible by different .js module. Some modules will update the tables but the data must be the same across all modules(sort of a in memory db). As such, I need a truly global object....not a global per module object. Creating a common.js file with all the objects then require it in all the modules will not do since the data will be global/local to the respective modules. I have seen reference to nodejs globals where global.myobject would be global to all modules but the documentation is not clear as to whether this is so or not. The last discussion I saw was from 2014. Can anyone update me on what is the current situation? How is this problem solved?
In node.js..
if you had a module called common.js, that looked like this..
'use strict';
var obj = {};
module.exports = obj;
And then inside another module you did this
'use strict';
var c = require('./common');
c.test = 1234;
Then later another module did this..
'use strict';
var c = require('./common');
console.log(c);
//output = { test: 1234 }
A module in modejs, is just another object. nodejs, caches any requires, and so will always return the same object.
One gotcha for windows users, windows filenames are not case-sensitive, so if you did require('Common'), and then did require('common'); you would have 2 version of the same module. And this is a good reason to keep all modules names in lowercase.

Adding Webpack to an existing Angular app

I'm working on an existing (and working) Angular 1.5.5 app. It's very small and has a controller, a directive and a couple of services, all split into individual files.
I'd now like to move to Webpack and make the minimum number of changes to the app to support that. A lot of the Webpack/Angular demos I've found have been about creating a new Angular app with web pack built in from the start, but I don't want to rebuild the existing app, just make whatever changes are necessary to use a webpack-produced bundle. It's also using regular JS, whereas most of the tutorials I've seen are for ES6.
I've got grunt-webpack installed and working, it's creating the bundle.js file and I can see inside the bundle that it's pulling in Angular, Angular-aria and Angular-animate (my module dependencies)
However, when I run the site I see an error:
Uncaught TypeError: angular.module is not a function
My webpack task is as follows:
module.exports = {
dist: {
entry: './Static/js/Ng/app.js',
output: {
path: './Static/dist/js',
filename: 'bundle.js'
}
}
};
As I say, the actual Webpack bundling seems to be working as expected and creates the bundle.js file.
The main entry file (app.js) is as follows:
(function () {
'use strict';
var angular = require('../vendor/angular.js');
var ngAria = require('../vendor/angular-aria.js');
var ngAnimate = require('../vendor/angular-animate.js');
angular.module('app', [ngAria, ngAnimate]);
}());
If I log out the angular variable in this file, it's just an empty object, even though I can see the Angular source in the bundle.
What am I missing?
You probably shadow the global angular property by your local var angular variable. Try this:
(function () {
'use strict';
require('../vendor/angular.js');
require('../vendor/angular-aria.js');
require('../vendor/angular-animate.js');
angular.module('app', [ngAria, ngAnimate]);
}());

Error while requiring external library with browserify (this = undefined)

I'm trying to require the library Chart.js with Browserify (tbh it's development environment with gulp, browserify and some other stuff that I barely know how it works togheter):
'use strict';
var angular = require('angular');
require('angular-ui-router');
require('./templates');
require('./controllers/_index');
require('./services/_index');
require('./directives/_index');
window.gauge = require('./vendors/gauge');
//this is what i'm trying to require
window.chartjs = require('./vendors/chart');
angular.element(document).ready(function() {
var requires = [
'ui.router',
'templates',
'app.controllers',
'app.services',
'app.directives'
];
window.app = angular.module('app', requires);
angular.module('app').constant('AppSettings', require('./constants'));
angular.module('app').config(require('./routes'));
angular.module('app').config(require('./PostFix'));
angular.module('app').run(require('./on_run'));
angular.bootstrap(document, ['app']);
});
Tbh it did work well with window.gauge = require('./vendors/gauge'); but when I require vendors/chart.js it throws this error:
undefined // chart.js:4
Uncaught TypeError: Cannot read property 'Chart' of undefined // chart.js:4
And here is those lines in the chart.js file:
(function(){
"use strict";
console.log(this); <------ outputs the "undefined"
var root = this,
previous = root.Chart; <----- fails, as "root" doesn't exist
It's weird, because when I add chart.js using <script></script> that console.log(this) outputs the window object/scope, but when executed from browserify, it's undefined, that's why the chart.js fails.
I'm a total newb with browserify/node/gulp, but I tried different stuff such as:
Browserify-shim -> same error
Requiring the script in different ways, like trying to require it inside an object { }, trying to do a var whatever = new require('./vendors/chart') but failed miserably like a beheaded chicken trying to go to the bathroom.
I'm guessing that somehow I have to attach that script to an object or something so this would not be undefined when executed, but I'm failing to find the way.
I already solved it. The problem was a browserify transform called Babelify. I still don't know why Babel was doing that, but I didn't need it anyway so I just disabled it and that was it. Just posting it here in case it happens to someone else.

Using NPM package in the browser with Browserify

I'm trying to use Browserify so that I can use an npm package in the browser. The package I'm trying to use is this
I have a fcs.js file:
// Use a Node.js core library
var FCS = require('fcs');
// What our module will return when require'd
module.exports = function(FCS) {
return FCS;
};
And an index.js file:
var FCS = require('./fcs.js');
console.log('FCS IS ');
console.log(FCS);
I then ran:
browserify index.js > bundle.js
And created an index.html file:
<html>
<script src="bundle.js"></script>
<script>
var fcs = new FCS();
</script>
</html>
But I end up with the error:
Uncaught ReferenceError: FCS is not defined
Maybe I'm not grasping the concept correctly. How can i use this package in the browser? Thanks.
Don't do this: require('./fcs.js');
Do this: require('./fcs');
When you require something, the extension is implicitly .js. Also make sure that your module, FCS, has an entry point (the default is index.js, but you can change that in the main entry in the package.json).
Also, in your index.html document, you're expecting that FCS is a global object. I haven't seen the internal code of FCS, but it will only be globally available if it's attached to the window object.
When you require something, it only makes it available to the rest of your code where it's required. If you want to make it globally available, you have to attach it to the window object, just like anything else.
In other words, the internals of your FCS module might look something like:
// node_modules -> fcs -> index.js
var FCS = function() {};
window.FCS = FCS; // this makes it globally available
module.exports = FCS; // this lets you require it
#JoshBeam's answer is correct - in order to expose assets inside the browserify bundle, you need to attach something to the window object. But instead of exposing specific assets, I wanted something more general.
Here's what I did:
in my app.js
require('this')
require('that')
require('./modules/mycode')
...
window.req = require
And in my <script> tag in my HTML:
something = req('./modules/mycode')
Notice that, instead of assigning the require function directly to window.require, I gave it a different name. The reason for this is simple: if you call it window.require, you're overwriting the original require and you'll find yourself in an infinite loop of recursion (at least until the browser runs out of stack space).
The problem is that your inline script (in index.html) is expecting a global variable called FCS to exist (when you do new FCS()). This is not the case because in index.js, your FCS variable is scoped to that file.
You should write all your scripts in separate files and bundle them all using browserify, avoiding the inline script or make FCS global, by attaching it to window.

In Node.js, how can I load my modules once and then use them throughout the app?

I want to create one global module file, and then have all my files require that global module file. Inside that file, I would load all the modules once and export a dictionary of loaded modules.
How can I do that?
I actually tried creating this file...and every time I require('global_modules'), all the modules kept reloading. It's O(n).
I want the file to be something like this (but it doesn't work):
//global_modules.js - only load these one time
var modules = {
account_controller: '/account/controller.js',
account_middleware: '/account/middleware.js',
products_controller: '/products/controller.js',
...
}
exports.modules = modules;
1. Using a magic variable (declared without var)
Use magic global variables, without var.
Example:
fs = require("fs");
instead of
var fs = require("fs");
If you don't put var when declaring the variable, the variable will be a magic global one.
I do not recommend this. Especially, if you are in the strict mode ("use strict") that's not going to work at all.
2. Using global.yourVariable = ...
Fields attached to global object become global variables that can be accessed from anywhere in your application.
So, you can do:
global.fs = require("fs");
This is not that bad like 1., but still avoid it when possible.
For your example:
Let's say you have two files: server.js (the main file) and the global_modules.js file.
In server.js you will do this:
require("./global_modules");
and in global_modules.js you will have:
_modules = {
account_controller: require('/account/controller.js'),
account_middleware: require('/account/middleware.js'),
products_controller: require('/products/controller.js'),
...
}
or
global._modules = {...}
In server.js you will be able to do:
_modules.account_controller // returns require('/account/controller.js'),
require already does it. Try loading a module, modify it and then load it another time in another place or file:
var fs = require('fs'):
console.log(fs.hey);
fs.hey = 'HEY TIMEX, WHATS UP?';
//another place of the same process
var fs = require('fs');
console.log(fs.hey);

Categories