es5 modular design pattern to es6 - javascript

I have a website with 100k users/day. Currently we are writing code in Jquery/Vanilla JS using the modular design pattern. A simple js to hide/show loader is as below
"use strict";
var loaderHandler = (function(){
var loader = document.getElementById('main_loader');
return{
showProcessLoader : function(){
loader.style.display = 'block';
loader.style.opacity = '0.5';
},
hideLoader : function(){
loader.style.display = 'none';
}
}
})();
docReady(function() {
loaderHandler.hideLoader();
});
Whenever I want to show loader at some place I just call loaderHandler.showProcessLoader(); and loaderHandler.hideLoader(); to hide it. Similarly, I have other JS files which are written using the same design pattern and I create a single minified JS using a gulp task from all the js that is required on that page. Currently, everything works fine and I am able to call one js file function inside the other without any problem.
I have decided to move my application to the latest es6 now I have the following issues/queries
What is the design pattern in es6 which will be equivalent to my modular design pattern?
I don't intend to rewrite my existing js files but write only new js in es6. So I want the new design pattern shouldn't interfere with the existing architecture and still provide me support to write new js files in es6.
Also, I still should be easily able to call one js file function in other when a single minified file for a page is created.
Edit - I am already using babel to transpile my es6 code to es5 equivalent

1) What is the design pattern in es6 which will be equivalent to my modular design pattern?
Design patterns aren't necessarily built into a language, they're just techniques that a language may or may not provide enough abstraction ability to accomplish. As it seems like you know based on question 2, any design pattern you could do before you can also do in ES6 and even vice versa. In fact, transpilers like babel take code writtin in es6 and convert it like magic to previous versions.
But what it really seems like is that you're eager to use some of the newest features available in ES6 and based on your code above it seems like you need some type of private variable and method encapsulation, which means classes are probably perfect for you.
Converting it is pretty simple, but the only thing you have to keep in mind is that you need to export a new instance of your class as compared to using an IIFE. With a class you'll also gain the ability to make multiple instances of your class if you want to or even do some inheritance, but with your current example there might not be a good use case for those features.
In the example below the id of the element is passed into the constructor, meaning you can re-use this class for any number of elements if you choose to or simply export a singleton instance.
class AbstractLoaderHandler{
constructor(el_id){
this.loader = document.getElementById(el_id)
}
showProcessLoader(){
this.loader.style.display = 'block';
this.loader.style.opacity = '0.5';
}
hideLoader(){
this.loader.style.display = 'none';
}
}
let loaderHandler = new AbstractLoaderHandler('main_loader');
loaderHandler.hideLoader();
<div id="main_loader">Hello World</div>
<button onClick="loaderHandler.showProcessLoader()">Show</button>
<button onclick="loaderHandler.hideLoader()">Hide</button>
3) Also, I still should be easily able to call one js file function in other when a single minified file for a page is created.
Keep in mind that this has to do entirely with the way in which you're bundling your files. All you really need to do to insure this is to keep whatever you create exposed as a global variable.

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.

Javascript and jQuery file structure

I have created a sizable application javascript and jQuery. However my file structure is getting a bit messy!
At the moment I have one large JS file with a if ($('#myDiv').length > 0) { test at the top to only execute the code on the correct page, is this good practice?
There is also a mixture of plain JS functions and jQuery extensions in the same file e.g $.fn.myFunction = function(e) {.
I also have a few bits of code that look like this:
function Product() {
this.sku = '';
this.name = '';
this.price = '';
}
var myProduct = new Product;
Basket = new Object;
My question is for pointers on good practice regarding javascript and jQuery projects.
The code if ($('#myDiv').length > 0) { is not good practice. Instead, make your page specific JS as functions and execute them in the corresponding page . Like this:
var T01 = function(){
// JS specific to Template 01
};
var T02 = function(){
// JS specific to Template 02
};
HTML head of Template 01:
<script type="text/javascript"> $(T01); </script>
Consistency is the golden rule.
You can discuss design patterns back and forth, but if you want to have easily maintainable code where new people can come in and get an overview fairly quickly, the most important part, whatever design patterns you chose, is to have a consistent code base.
It is also the hardest thing to do - keeping your codebase clean and consistent is probably the hardest thing you can do as a programmer, and especially as a team.
Of course the first tip I can give you is to separate the jQuery extensions in their own source files. You can always serve everything together with a minification tool, so you should not worry about performance.
About the code youo mention, it could be simplified to
var Product = {
sku: '',
name: '',
price: ''
}
var myProduct = objectCopy(Product);
var Basket = {};
provided you write a simple objectCopy function which loops through the object own properties and just copies them to a new object (you can make a shallow or a deep copy, according to your needs).
Finally, if you think your code is starting to get messy, you may want to learn some patterns to organize JS code, like the module pattern. Alternatively, if you are familiar with doing this on the backend, you may want to organize your application following the MVC pattern. personal advertisement - I have written myself a tiny library which helps organize your code in this fashion. There are also many other libraries for the same task, often adding other functionality as well.
If you follow the MVC pattern, your page will actually correspond to some action in some controller, and you could just start it with a call like
<script>someController.someAction()</script>
in the head of your document, hence removing the need for the manual check for #myDiv. If you use my library MCV, it will be enough to declare your body like
<body class="mcv:controller/action">
and start the application with
$(document).ready(function() {
mcv.autostart();
});
Yes it's good practice to put as much of your code into a seperate JS file as this could then be compressed before transmission and hence speed up download time. However no you should not have code that looks like
if ($('#myDiv').length > 0) {
on every page. Split your JS code up into manageable functions and call those as-and-when you need to.
I don't see a problem with mixing JS and jQuery functions up in the same file.

How to use javascript namespaces correctly in a View / PartialView

i've been playing with MVC for a while now, but since the project i'm on is starting to get wind in its sails more and more people are added to it. Since i'm in charge of hacking around to find out some "best practice", i'm especially wary about the possible misuses of javascript and would like to find out what would be the best way to have our views and partial views play nicely with javascript.
For the moment, we're having code that looks like this (only simplified for example's sake)
<script type="text/javascript">
function DisableInputsForSubmit() {
if ($('#IsDisabled').is(':checked')) {
$('#Parameters :input').attr('disabled', true);
} else {
$('#Parameters :input').removeAttr('disabled');
}
}
</script>
<%=Html.SubmitButton("submit", Html.ResourceText("submit"), New With {.class = "button", .onclick = "DisableInputsForSubmit(); if ($('#EditParameters').validate().form()) {SetContentArea(GetHtmlDisplay('SaveParameters', 'Area', 'Controller'), $('#Parameters').serialize());} return false;"})%><%=Html.ResourceIcon("Save")%>
Here, we're saving a form and posting it to the server, but we disable inputs we don't want to validate if a checkbox is checked.
a bit of context
Please ignore the Html.Resource* bits, it's the resource management
helpers
The SetContentArea method wraps ajax calls, and GetHtmlDisplay
resolves url regarding an area,
controller and action
We've got combres installed that takes care of compressing, minifying
and serving third-parties libraries and what i've clearly identified as reusable javascript
My problem is that if somebody else defines a function DisableInputsForSubmit at another level (let's say the master page, or in another javascript file), problems may arise.
Lots of videos on the web (Resig on the design of jQuery, or Douglas Crockford for his talk at Google about the good parts of javascript) talk about using the namespaces in your libraries/frameworks.
So far so good, but in this case, it looks a bit overkill. What is the recommended way to go? Should i:
Create a whole framework inside a namespace, and reference it globally in the application? Looks like a lot of work for something so tiny as this method
Create a skeleton framework, and use local javascript in my views/partials, eventually promoting parts of the inline javascript to framework status, depending on the usage we have? In this case, how can i cleanly isolate the inline javascript from other views/partials?
Don't worry and rely on UI testing to catch the problem if it ever happens?
As a matter of fact, i think that even the JS code i've written that is in a separate file will benefit from your answers :)
As a matter of safety/best practice, you should always use the module pattern. If you also use event handlers rather than shoving javascript into the onclick attribute, you don't have to worry about naming conflicts and your js is easier to read:
<script type="text/javascript">
(function() {
// your button selector may be different
$("input[type='submit'].button").click(function(ev) {
DisableInputsForSubmit();
if ($('#EditParameters').validate().form()) {
SetContentArea(GetHtmlDisplay('SaveParameters', 'Area','Controller'), $('#Parameters').serialize());
}
ev.preventDefault();
});
function DisableInputsForSubmit() {
if ($('#IsDisabled').is(':checked')) {
$('#Parameters :input').attr('disabled', true);
} else {
$('#Parameters :input').removeAttr('disabled');
}
}
})();
</script>
This is trivially easy to extract into an external file if you decide to.
Edit in response to comment:
To make a function re-usable, I would just use a namespace, yes. Something like this:
(function() {
MyNS = MyNS || {};
MyNS.DisableInputsForSubmit = function() {
//yada yada
}
})();

How can I easily maintain a cross-file JavaScript Library Development Environment

I have been developing a new JavaScript application which is rapidly growing in size.
My entire JavaScript Application has been encapsulated inside a single function, in a single file, in a way like this:
(function(){
var uniqueApplication = window.uniqueApplication = function(opts){
if (opts.featureOne)
{
this.featureOne = new featureOne(opts.featureOne);
}
if (opts.featureTwo)
{
this.featureTwo = new featureTwo(opts.featureTwo);
}
if (opts.featureThree)
{
this.featureThree = new featureThree(opts.featureThree);
}
};
var featureOne = function(options)
{
this.options = options;
};
featureOne.prototype.myFeatureBehavior = function()
{
//Lots of Behaviors
};
var featureTwo = function(options)
{
this.options = options;
};
featureTwo.prototype.myFeatureBehavior = function()
{
//Lots of Behaviors
};
var featureThree = function(options)
{
this.options = options;
};
featureThree.prototype.myFeatureBehavior = function()
{
//Lots of Behaviors
};
})();
In the same file after the anonymous function and execution I do something like this:
(function(){
var instanceOfApplication = new uniqueApplication({
featureOne:"dataSource",
featureTwo:"drawingCanvas",
featureThree:3540
});
})();
Before uploading this software online I pass my JavaScript file, and all it's dependencies, into Google Closure Compiler, using just the default Compression, and then I have one nice JavaScript file ready to go online for production.
This technique has worked marvelously for me - as it has created only one global footprint in the DOM and has given me a very flexible framework to grow each additional feature of the application. However - I am reaching the point where I'd really rather not keep this entire application inside one JavaScript file.
I'd like to move from having one large uniqueApplication.js file during development to having a separate file for each feature in the application, featureOne.js - featureTwo.js - featureThree.js
Once I have completed offline development testing, I would then like to use something, perhaps Google Closure Compiler, to combine all of these files together - however I want these files to all be compiled inside of that scope, as they are when I have them inside one file - and I would like for them to remain in the same scope during offline testing too.
I see that Google Closure Compiler supports an argument for passing in modules but I haven't really been able to find a whole lot of information on doing something like this.
Anybody have any idea how this could be accomplished - or any suggestions on a development practice for writing a single JavaScript Library across multiple files that still only leaves one footprint on the DOM?
The jQuery github has a similar setup to the one you speak of. There is even a Makefile / ant build.xml that use the google closure complier.
The basic concept is to develop all your stuff in separate files, then use cat (or something similar) to put all the files together.
cat intro.js core.js featureOne.js featureTwo.js featureThree.js outro.js > build/script.js
The code inside intro.js and outro.js from jQuery:
// intro.js
(function(window, undefined) {
// outro.js
})(window);
Take a look at how this library is built
http://github.com/oyvindkinsey/easyXDM
The files are separated, but merged together, placed into a closure, and run through jslint by the ant script (build.xml).
The ant script also does conditional 'compilation', string replacements and minification.
I recommend that you split your code base into AMD/RequireJS-style modules.
The AMD format seems to meet most of your requirements, and is rapidly becoming a de facto standard.

Advice for order in big javascript file

I started creating a javascript file in Sublime Text with a few lines and a few functions, but over days passed the file was growing and growing and now it has around 600 lines with about 40 functions.
So I keep scrolling up and down for writing or reading code. And I think that that it's not a good workflow. How can i be more organized with javascript code. Is there a technique that professionals use for that, or a tool?
600 lines is not so much, yet. What you can do is namespace your code (separate it according to functionality). For example:
Lets say you have a js file with a bunch of functions
function formatDate(date){ ... }
function calcAge(birthdate){ ... }
function removeAccents(string){ ... }
function resizeImage(img){ ... }
... and many more ...
You can go ahead and separate functions by category, in this case we could group all the functions that deal with dates. All the ones that deal with strings and the ones that handle images.
// we create a global namespace, on main.js
var MyCoolProject = {};
// then we include string.js, and put all the string functions here
MyCoolProject.string = {
removeAccents: function(string){ ... }
};
// on date.js, we put all date functions
MyCoolProject.date = {
formatDate: function(date){ ... },
calcAge: function(birthdate){ ... }
};
// so on with image.js
MyCoolProject.img = {
resizeImage: function(date){ ... }
};
This way you have several smaller files that handle a specific kind of logic and you would call your functions like this:
function doSomethingAwesome(str){
var awesomeString = MyCoolProject.string.awesomize(str);
alert(awesomeString);
}
You also benefit by having more maintainable code and avoid collisions. Collisions happen when you include another script that happens to have a function with the same name as yours. If this happens, only the last included function will be executed. By namespacing your code you prevent this.
Keep in mind
You will have more files, this means more <script> tags in your html in which sometimes the order matters! You should eventually use build tools like grunt or gulp to concatenate and minimize all the js into one single scripts.js file. This way you have full control over your code during development. But once in production your site will make only one request for a js file which should make your site load faster.
Also, the namespacing method used here is my personal preference but in js you can achieve the same behavior through other patterns like prototypes, closures, commonjs, etc so you could research these and see which one fits your personal preference. There is not one better than the other, just one that will serve as a tool to make you build it faster and better.

Categories

Resources