Learning npm with browserify.
I would like to refactor a code I wrote in modules.
For the sake of learning, I am trying to break it down little by little.
So far I have something like:
on index.html
<body onload=example.main()>
and on my javascript:
(var example = function() {
var helper = function (){
// smtg
}
// body:
// body is made by global objects, functions that I will then return on traps, e.g. main and helper. I would like now to separete functions and body in dedicated modules, to tide a bit the code
return {
main : function() {
// show main UX
},
helper : helper
}
})()
The first thing I want to do, is to export the function as a module, so that I can call example.main() on my index page.
I would like to start separate functions and "body", and then exports only traps I want in my example object.
I tried:
module.export = function () {
return example
}
var example = function() { ...} // no more calling the anonymous function
but got error example.main is not a function
and other attempts to export my example(), I cannot.
Is it maybe because it is not a constructor?
Could you help to show a syntax and logic of a first example to export only the traps I want from example ( main, helper) and how would you refactor helper, main, and "body" in three different npm modules ?
Related
I have a file containing the definition of a Object and in that same file I have a function that is part of this object like so:
export function ARScene(_callbacks) {
this.callbacksObject = _callbacks;
// more fancy code..
}
ARScene.prototype.changeCar = function() {
//some fancy code here
this.loadHDCar(); // THIS LIKE GENERATES A ERROR.
}
now I have a different file containing an other method that is part of the Object called ARScene like so:
import { ARScene } from './arScene';
ARScene.prototype.loadHDCar = function() {
//some more fancy code..
}
What is happening when I build this with webpack and run it in the browser I get the error that this.loadHDCar(); is undefined I guess this happens because webpack doesnt add a file if it is not imported. But how do I make sure that ARScene.prototype.loadHDCar is added to the object in the final output?
I am a complete newbie to webpack and modules. I have found answers on stackoverflow about this but they had slightly different scenarios then me. So their solutions didnt work (or maybe I didnt understand it).
If more context or information is needed please let me know.
How do I make sure that ARScene.prototype.loadHDCar is added to the object in the final output?
You should import it in the arScene module, and you should even create the prototype method in there (where you are defining the class) for visibility.
export function loadHDCar() {
… //some more fancy code
}
import { loadHDCar } from './loadHDCar';
export function ARScene(_callbacks) {
…
}
ARScene.prototype.loadHDCar = loadHDCar;
ARScene.prototype.changeCar = function() {
… // some fancy code here
this.loadHDCar();
};
I'm using Meteor and am writing unit tests for a Collection. I've got Helper methods for the collection in addition to just regular JS functions.
I.e.
Collection.helpers({
helperFn: function () {
return 'foo';
}
});
//And in the same file
function bar() {
return "bar";
}
Then in my tests file I have something like
import { Collection } from '../collections'
//Use Factory or Stub to create test Document
//This then works just fine and I can assert, etc..
testDoc.helperFn
My question is with wanting to test just the regular 'bar' JS function. This isn't a big deal using ES6 classes because then I can just export the whole class and call any function with an instance of it. But with Meteor I'm finding the only way I can access the function is by using the 'export' keyword.
So in my Collection file
export function bar ({ return bar; });
And now in my test file I'd do something like
import { bar } from '../collection'
I'd rather not add an export statement for every time I test a new function. Is there any way around this or is it not a big deal?
I do think that the export/import is the way to go, but to answer the first part of your question: yes, you can fall back to the original scoping of meteor and put these functions in the global scope of meteor as follows:
do not put your files in the imports/ folder, but into another folder in your project, e.g., server/.
defined the functions as:
bar = function() { /* function body */ }
These variables are interpreted by meteor as being global to the project, and hence do not need to be imported before use.
That said, there was a reason meteor introduced the imports/ folder and corresponding export/import paradigm in version 1.3. It avoids polluting the global scope and makes it much easier to see where things are defined.
perhaps I have not worded the title correctly. Below is the explanation of what I'm trying to do.
I'm creating a helper.js file for my project. Inside it contains many functions, one I've pasted below. I export this function using module.exports.
function generateInternalError(message, stack_trace) {
if (process.env.NODE_ENV == 'dev') {
console.log({ message: message, stack_trace: stack_trace });
} else {
console.log({message: message});
}
}
module.exports = {
generateInternalError: generateInternalError
};
Where I want to utilize this function I would call:
helper.generateInternalError('Not Found',new Error().stack);
And it works as expected.
But, what I have been tasked with, is creating categories of functions. Essentially I need the following:
helper.errors.generateInternalError('Not Found',new Error().stack);
I can not seem to figure out the right way to export a class of functions or an object of functions in NodeJS such that I don't get an error like:
TypeError: helper.errors.generateClientError is not a function
Any assistance is appreciated.
Thank you
The module.exports property of a file is simply an object that maps names to functions. You can define it arbitrarily, for example:
module.exports = {
errors: {
generateInternalError,
...
},
...
};
Then, require('./helper').errors.generateInternalError will be defined.
helpers is just noise if everything is a helper, so drop that. Just use regular modules and unless you are sure you only have one function in that category export multiple functions. If you only export one function with module.exports then you don't need to do that as a property of an object which also means you can just say const genError=require('./errors')
Don't make something like helpers.errors.someErrorFunc because helpers is noise and you make categories with just separate module files. Don't try to make Node.js look like Java or something equally horrible.
It might be better to structure your helper sub classes in separate files.
Example
src/helpers.js
src/helpers/
src/helpers/errors.js
File helpers.js
module.exports = {
errors: require('./helpers/errors')
}
File helpers/errors.js
module.exports = {
generateInternalError: function(){
//write some internal error code here
}
};
Structuring your code like this will keep your root helpers file very organized and create a pattern that is easy to replicate for new subclasses.
If you prefer a less modular approach you could simply just return one big JSON object as other's have demonstrated...
module.exports = {
errors: {
generateInternalError: function(){
//internal error code
},
generateDatabaseError: function(){
//db error code
}
}
}
What 's the difference with the modularisation of a javascript code (with browserify by example) and the dependency injection?
Are they synonymes? Are the two going together? Or Am I missing some point?
Modularisation refers to breaking code into individual, independent "packages".
Dependency injection refers to not hardcoding references to other modules.
As a practical example, you can write modules which are not using dependency injection:
import { Foo } from 'foo';
export function Bar() {
return Foo.baz();
}
Here you have two modules, but this module imports a specific other hardcoded module.
The same module written using dependency injection:
export function Bar(foo) {
return foo.baz();
}
Then somebody else can use this as:
import { Foo } from 'foo';
import { Bar } from 'bar';
Bar(Foo());
You inject the Foo dependency at call time, instead of hardcoding the dependency.
You can refer this article:
Modules are code fragments that implement certain functionality and
are written by using specific techniques. There is no out-of-the box
modularization scheme in the JavaScript language. The upcoming
ECMAScript 6 specification tends to resolve this by introducing the
module concept in the JavaScript language itself. This is the future.
and Dependency injection in JavaScript
The goal
Let's say that we have two modules. The first one is a service which
makes Ajax requests and the second one is a router.
var service = function() {
return { name: 'Service' };
}
var router = function() {
return { name: 'Router' };
}
We have another function which needs these modules.
var doSomething = function(other) {
var s = service();
var r = router();
};
And to make the things a little bit more interesting the function
needs to accept one more parameter. Sure, we could use the above code,
but that's not really flexible. What if we want to use ServiceXML or
ServiceJSON. Or what if we want to mockup some of the modules for
testing purposes. We can't just edit the body of the function. The
first thing which we all come up with is to pass the dependencies as
parameters to the function. I.e.:
var doSomething = function(service, router, other) {
var s = service();
var r = router();
};
By doing this we are passing the exact implementation of the module
which we want. However this brings a new problem. Imagine if we have
doSomething all over our code. What will happen if we need a third
dependency. We can't edit all the function's calls. So, we need an
instrument which will do that for us. That's what dependency injectors
are trying to solve. Let's write down few goals which we want to
achieve:
we should be able to register dependencies
the injector should accept a function and should return a function which somehow gets the needed resources
we should not write a lot, we need short and nice syntax
the injector should keep the scope of the passed function
the passed function should be able to accept custom arguments, not only the described dependencies
A nice list isn't it. Let's dive in.
I want to test a Javascript function with Jasmine that has a structure like this:
showEditUser: function (...) {
// more code here...
var editUserView = new EditUserView();
// more code here...
editUserView.generate(...);
}
editUserView.generate() causes an error. That does not matter because I don't want to test it. But how can I prevent it from being called?
EditUserView is a RequireJS Module that extends another Module called BaseView. The function generate() is defined in BaseView. There are other Modules that extend BaseView and I want all of them not to call generate while testing. How can I do that with Jasmine? It seems not to be possible with spyOn(...).and.callFake() because I don't have the editUserView Object when calling the function. Is there kind of a static way to tell Jasmine to callFake() the function generate in BaseView?
There is no "nice" way to solve this with jasmine. I think, to take a BaseView viewObj as parameter is a nicer coding style. It will reduce the dependencies of the method. So it don't have to know the specific BaseView-class, he will simply need a viewObj that has a generate-method.
showEditUser: function(..., viewObj) {
// ...
viewObj.generate(...);
}
Then you could create a ViewMock and put it into that function like this:
var viewMock = {};
viewMock.generate = jasmine.createSpy('generate() spy');
Then you will call it this way:
showEditUser(..., viewMock);
EDIT: Here is a similar question