For multiple pages use single requireJs config or multiple? - javascript

I have a rather large multi-page website. Each page will require a set of common js libraries (jquery, etc) as well as at least one js file specific to that page (that sets up an js functionality specific to said page).
I can have one config file for the entire site that sets up all my paths. This seems like the logical choice so that a config file for the paths needed for a specific file will not be needed for each page (a pain to maintain, and essentially negates what I am trying to do with requirejs).
However, part of me cringes at the idea of having paths available to a page that will never need them.
Question: What is recommended approach: use one combined require.config or multiple smaller configs (common + one-per-page)?
Note: I will be pulling js files from a CDN so none of the paths will be local, which I know isn't really a concern with the config file.

Generally I'd advise bundling your paths together, not only does this tend to be a convention other developers will expect. It also means your options can be re-used by the build tool by simply pointing it to file containing your config options.
However, if you really would like to separate the options then multiple calls to require.config() are permitted and the config object will simply be mixed.
require.config({
paths: {
'moduleA': 'bla/bla'
}
})
require.config({
paths: {
'moduleB': 'bla/bla2'
}
})

Related

Bundling a durandal single page application into one HTML page

I have a very strange requirement that I need to bundle everything together in one HTML page with my Durandal Single Page application. I can make this away with my dependencies as I am defining them with a name:
define("models.mapper", [], function() {
});
However, it seems like it will not be possible to bundle durandal stuff as it defines modules without names:
define(['require', 'jquery'], function(require, $) {
// ....
}
This is fine when you want to make it work with path references but it seems like this will make it hard to inline this into HTML. Any ideas or suggestions on this?
Require.JS requires you to have only one anonymous define per file so that it can use the file path+name relative to the base path to give it a name. If you would like to have the durandal source inline on your page as well then you'll need to update their define lines to give them the appropriate names (i.e. define('durnadal/system', ......).
An easier approach may be to just build your source code in the structure of a normal durandal project and then use the RequireJS optimizer (http://requirejs.org/docs/optimization.html) to build them into a single JS file - if you configure this correctly without minification then you can just paste the file contents into a script tag on your page and it'll still be legible!
If you really wanted to you could then just continue developing in the single HTML file however you really should look at automating all of this into a grunt workflow and it shouldn't be too hard and you'll have much easier to manage code. Note that you may even be able to use the durandal grunt task to do this, but I'm not sure what options it allows you to provide but you can definitely use the requirejs grunt task and build it into your workflow without minification. With some templating task you could then inject that output into your final HTML page.

Requirejs multi-page & multi-app not executing define callbacks

I have a multi-page / mulit-application minifcation I'm trying to make work.
the structure is as follows
common/
--main config file that defines the common libs
common/build
--app.build.js (see example below)
application1/
--application
--milion other files
application2/
--application
--thousand other files
this is placed in the header the page(s)
</style><script data-main='common/main' src='libraries/require.js'></script>
footer like this
<script>require(['../application1/application']);</script>
<script>require(['../application2/application']);</script>
This approach works perfect when using a bunch of files, and the applications run and interact perfect
However trying to make them into one seems a bit more of a challenge in terms of making it work.Granted I could just be an idiot
Build File
({
baseUrl: "../",
mainConfigFile: '../main.js',
optimize: 'uglify',
optimizeCss: 'standard',
out: "../global.min.js",
//insertRequire: ['main'],
include: ['../application1/application', '../application2/application'],
wrap: true // have tried both options - this makes the scenario at the bottom work
})
This works perfect and produces a lovely global.min.js. Challenge is it does not execute the callbacks on define calls I include it like so:
this is placed in the header the page(s)
</style><script data-main='common/main' src='libraries/require.js'></script>
footer like this
<script>require(['../common/global.min']);</script>
HOWEVER: if I keep the old requires in places like so:
<script>require(['../application1/application']);</script>
<script>require(['../application2/application']);</script>
it downloads 3 files
common/global.min.js
application1/application.js
application2/application.js
NOTE: At this point it is missing about 150 files, but the application(s) work perfect.
Having spent some serious time on this, my head is now properly wrecked and I can't figure out how to make it work from a single minified file.
Any help much appreciated as I have tried whatever I could think of. Happy to share all the files, howvere there is a lot of them ;-)
This is an educated guess, based on what you've shown in the question and experience with RequireJS' failure modes. I'm guessing "./common/global.min" is not a module name. (If you want to check this, open your optimized bundle and look at all the define calls. If you find that none of them has "./common/global.min", then it is not a module name.)
When you require "./common/global.min", RequireJS loads the corresponding file, and then looks in it for a module named "./common/global.min". It finds none, and your code does not get to run.
One way to fix this is to use a RequireJS configuration with your optimized bundle that maps names like this:
paths: {
'../application1/application': './common/global.min'
'../application2/application': './common/global.min'
}
And call require with these module names instead of "./common/global.min". This configuration tells RequireJS "when you are looking for these modules, look in that file: they are there" and indeed that's what the optimization process does.

Best way to import JavaScript files into one file?

I have a background in coding in languages that have a concept of "classes". Now that I am coding JavaScript, I would like to code in a similar way so that each object oriented "class" I create is its own separate file.
see Accessing "Public" methods from "Private" methods in javascript class
see http://phrogz.net/JS/classes/OOPinJS.html
In other languages, I would create import statements at the top of the class file to ensure other custom classes that were used within a class file so that the other custom classes were compiled into the final binary.
Of course JavaScript is not a compiled language; however, I would still like to be able to be include some kind of "import" statement at the top of custom class files so I could ensure the imported JS "class" file was available for the user's browser to download.
It would be ideal if there were a 3rd party tool that combined all of my separate class files into one JS file so the browser only had to make one HTTP request for a single JS file instead of many calls for each indicidual JS "class". Does anyone know if such a tool exists where it would do the following:
allowed me to choose which JS files that I wanted to include in a single JS file
crawled thru the files I selected in step 1 and found all the "import" statements at the top of each custom "class" file. These "import" statements could simply be specially formatted comments in the code that the 3rd party recognizes as import statements.
The 3rd party would then create the single JS file with all of the files that were selected from step 1 and from all of the imported files that were found in step 2.
Some popular JavaScript frameworks seem to do just that. For example, jQueryUI allows you to customize the download of a single jQueryUI source file by allowing the user to check off which objects you want to use. If you uncheck an element that is needed for an item that you checked off, then the form tells you that there is a dependency you need to rectify before being able to proceed to download the file.
see http://jqueryui.com/download/
So is there a 3rd party tool that allows a developer to use some kind of "import" statement comment to ensure that many dependent JS files (and only the ones that the developer needs) to be combined into a single JS file?
RequireJS was built for exactly this purpose.
Have a look at Require.js. It lets you import various javascript files in a modularized fashion and add the required dependencies between them. Also at the end you can minify them all into one single JS file using r.js
A trivial batch file can do this for you:
#for %i in (classes/*.js) type %i >> build.js
This works best if your JS source files are all in one folder, and this example assumes that folder is named classes. It gets a bit more complicated if you have subfolders, but a similar principle can be applied.
Have a look at GruntJS, JQuery uses it for building. If you don't care for HTTP requests, you can use already mentioned RequireJS, which also has nice async methods to load files, which can improve perfomance in some situations.
Check out this class https://www.youtube.com/watch?v=KnQfGXrRoPM
This allows for importing on the fly within classes. also it allows
for importing all classes within an folder and all of its sub folders.
and its really simple because it is just a prototype function added to String.
just by adding the importer class you will call in classes like "com.project.Classfile.js".import();
or "com.project.*".import() to get all sub-classes.
fork on - https://github.com/jleelove/Utils

How do I put multiple files into a single namespace/module? (javascript)

I've been reading about the module pattern, but everything I read assumes that the entire contents of the module will be in a single file. I want to have one file per class.
I've resorted to doing this at the top of every file:
if(window.ModuleName === undefined) { window.ModuleName = {}; }
ModuleName.ClassName = function () { ... }
But this allows files to be included without their dependencies, which is also annoying. For example, lets say there is ClassA which uses ClassB, and "ClassB.js" is left out of the HTML, then ClassA will throw up errors. As far as I'm aware Javascript lacks an import statement, so in this case I actually want everything to be in a single file.
I assume that large javascript projects are broken up into multiple files, so there has to be a way around this. How is it generally done? Is there some tool that will combine multiple class files into a single module file?
This is a big topic but let me explain as much as I can. Javascript requires that you have preloaded anything you intended to use, which is why your module pattern has all the "things" in the same file. But if you plan to separate them in different files then you have to manage it before using. I suggest the following approaches
Concatenate them before serving them in the server. For example in jsp, you can create a servlet that returns contenttype = "text/javascript", inside that servlet you can append all the scripts you need in one dynamically generated script then return it to the client.
In your ant or maven builds etc, there are configurations where in you can concatenate them the files you want together. This is a common practice therefore you should find many reference in the internet.
Lazy-load javascripts. This is my preferred way. I use Lazyload javascript library. Basically I declare the dependencies of certain codes much like "import" in Java, then before i call any of them i load their dependencies. This allows for optimized dependency loading without scripts redundancies. The problem is you need to write some fairly complicated scripts to do this.
Hope to help.

Javascript object dependencies

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.

Categories