How to make a requirejs module with multiple files - javascript

I was wondering how to make a requirejs module with multiple files.
e.x. I require one file which then somehow gets multiple files.
I know I could do this:
define([all the other files], function () {
var mod = {},
files = [all the other files];
arguments.forEach(function (i) {
mod.[files[i]] = i;
});
return mod;
});
but I was wondering whether there was a better method?

You want a dynamic list of files(.txt,.tpl,.htm,.json), to avoid a change in JS source code to add more files.
I don't know if is there a way to do that, but you must take care about the time that will take to download all this files. I suggest you to create a json file with all files that you want to download, and iterate through this array of files using ajax to get them.
If you are try to get all module inside a directory, you need to create a js file: <package-all>.js that encapsulate an require([all files],function()); for example.
I believe that this is the only way to solve this.

first, write the modules like this,
define(function(){
return {
'mod-a' : require('modules/mod-a'),
'mod-b' : require('modules/mod-b'),
'mod-c' : require('modules/mod-c')
}
})
then use r.js to optimize the above js to blow one (r.js will combine all module file to one), or, you can write like this directly :
define('modules/mod-a', [], function(){});
define('modules/mod-b', [], function(){});
define('modules/mod-c', [], function(){});
define('mod-all', ['modules/mod-a','modules/mod-b','modules/mod-c'], function(){
return {
'mod-a' : require('modules/mod-a'),
'mod-b' : require('modules/mod-b'),
'mod-c' : require('modules/mod-c')
}
})
now, the modules 'mod-all' is the thing you wanted.

Related

load all templates at once

The following code loads templates.
tpl = {
// Hash of preloaded templates for the app
templates: {},
// Recursively pre-load all the templates for the app.
// This implementation should be changed in a production environment. All the template files should be
// concatenated in a single file.
loadTemplates: function(names, callback) {
var that = this;
var loadTemplate = function(index) {
var name = names[index];
console.log('Loading template: ' + name);
$.get('tpl/' + name + '.html', function(data) {
that.templates[name] = data;
index++;
if (index < names.length) {
loadTemplate(index);
} else {
callback();
}
});
}
loadTemplate(0);
},
// Get template by name from hash of preloaded templates
get: function(name) {
return this.templates[name];
}
};
and u can load templates like
tpl.loadTemplates(['header', 'wine-details', 'wine-list-item'], function() {
});
But here the templates are defined in seperate html file.
Is it possible all my templates are defined in one html file and i load them all together.
Do i need to write some kind of parser. The reason is for my home page i have 40 templates and I dont want to create 40 Html template pages instead it would be i can keep them in one single html page and than load them all together.
Is this possible?
Yes you don't need to be doing it like this.
Check this: https://github.com/requirejs/text
define([
'some/module',
'text!some/module.html',
'text!some/module.css'
], function (SomeModule, HtmlFile, CssFile) {
'use strict';
// ....
}
This can load text resources. When you are ready to deploy your app you can compile all your js files and templates into a single minified file using r.js. You can do this via command line, or as a grunt or gulp task.
There are many template libraries which you can find requirejs plugins for (often extended off that text plugin ^^). For example this one for Handlebars https://github.com/jfparadis/requirejs-handlebars or this one for underscore https://github.com/jfparadis/requirejs-tpl. Just google search "requirejs «template engine name»".
If you want to have multiple templates in one html file you need a way to separate them. The nicest way to do this is using the new template tag.
You can, define templates single file, under different container with Ids. load single html the way you are loading here, create a jquery node with template html, run through children read id attribute and save html of each child saved as that.templates[id_you_read] = child.html();
But this is not the right way of doing stuff. use requirejs with text plugin as in the prev answer.

Gulp.js get filename from .src()

I'm trying to use gulp-proceesshtml (https://github.com/julien/gulp-processhtml) to remove some unwanted code in my build version, the problem is that the task requires a filename to be given.
gulp.src('test.html').pipe(processhtml('test.html'));
But I can't figure out how this would work when I'm processing all HTML files in a folder
gulp.src('*.html).pipe(processhtml('filename here'));
Personally, it sounds like that's the wrong plugin for what you are trying to accomplish. See below.
However, because it's not clear what you are using it for, you can be able to use node-glob to process each file one-by-one:
var glob = require('glob')
// you also need event-stream for merging the streams
es = require('event-stream');
gulp.task('myTask', function() {
var files = glob.sync('*.html'),
streams;
streams = files.map(function(file) {
// add the *base* option if your files are stored in
// multiple subdirectories
return gulp.src(file, {base: 'relative/base/path'})
// may need require('path').filename(file)
.pipe(processhtml(file));
});
return es.merge.apply(es, streams);
});
This will create a single asynchronous stream out of every file that matches your initial pattern.
For simply removing some text from your files, you can use gulp-replace, like so:
var replace = require('gulp-replace');
gulp.src('*.html')
// replaces all text between
// <!-- remove-this --> and <!-- /remove-this -->
.pipe(replace(/<!--\s*remove-this\s*-->[\s\S]*?<!--\s*\/remove-this\s*-->/g, ''));
I know this question is old, but for a shorter solution you can use gulp-tap, something like this:
.pipe(tap(function(file, t) {
console.log(file.path);
}))
if you need to use the filename in other step of the pipe you can store it in a variable and use it for next step.

Concatenating JavaScript files using Ant

I have about 50-60 js files and there are dependencies among them so I need to maintain an order while cocatenating. Writing all the names in "files" attribute would make the build.xml messy and any addition of js files in future would need to added accordingly. So, I wanted to write the order in a separate txt file and just copy the contents using Ant following that order. Is it possible ?
You can do what you want using a resourcelist, for example:
<concat destfile="concatenated.js">
<resourcelist>
<file file="js.files.txt"/>
<filterchain>
<striplinecomments>
<comment value="#"/>
</striplinecomments>
</filterchain>
</resourcelist>
</concat>
The filterchain isn't required, but is useful as you can then include comment lines in your list-of-files.
You can use order independent declarations like these:
// in every file
if(!("myLib" in window))myLib = {};
if(!("canvas" in myLib))myLib.canvas = { .... };
//next file
if(!("myLib" in window))myLib = {};
myLib = $.extend(myLib, true, {
init: function(){},
move: function(){}
});
//in index
myLib.init();

How can I combine my JavaScript files and still have my callbacks wait for a ready state?

I have lots of functions and event handlers that are split across multiple javascript files which are included on different pages throughout my site.
For performance reasons I want to combine all of those files into 1 file that is global across the site.
The problem is I will have event handlers called on elements that won't necessarily exist and same function names.
This is an example of a typical javascript file...
$(document).ready(function(){
$('#blah').keypress(function(e){
if (e.which == 13) {
checkMap();
return false;
}
});
});
function checkMap() {
// code
}
function loadMap() {
// code
}
I would need to seperate this code into an object that is called on that specific page.
My thoughts are I could re-write it like this:
(function($) {
$.homepage = {
checkMap: function(){
// code
},
loadMap: function(){
//code
}
};
})(jQuery);
And then on the page that requires it I could call $.homepage.checkMap() etc.
But then how would I declare event handlers like document.ready without containing it in it's own function?
First of all: Depending on how much code you have, you should consider, if serving all your code in one file is really a good idea. It's okay to save http-requests, but if you load a huge chunk of code, from which you use 5% on a single page, you might be better of by keeping those js files separated (especially in mobile environments!).
Remember, you can let the browser cache those files. Depending on how frequent your code changes, and how much of the source changes, you might want to separate your code into stable core-functionality and additional .js packages for special purposes. This way you might be better off traffic- and maintainance-wise.
Encapsulating your functions into different objects is a good idea to prevent unnecessary function-hoisting and global namespace pollution.
Finally you can prevent calling needless event handlers by either:
Introducing some kind of pagetype which helps you decide calling only the necessary functions.
or
checking for the existence of certain elements like this if( $("specialelement").length > 0 ){ callhandlers}
to speed up your JS, you could use the Google Closure Compiler. It minifies and optimizes your code.
I think that all you need is a namespace for you application. A namespace is a simple JSON object that could look like this:
var myApp = {
homepage : {
showHeader : function(){},
hideHeader : function(){},
animationDelay : 3400,
start : function(){} // the function that start the entire homepage logic
},
about : {
....
}
}
You can split it in more files:
MyApp will contain the myApp = { } object, maybe with some useful utilities like object.create or what have you.
Homepage.js will contain myApp.homepage = { ... } with all the methods of your homepage page.
The list goes on and on with the rest of the pages.
Think of it as packages. You don't need to use $ as the main object.
<script src="myapp.js"></script>
<script src="homepage.js"></script>
<-....->
<script>
myApp.homepage.start();
</script>
Would be the way I would use the homepage object.
When compressing with YUI, you should have:
<script src="scripts.min.js"></script>
<script>
myApp.homepage.start();
</script>
Just to make sure I've understood you correctly, you have one js file with all your code, but you want to still be in control of what is executed on a certain page?
If that is the case, then the Terrific JS framework could interest you. It allows you to apply javascript functionality to a module. A module is a component on your webpage, like the navigation, header, a currency converter. Terrific JS scans the dom and executes the js for the modules it finds so you don't have to worry about execution. Terrific JS requires OOCSS naming conventions to identify modules. It's no quick solution to your problem but it will help if you're willing to take the time. Here are some more links you may find useful:
Hello World Example:
http://jsfiddle.net/brunschgi/uzjSM/
Blogpost on using:
http://thomas.junghans.co.za/blog/2011/10/14/using-terrificjs-in-your-website/
I would use something like YUI compressor to merge all files into one min.js file that is minified. If you are looking for performance both merging and minifiying is the way to go. http://developer.yahoo.com/yui/compressor/
Example:
Javascript input files: jquery.js, ads.js support.js
run yui with jquery.js, ads.js, support.js output it into min.js
Javascript output files: min.js
then use min.js in your html code.

How to organize javascript file into smaller pieces?

I currently have one large external javascript file that is used on the page. I currently wrap the code in a self-invoking function because I have other sections that are loaded using ajax tabs, so I want to avoid naming clashes with those other external js files.
The code in the file is organized like below. I would like to split some of the code inside the plannerTab namespace into smaller files, yet still have it be part of that namespace.
How could I do this? Or, do you guys recommend a different approach? Thanks!
// Document Ready
$(function ()
{
// initializes table
plannerTab.plannerTable.init();
});
var plannerTab = (function ()
{
// All the code for the page is in here. I would like to extract sections
// from in here and put them into their own external files while still keeping
// the namespacing
}();
Update
How could I separate parts from within the plannerTab variable into smaller external js files, and still maintain that they are part of the plannerTab namespace? A small example below.
// Scope: plannerTab.config - Would like to store configuartion into a separate file
var config = {
selectors: {
tableId: '#plannerTable',
addTaskId: '#AddTask',
editTaskSelector: '#plannerTable .edit',
dateFilterSelector: '#plannerTable_TimeFilter li',
deleteTaskClass: '.delete',
searchFilter: '#plannerTable_filter',
selectedDateFilter: 'selected-dateFilter',
taskCellSelector: '#plannerTable .task-col',
taskClass: '.taskId'
},
urls: {
addTaskFormURL: '/Planner/Planner/LoadAddTaskForm',
editTaskFormURL: '/Planner/Planner/LoadEditTaskForm',
deleteTaskURL: '/Planner/Planner/DeleteTask',
getTasksByDateRangeURL: '/Planner/Planner/GetTasksByDateRange',
viewTaskURL: '/Planner/Planner/ViewTask'
}
};
Look at this example (from google)
<script type="text/javascript">
function importScript(url){
var tag = document.createElement("script");
tag.type="text/javascript";
tag.src = url;
document.body.appendChild(tag);
}
window.onload = function(){
// imports go here
importScript("foo.js"); // example
};
</script>
I'm assuming that plannerTab becomes an object return result of the self executing function. If you need to add properties or methods to that object dynamically, you can take a look at jQuery.extend() http://api.jquery.com/jQuery.extend/
You would need to modify the external JS to use the jQuery extend method to add onto existing properties and methods of plannerTab. As long as you keep plannerTab a global variable, you will continue adding to it as you import more external js files.
If you are using the module pattern to maintain private variables in plannerTab, be sure to test how those values behave once you use jQuery.extend().

Categories

Resources