Concatenating JavaScript files using Ant - javascript

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();

Related

Javascript code organization data driven application

I'm currently working on the front-end of a medium/large-scale data-driven Asp.net MVC application and I have some doubts about the right code-organization/design pattern to follow.
The web application is made by multiple pages containing many Kendo UI MVC widgets defined with Razor template.
For those who are unfamiliar with Kendo, the razor syntax is translated to Javascript as the following snippet:
I defined inside my Script folder two main folders, and I structured my js files as follow:
shared //Contains the shared js files
-file1.js
-file2.js
pages //One file per page
page1.js
page2.js
...
Ticket.js // page 4 :)
Each js file is a separate module defined with the following pattern:
Note: Inside init function is registered every callback function to the window events and occasionally a $(document).ready(function(){}) block.
;(function () {
"use strict";
function Ticket(settings) {
this.currentPageUrls = settings.currentPageUrls;
this.currentPageMessages = settings.currentPageMessages;
this.currentPageEnums = settings.currentPageEnums;
this.currentPageParameters = settings.currentPageParameters;
this.gridManager = new window.gridManager(); //usage of shared modules
this.init();
}
Ticket.prototype.init = function () {
$("form").on("submit", function () {
$(".window-content-sandbox").addClass("k-loading");
});
...
}
Ticket.prototype.onRequestStart = function (e) {
...
}
//private functions definition
function private(a, b, c){
}
window.Ticket = Ticket;
}());
Once I need my Javascript functions defined in a module I include the associated Javascript file in the page.
An istance of my object is stored inside a variable and, on top of that, a function is bound to the widget event (see: onRequestStart).
HTML/JAVASCRIPT
#(Html.Kendo().DropDownList()
.Name("Users")
.DataValueField("Id")
.DataTextField("Username")
.DataSource(d => d.Read(r => r.Action("UsersAsJson", "User"))
.Events(e => e.RequestStart("onRequestStart"))))
var settings = {};
var ticket = new window.Ticket(settings);
function onRequestStart(e){
ticket.onRequestStart(e);
}
I feel like my design pattern might be unfriendly to other front-end delevoper as I am, mostly because I choose not to implement the Javascript modules within Jquery plugin.
First, Am I doing everything the wrong way?
Second, is my design pattern suitable for a Javascript test-framework?
Third, which are the must-have scenarios for Jquery plugins?
Update
Added the Javascript output by the above Razor syntax.
Folder structure
In terms of functionality (shared) and modules (modular approach), the development or application code should represent what you can encounter in HTML. A simple ctrl+f over your solution should yield all possible changes. From that experience over the years I personally prefer dividing it in:
app (application code)
classes (reusable)
modules (singleton)
lib (package manager/grunt/gulp/...)
jquery (proper library names/unminified dist file or root file)
kendo
File names
Representing what something does and to be able to reuse it in a blink of an eye is what will cut your development time. Choosing proper names has value as I'm sure you are aware. My file names always starts with the namespace usually in short followed by a reusable "search" term:
app/prototypes
ns.calendar.js (multiple configs)
ns.maps.js (combinations or single uses)
ns.places.js (forms or map add-ons)
ns.validation.js (multiple forms and general handling)
app/singletons
ns.cookiebox.js (single config)
ns.socialmedia.js (single config)
ns.dom.js (provides a place for dom corrections, global resize events, small widgets, ...)
To add, what you called shared, is functionality that's meant to be global. A great example would be to use underscore library. Or create a collection of functions (device detection, throttle, helpers in general) on your own to reuse throughout projects => ns.fn.js
Since you add them only once throughout your namespace, it's also built as singleton and can be added to the modules folder or directly in the app root.
As last addition a loader file to kickstart your point of control => ns.load.js in the app root. This file holds the single DOM ready event to bind protoypes and modules.
So you might want to rethink your idea of dividing into pages. Trust me, I've been there. At some point you'll notice how functionality grows too large in order to configure all pages separately and therefor repeatedly.
File structure
To be honest I like Tip 1 of #TxRegex answer the most, with a small addition to bind the namespace and pass it from file to file as it get's loaded.
Core principle: IIFE bound to window object
window.NameSpace = (function($, ns){
'strict'
function private(){}
var x;
ns.SearchTerm = {};
return ns;
}(window.jQuery, window.NameSpace || {}));
For more example code I'd like to point out my github account.
Bundling
Try to achieve a single bundled and minified file from lib to app, loaded in the head on async for production releases. Use separated and unminified script files on defer for development and debug purposes. You must avoid inline script with global dependencies throughout the whole project if you do this.
path to js/lib/**/*.js (usually separated to keep sequential order)
path to js/app/ns.load.js
path to js/app/ns.fn.js
path to js/app/**/*.js (auto update the bundle)
Output => ns.bundle.js
=> ns.bundle.min.js
This way you'll avoid render blocking issues in JavaScript and speed up the loading process which in turn boosts SEO. Also enables you to combine functionality for mobile layouts and desktop layouts on the fly without memory issues or jerky behavior. Minifies really well and generates little overhead in calling instances from the loader file. As a single bundle will be cached throughout your pages it all depends on how many dependencies or libraries you can cut from the bundle. Ideally for medium and large projects where code can be shared and plugged in to different projects.
More info on this in another post.
Conclusion
First, Am I doing everything the wrong way?
Not at all, your modular approach seems ok...
It's missing a global namespace, which is hard to avoid without at least one. You create one for each module but it seems better to group them all under one namespace so you can differentiate library code from application code in the window object.
Kendo seems to create inline scripts? Can't you counter the placement server side?
Second, is my design pattern suitable for a Javascript test-framework?
Except for the Kendo instances, you can add a layer for testing purposes. Remember if jQuery is your dependency inline, you'll have to render block it's loading. Otherwise => jQuery is undefined
Exclude Kendo dependencies from the bundle if you can't control the inline script. Move to a </body> bundled solution.
Third, which are the must-have scenarios for Jquery plugins?
modular approach
configurable approach for multiple instances (tip: moving all strings from your logic, see how Kendo uses object literals)
package manager to separate the "junk" from the "gold"
grunt/gulp/... setup to separate scss and css from js
try to achieve a data-attribute binding, so once all is written, you configure new instances through HTML.
Write once, adapt easily where necessary and configure plenty!
The organization and pattern seems fine, but I have some tips:
Tip 1:
Instead of setting specific global variables within your module, perhaps you could return the object instead. So instead of doing this:
;(function () {
"use strict";
function Ticket(settings) {
console.log("ticket created", settings);
}
...
window.Ticket = Ticket;
}());
You would do this:
;window.Ticket = (function () {
"use strict";
function Ticket(settings) {
console.log("ticket created", settings);
}
...
return Ticket;
}());
The reason for this is to be able to take your module code and give it a different global variable name if needed. If there is a name conflict, you can rename it to MyTicket or whatever without actually changing the module's internal code.
Tip 2:
Forget Tip 1, global variables stink. Instead of creating a seperate global variable for each object type, why not create an object manager and use a single global variable to manage all your objects:
window.myCompany = (function () {
function ObjectManager(modules) {
this.modules = modules || {};
}
ObjectManager.prototype.getInstance = function(type, settings) {
if (!type || !this.modules.hasOwnProperty(type)) {
throw "Unrecognized object type:";
}
return new this.modules[type](settings);
};
ObjectManager.prototype.addObjectType = function(type, object) {
if (!type) {
throw "Type is required";
}
if(!object) {
throw "Object is required";
}
this.modules[type] = object;
};
return new ObjectManager();
}());
Now each of your modules can be managed with this single global object that has your company name attached to it.
;(function () {
"use strict";
function Ticket(settings) {
console.log("ticket created", settings);
}
...
window.myCompany.addObjectType("Ticket", Ticket);
}());
Now you can easily get an instance for every single object type like this:
var settings = {test: true};
var ticket = window.myCompany.getInstance("Ticket", settings);
And you only have one global variable to worry about.
You can try separating your files in different components asuming each component has a folder.
for example: page 1 is about rectangles so you make a folder call rectangle inside that folder you create 3 files rectangle.component.html, rectangle.component.css, rectangle.component.js (optional rectangle.spec.js for testing).
app
└───rectangle
rectangle.component.css
rectangle.component.html
rectangle.component.js
so if anything bad happends to a rectangle you know where is the problem
a good way to isolate variables and execute in the right place is to use a router basically what this does it check at the url and executes the portion of code you asign to that page
hope it helps let me know if you need more help.

vim NERDTreeIgnore for specific files in specific subdirectory

i am using https://github.com/MarcWeber/vim-addon-local-vimrc for setting project specific vim settings.
now i want to use NERDTreeVimIgnore to ignore javascript files only in the subdirectory src.
i tried that:
let NERDTreeIgnore = ['^src*\.js$']
but had no success.
let NERDTreeIgnore = ['\.js$']
ignores all js files but i need them ignored only in src and its recursive subdirectories.
can anyone give me a hint?
Unfortunately, it seems that the NERDTreeIgnore option only looks at the last path component (the basename of the file). This means that you won't be able to filter out particular files like that.
The only way I can think of doing this would be by using the NERDTreeAddPathFilter() function: https://github.com/scrooloose/nerdtree/blob/15445be5fb2559829ac7a1f05af5d713586e8ec9/doc/NERD_tree.txt#L1175
You could create a vim file in your nerdtree_plugin directory, for example ~/.vim/nerdtree_plugin/path_filters.vim. It would contain something like the example in the docs:
call NERDTreeAddPathFilter('MyFilter')
function! MyFilter(params)
" params is a dict containing keys: 'nerdtree' and 'path' which are
" g:NERDTree and g:NERDTreePath objects
" return 1 to ignore params['path'] or 0 otherwise
" You could do something like this, then:
let filename = fnamemodify(a:params.path.str(), ':p')
return filename =~ 'src/myproject/.*\.js'
endfunction
You may have to read up a bit in the documentation on writing functions and such, if you run into trouble.

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.

How to make a requirejs module with multiple files

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.

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