I have a question about get routes and dependency of the main module dynamically. I've been researching this for over 3 days now and haven't found a satisfactory answer. I have found something which seems to come close but it's not what I'm looking for, I do not want to lazy-load my modules or just set routes dynamically .
so I will try to explain my needs as clearly as possible:
there is a folder that name is shared in my project that contains some reusable modules. I need my app.js to realize routes by drag and drop modules and dependency without manually change!
Does anyone have a solution for this?
Thank you for your time and help
This snippet can address your dynamic module resolution requirements.
create deps array and then pass it to "define" method (registered by requirejs).
put all of your related dependencies in the same folder. for each module, you can create a separate js file. every time that I need a new service, I create a separate js file for that service and place it to the 'services' directory and finally append the new service name to the dependency array. and new module is ready to use.
(function () {
(function (deps) {
window.app.utils.appendPrefixToPaths(window.app.paths.services.out.get(), deps);
deps.unshift("2.services/directive");
deps.unshift("2.services/view");
deps.unshift("2.services/preference");
deps.unshift("2.services/alert");
deps.unshift("2.services/materialDataTable");
deps.unshift("2.services/security");
deps.unshift("2.services/theme");
deps.unshift("1.directives/_");
define(deps, function (obj) {
return obj;
});
})(window.app.services.fileNames.get());
})();
Related
I have a structure to my angularjs app project as below:
I am aiming to have each component have its own controller and service to display portfolio information like images, videos, links etc.
The issue I am having is that the only way I am able to define each controller is by stacking them into my head tag in the index.html file. If I choose to create more pages, I am going to have to do this over and over again, meaning lots of calls, lots of load time etc.
Is there a way to inject each of these controllers into the app.module.js file, so this is the only file that needs to be loaded?
thanks in advance.
You will still have to place a script-tag into your html-file for every script-file you have. For testing/learning purposes you can just put them there by hand. But when this gets to annoying for you, consider using some kind of build tool like Gulp where you can inject them based on folder structure for example.
You can define index.js file for every folder and export this modules with gulp for bundle.js
like
module.exports =
angular.module('app.component.contact', [
]);
and assume that you need sub-folders and different directives at the contact folder like:
---contact
---list
---favorites
then:
module.exports =
angular.module('app.component.contact', [
'angularMoment',
require("./list"),
require("./favorites"),
]);
also parent of the contact like components you can do export operation like that:
module.exports =
angular.module('app.component', [
'ui.router',
require('./about'),
require('./contact'),
require('./home'),
]);
this is the simple logic of the exports from child to parent folders.
I am mildly familiar with require.js and Backbone.js having used them together for about a year now and relatively new to Backbone.Marionette although I am very interested in what it can bring to the table.
In looking for examples of project structure (I can get a little obsessed with this stuff) I have found https://github.com/BoilerplateMVC/Marionette-Require-Boilerplate and other similar examples.
Something that has been bothering me: in their app.js file, they return a reference to an instance of a Marionette application, ie:
var app = new Backbone.Marionette.Application();
app.addInitializer(...);
...
return app;
And in many components, they reference the app.js via require.js and use as follows:
define([..., 'app'], function (... , App) {
App.someProperty(...);
});
Now here's what I'm not understanding: I have been under the assumption that the code in their app.js is really more like a Factory than a Class since it returns an instance of an application rather than, say, a modified prototype or extension thereof.
Therefore, when they reference app.js, aren't they actually creating a whole new instance rather than accessing some sort of shared instance? There is nothing to suggest that app.js is returning a singleton in their code.
And yet, it works, and obviously I am the one who is confused.
So, why does this work?
This works because objects are passed by reference in javascript and the fact that require.js only loads every dependency once. Then, app.js returns an initialized instance, and every other module that requires 'app' gets reference to the same object.
It's not a factory, it's simply an initialized application object instance.
I'm trying to update the javascript on a large scale, php/codeigniter based website. It has many, many php partials for code being loaded onto certain pages, but only one footer, header. Most of the partials have inline script tags in them for loading javascript. This needs to be fixed and because the site is very modular with components being used multiple times across pages, require.js seems like a pretty good solution.
So, it's instantiate javascript, we typically do this.
<script type="javascript" src="../js/scriptname.js">
<script type="javascript">
DP.scriptname.init(parameters)
</script>
I'd like to get away from this and just have a have a single entry point for the js using require.
My question is this: what's the best way to instantiate javascript for certain pages using require? Do I need I need to continue including my scripts in the partial and then do something like writing a require module for that specific page and then wrap it all in my data-main script like this? We're planning on using Backbone and Marionette as well, but I won't be able to use the Backbone router to do anything like setting hash URLs. Should I use the URLs to instantiate my require modules perhaps?
Ok, hope someone can help. My experience has typically been in building single page websites. This is different. Thanks
Cam
Well, if I understand your question correctly, you can use Require JS in such way.
First of all, write a config in which you can describe mapping between module names and concrete files. For example:
requirejs.config({
baseUrl: 'js/modules' // by default load any module using this path
});
After that you should refactor your existing module and adjust it to the AMD format (see http://requirejs.org/docs/whyamd.html)
As a result of this step you will have something like this (let's say in file 'js/modules/scriptname.js'):
// module has the same name as the file, which contains it - "scriptname"
define(function () {
// define the module value by returning a value
return function () {};
});
And as a final step you can refactor your inline script and use this module in such way:
<script type="javascript">
// when we place name of the module as a first argument of the "define"
// function, Require JS find file that contains it and load it asynchronously
define(["scriptname"], function (scriptname) {
// "scriptname" now contains value that we recieve from the module definition
scriptname.init(parameters);
});
</script>
Hope this helps.
Note. My solution based on this section of official Require JS documentation: http://requirejs.org/docs/api.html#jsfiles
This question seems to come up a lot, so I'll point you to some resources that may help:
How does RequireJS work with multiple pages and partial views? - https://stackoverflow.com/a/10816983/617615
Modular HTML components with RequireJS - http://simonsmith.io/modular-html-components-with-requirejs/
Example RequireJS-based project that has multiple pages that share a common set of modules - https://github.com/requirejs/example-multipage
I scaffolded a simple Angular app using Yeoman, and I've been playing with it ever since.
Inside the file app.js, which is the first one listed as a <script> inside index.html, I define the main module as:
angular.module('myMod', [])
.config(...)
Note the empty array of dependencies.
Now, when I want to, say, add a filter to this module, I create a myFilter.js file (which I load after app.js inside index.html); myFilter.js consists of:
angular.module('myMod').filter(...)
Note there's just one parameter to the module() function. If I pass the empty array of dependencies as a parameter to this module() function, really nothing appears on screen.
I've been playing with a bunch of other files which extended myMod with controllers, and passing [] as a parameter to the angular.module() function breaks my app every time.
It seems to me like I can only call angular.module() once using the second parameter, which may have some sense (how many times do I want to list my dependencies? What about consistency?). Is it that way?
If it is, is there some standard place where to list dependencies for a module?
angular.module("myModule",["dependencyA"]) will create a new module (this will crash if module allready exists.)
angular.module("myModule") uses an already known module.
This will also affect how you need to load the scripts in the index.html
You should declare your dependencies only once. In addition, it's best practice to keep all of your filters as a separate module that your app depends on, for example:
var myApp = angular.module('myApp', ['myApp.filters', 'myApp.directives', 'myApp.someOtherDependency']);
then, you would define your filters as a module that your app is dependant on:
angular.module('myApp.filters', []).filter(...)
In complex client side projects, the number of Javascript files can get very large. However, for performance reasons it's good to concatenate these files, and compress the resulting file for sending over the wire. I am having problems in concatenating these as the dependencies are included after they are needed in some cases.
For instance, there are 2 files:
/modules/Module.js <requires Core.js>
/modules/core/Core.js
The directories are recursively traversed, and Module.js gets included before Core.js, which causes errors. This is just a simple example where dependencies could span across directories, and there could be other complex cases. There are no circular dependencies though.
The Javascript structure I follow is similar to Java packages, where each file defines a single Object (I'm using MooTools, but that's irrelevant). The structure of each javascript file and the dependencies is always consistent:
Module.js
var Module = new Class({
Implements: Core,
...
});
Core.js
var Core = new Class({
...
});
What practices do you usually follow to handle dependencies in projects where the number of Javascript files is huge, and there are inter-file dependencies?
Using directories is clever, however, I think you might run into problems when you have multiple dependencies. I found that I had to create my own solution to handle this. So, I created a dependency management tool that is worth checking out. (Pyramid Dependency Manager documentation)
It does some important things other javascript dependency managers don't do, mainly
Handles other files (including inserting html for views...yes, you can separate your views during development)
Combines the files for you in javascript when you are ready for release (no need to install external tools)
Has a generic include for all html pages. You only have to update one file when a dependency gets added, removed, renamed, etc
Some sample code to show how it works during development.
File: dependencyLoader.js
//Set up file dependencies
Pyramid.newDependency({
name: 'standard',
files: [
'standardResources/jquery.1.6.1.min.js'
]
});
Pyramid.newDependency({
name:'lookAndFeel',
files: [
'styles.css',
'customStyles.css'
]
});
Pyramid.newDependency({
name:'main',
files: [
'createNamespace.js',
'views/buttonView.view', //contains just html code for a jquery.tmpl template
'models/person.js',
'init.js'
],
dependencies: ['standard','lookAndFeel']
});
Html Files
<head>
<script src="standardResources/pyramid-1.0.1.js"></script>
<script src="dependencyLoader.js"></script>
<script type="text/javascript">
Pyramid.load('main');
</script>
</head>
This may be crude, but what I do is keep my separate script fragments in separate files. My project is such that I'm willing to have all my Javascript available for every page (because, after all, it'll be cached, and I'm not noticing performance problems from the parse step). Therefore, at build time, my Ant script runs Freemarker via a little custom Ant task. That tasks roots around the source tree and gathers up all the separate Javascript source files into a group of Maps. There are a few different kinds of sources (jQuery extensions, some page-load operations, so general utilities, and so on), so the task groups those different kinds together (getting its hints as to what's what from the script source directory structure.
Once it's built the Maps, it feeds those into Freemarker. There's a single global template, and via Freemarker all the script fragments are packed into that one file. Then that goes through YUI compressor, and bingo! each page just grabs that one script, and once it's cached there's no more script fetchery over my entire site.
Dependencies, you ask? Well, that Ant task orders my source files by name as it builds those maps, so where I need to ensure definition-use ordering I just prefix the files with numeric codes. (At some point I'm going to spiff it up so that the source files can keep their ordering info, or maybe even explicitly declared dependencies, inside the source in comment blocks or something. I'm not too motivated because though it's a little ugly it really doesn't bother anybody that much.)
There is a very crude dependency finder that I've written based on which I am doing the concatenation. Turns out the fact that its using MooTools is not so irrelevant after all. The solution works great because it does not require maintaining dependency information separately, since it's available within the javascript files itself meaning I can be super lazy.
Since the class and file naming was consistent, class Something will always have the filename Something.js. To find the external dependencies, I'm looking for three things:
does it Implement any other
classes
does it Extend any other
classes
does it instantiate other classes
using the new keyword
A search for the above three patterns in each javascript file gives its dependent classes. After finding the dependent classes, all Javascript files residing in any folder are searched and matched with this class name to figure out where that class is defined. Once the dependencies are found, I build a dependency graph and use the topological sort algorithm to generate the order in which files should be included.
I say just copy and paste this files to a one file in an ordered way. Each file will have a starting and ending comment to distinguish each particular code.
Each time you updated one of the files, you'll need to updated this file. So, this file need to contain only finish libraries, that not going to changes in the near time.
Your directory structure is inverted...
Core dependencies should be in the root and modules are in subdirs.
scripts/core.js
scripts/modules/module1.js
and your problem is solved.
Any further dependency issues will be indicative of defective 'class'/dependency design.
Similar to Mendy, but I create combined files on server-side. The created files will also be minified, and will have a unique name to omit cache issues after an update.
Of course, this practice only makes sense in a whole application or in a framework.
I think your best bet if at all possible, would be to redesign to not have a huge number of javascript files with interfile dependencies. Javascript just wasn't intended to go there.
This is probably too obvious but have you looked at the mootools Core Depender: http://mootools.net/docs/more/Core/Depender
One way to break the parse-time or load-time dependencies is with Self-Defining Objects (a variation on Self-Defining Functions).
Let's say you have something like this:
var obj = new Obj();
Where this line is in someFile.js and Obj is defined in Obj.js. In order for this to parse successfully you must load or concatenate Obj.js before someFile.js.
But if you define obj like this:
var obj = {
init: function() {
obj = new Obj();
}
};
Then at parse or load time it doesn't matter what order you load the two files in as long as Obj is visible at run-time. You will have to call obj.init() in order to get your object into the state you want it, but that's a small price to pay for breaking the dependency.
Just to make it clearer how this works here is some code you can cut and paste into a browser console:
var Obj = function() {
this.func1 = function ( ) {
console.log("func1 in constructor function");
};
this.init = function () {
console.log("init in constructor function");
}
};
var obj = {
init: function() {
console.log("init in original object");
obj = new Obj();
obj.init();
}
};
obj.init();
obj.func1();
And you could also try a module loader like RequireJS.