I want to tidy up the js-code used on my php-website to increase the loading speed. For the moment i include in every website the required js-file.
My plan is to merge all js-files into one big one. Not every page uses every js-code, so i started something but don't know if this makes any sense.
I have already read the article One JS File for Multiple Pages but the method of Paul Irish is way to complicated for me (for the moment) as a beginner.
This is my approach:
I create the file core.js and call it on every website like..
<script src="js/core.js"></script>
In core.js i first get the name of the corresponding page.
var path = window.location.pathname;
var page = path.split("/").pop();
var page_name = page.slice(0, -4);
Then i check which site requires which js-script (pseudo-code).
if (page_name == 'xyz'){
execute this code which is only used on this site
}
if (page_name == 'abc' || 'xyz' || 'def'){
execute another code which is used on multiple sites
}
if (page_name == 'ghi' || 'jkl' || 'mno' || 'xyz'){
include jquery for multiple sites
}
...
...
This means a lot of work for me, because i have a lot of js, so i wanted to ask first if this is a good solution to tidy up.
By the way: The js code i place on my website doesn't change often.
Thank you
Misch
A solution for your problem could be something like:
if(selector) {
//run code
}
This runs the code inside the block only if a particular selector exists. This way you don't have to go through all the trouble of getting the name of the page, splitting and slicing the string etc (this is also prone to errors).
So let's say you want to add some innerHTML on some node it will look something like this:
function bar (text) {
alert(text)
}
if(document.getElementById('#foo')) {
bar('#foo exists!')
}
This way bar is only called when a node with id #foo exists.
Split your javascript into sensible groups. You may have an admin section to your site, so have admin.js.
It's also worth noting that most browsers will only download the javascript file once and then cache it. You said that your code does not change very often so you may find that putting it all in one file doesn't actually have that much of an affect.
Lets say you have pages like page1, page2, page3 etc.
Then your core.js will include all the codes of all the pages and then just initialize the code which you want to use
var page1= (function () {
var Init = function (){
//write the codes used by page 1
};
return {
Initialize: function () {
Init();
}
};
})();
var page2= (function () {
var Init = function (){
//write the codes used by page 2
};
return {
Initialize: function () {
Init();
}
};
})();
var page3= (function () {......});
var page = path.split("/").pop();
var path = window.location.pathname;
var page = path.split("/").pop();
var page_name = page.slice(0, -4);
if (page_name == 'pg1'){
page1.Initialize();
}
if (page_name == 'pg2' || 'pg3'){
page2.Initialize();
page3.Initialize();
}
if (page_name == 'pg4' ){
page4.Initialize();
}
To be honest, this is just going to slow down your performance. If your users stay a long time on the website, then one single file reduces a bit of clutter in your code. But, if the user is visiting only a few pages, single file is just extra burden on bandwidth. There is a possibility, most of your users might not even need more than half of your js.
Plus, those extra conditions aren't really helping anyone. So, I would say, don't use single file option.
Related
I have a complex jQuery plugin to write, It does have a lot of html to show on screen and I am supposed to create them. Well, what is the best way to do the job. I can already hard code them for sure , but is there any other elegant method? is there a way to use some kind of templating?. definitely I don't want to have lot more dependency either.
You can put them in an external file(s) and load them when you need but this means plugin users will have to download all your files, instead of a single js file. Another option I used before (not for a plugin though) is to have an object inside your plugin which holds all the html you want. This makes it easier to write the plugin as the html doesn't clutter the plugin code. Also when you need to edit the html, it's in a single place. You can also put your templating code inside this object.
var pi = function() {
var self = this;
self.getNewDiv = function(){
return repo.getDiv();
}
//..... all your plug in code goes here and at the bottom
var htmlRepository = function() {
var divCode = "<div></div>";
this.getDiv = function(){
return divCode;
};
this.getSpan = function(){
return "Span Content";
}
this.getDivWithSpan = function(){
return getSpan().wrap(divCode); //etc
}
};
var repo = new htmlRepository();
}
now, this question has been asked and answered successfully many times, yet none of the things i try work.
I have tried head.js & require.js libraries
I have also tried
if (!window.unique_name) {
unique_name = true;
//code here..
}
none of which I can get to work (the global variable is always undefined)
the script I am trying to include runs something like this:
//clock.js
clockyTick = function() {
//my code here
}
setInterval(clockyTick, 1000);
the apps that call this script, standalone, work fine.
only when both apps are included on the same page (via calls to PHP require()) they break.
Here is the cause of the problems (I think):
I am building custom web apps on a (Joomla) site and have the requirement of displaying two of my apps on the same page.
Both apps need the same .js file to operate correctly, which works fine when they run standalone, but as soon as both apps are running on the same page (in the admin section) the scripts conflict and stop each other from working
(the script in question is a dynamic clock script that grabs the specialised contents of a div and modifies it to something else)
I think the reason I cannot get aforementioned libraries to work, is the fact that they also are being included twice on the admin page.
is there any way around this, or do I have to bite the bullet and integrate a library into the main Joomla template? (meaning the library is uselessly loaded on every single page, yet only used on 3 of hundreds)
jQuery is also required, separately, on each app..but thankfully I am able to use noConflict to avoid problems there (not ideal)
The joomla way would be to instantiate the document inside your module and unset only the conflicting script as described in this question here just before you load the module's script:
1) get an instance if the document object and remove the js files (you
could do that in a plugin) :
<?php
//get the array containing all the script declarations
$document = JFactory::getDocument();
$headData = $document->getHeadData();
$scripts = $headData['scripts'];
//remove your script, i.e. mootools
unset($scripts['/media/system/js/mootools-core.js']);
unset($scripts['/media/system/js/mootools-more.js']);
$headData['scripts'] = $scripts;
$document->setHeadData($headData);
?>
Or in your case, I think you could try the dirty solution below inside your js files:
//1st module script
var unique_name;
if (unique_name == false || unique_name == null) {
unique_name = true;
//code here..
alert("Included 1st script");
}else{
//do nothing
alert("Not included 1st script")
}
//2nd module script
var unique_name;
if (unique_name == false || unique_name == null) {
unique_name = true;
//code here..
alert("Included 2nd script");
}else{
//do nothing
alert("Not included 2nd script")
}
Here is a DEMO
If you are having conflicts with PHP require(), you can try require_once(). However, as mentioned, that’s not the Joomla way of doing things.
I have file called common.js and it's included in each page of my site using <script />.
It will grow fast as my sites functionality will grow (I hope; I imagine). :)
Lets example I have a jQuery event:
$('#that').click(function() {
one_of_many_functions($(this));
}
For the moment, I have that one_of_many_functions() in common.js.
Is it somehow possible that JavaScript automatically loads file one_of_many_functions.js when such function is called, but it doesn't exist? Like auto-loader. :)
The second option I see is to do something like:
$('#that').click(function() {
include('one_of_many_functions');
one_of_many_functions($(this));
}
That not so automatically, but still - includes wanted file.
Is any of this possible? Thanks in an advice! :)
It is not possible to directly auto-load external javascripts on demand. It is, however, possible to implement a dynamic inclusion mechanism similar to the second route you mentioned.
There are some challenges though. When you "include" a new external script, you aren't going to be able to immediately use the included functionality, you'll have to wait until the script loads. This means that you'll have to fragment your code somewhat, which means that you'll have to make some decisions about what should just be included in the core vs. what can be included on demand.
You'll need to set up a central object that keeps track of which assets are already loaded. Here's a quick mockup of that:
var assets = {
assets: {},
include: function (asset_name, callback) {
if (typeof callback != 'function')
callback = function () { return false; };
if (typeof this.assets[asset_name] != 'undefined' )
return callback();
var html_doc = document.getElementsByTagName('head')[0];
var st = document.createElement('script');
st.setAttribute('language', 'javascript');
st.setAttribute('type', 'text/javascript');
st.setAttribute('src', asset_name);
st.onload = function () { assets._script_loaded(asset_name, callback); };
html_doc.appendChild(st);
},
_script_loaded: function (asset_name, callback) {
this.assets[asset_name] = true;
callback();
}
};
assets.inlude('myfile.js', function () {
/* do stuff that depends on myfile.js */
});
Sure it's possible -- but this can become painful to manage. In order to implement something like this, you're going to have to maintain an index of functions and their corresponding source file. As your project grows, this can be troublesome for a few reasons -- the 2 that stick out in my mind are:
A) You have the added responsibility of maintaining your index object/lookup mechanism so that your scripts know where to look when the function you're calling cannot be found.
B) This is one more thing that can go wrong when debugging your growing project.
I'm sure that someone else will mention this by the time I'm finished writing this, but your time would probably be better spent figuring out how to combine all of your code into a single .js file. The benefits to doing so are well-documented.
I have created something close to that a year ago. In fact, I have found this thread by search if that is something new on the field. You can see what I have created here: https://github.com/thiagomata/CanvasBox/blob/master/src/main/New.js
My project are, almost 100% OOP. So, I used this fact to focus my solution. I create this "Class" with the name "New" what is used to, first load and after instance the objects.
Here a example of someone using it:
var objSquare = New.Square(); // Square is loaded and after that instance is created
objSquare.x = objBox.width / 2;
objSquare.y = objBox.height / 2;
var objSomeExample = New.Stuff("some parameters can be sent too");
In this version I am not using some json with all js file position. The mapping is hardcore as you can see here:
New.prototype.arrMap = {
CanvasBox: "" + window.MAIN_PATH + "CanvasBox",
CanvasBoxBehavior: "" + window.MAIN_PATH + "CanvasBoxBehavior",
CanvasBoxButton: "" + window.MAIN_PATH + "CanvasBoxButton",
// (...)
};
But make this more automatic, using gulp or grunt is something what I am thinking to do, and it is not that hard.
This solution was created to be used into the project. So, the code may need some changes to be able to be used into any project. But may be a start.
Hope this helps.
As I said before, this still is a working progress. But I have created a more independent module what use gulp to keep it updated.
All the magic que be found in this links:
https://github.com/thiagomata/CanvasBox/blob/master/src/coffee/main/Instance.coffee
https://github.com/thiagomata/CanvasBox/blob/master/src/node/scripts.js
https://github.com/thiagomata/CanvasBox/blob/master/gulpfile.js
A special look should be in this lines of the Instance.coffee
###
# Create an instance of the object passing the argument
###
instaceObject = (->
ClassElement = (args) ->
window[args["0"]].apply this, args["1"]
->
ClassElement:: = (window[arguments["0"]])::
objElement = new ClassElement(arguments)
return objElement
)()
This lines allows me to initialize a instance of some object after load its file. As is used in the create method:
create:()->
#load()
return instaceObject(#packageName, arguments)
I spent the better part of last month beating my head against the wall before I came up with an easy way to dynamically load, and chain together HTML canvas classes which are stored on the server, but, obviously, initialized on the client (harder than it sounds when the ordering is important in an asynchronous environment).
I was wondering if someone could help me find a way to load simple javascript scripts. Lets define a load('foo.js') function which instructs the client to load script foo.js from the server and execute it as javascript code.
Given the three files, stored on the server:
A.js
a = 10;
B.js
load('A.js');
b = a + 10;
C.js
load('B.js');
c = b + 10;
If the client issues the command load('C.js'); what's the easiest/most reliable way to implement this. One idea I had was to scan the code serverside and return all the scripts at once. This requires the minimal amount of php requests. However, if the client has already requested C.js before, the script should exist client side, and this would be inneficient, especially if C.js and all its dependent files are large. Another option I considered was to wrap all of these serverside scripts in an object like so, for C.js above:
{
depenencies: ['B.js'] ,
code : 'c.age = b.age + 10;'
}
I just don't know how to 'pause' execution of script C.js after the load('B.js') statement, and then resuming it after B.js has been loaded.
EDIT Thanks to redsqaure for suggesting yepnope and requirejs. Unfortunately, I do not like them for several reasons. For one, requirejs is difficult (I am sure I will come under criticism for this one). My main gripe with this is that, if it is so difficult to learn, I might as well recreate it myself, learning it in the process, AND having greater control over it. Second, it requires you to change your style of writing. Switching to Dojo and having to use dojo.declare("ClassName", [ParentA,ParentB], {...}); to declare classes is one thing, but wrapping every snippet of code in require(['A','B',...], function(){}); is another. Finally, I don't know how simple it will be to instruct where to look for files. I want the user to be able to define a 'PATH' variable server side, and have the search occur in each of the folders/subfolders of the 'PATH'
Depends on how optimized you want it to be. Either you can go the route of synchronous XHR or use a callback (async and recommended). If you were to go the second route your code would look something like:
// Say C.js is dependent on A.js and B.js..
load(["A.js","B.js"], function() {
// code goes here
});
EDIT
Taking a second look after you feedback what you want is somewhat possible, but would be brittle and hard to write in javascript. Below i have a sample/untested implementation of a dependency loader where a file can only have one call to load("file.js") possible. This would be more complex for multiple possible dependencies. Also I'm assuming these files are coming from the same domain.
// Usage: load("A.js")
// A.js -> B.js -> C.js
window.load = (function() {
var loaded = {};
return function(str, /* internally used */ callback) {
if(!loaded[str]) {
loaded[str] = true;
$.get(str, function(data) {
var matches = data.match(/load\(['|"](.*)["|']\)/);
if(matches.length > 1) { // has deps
window.load(matches[1], function() {
window.eval(data);
if(!!callback) callback();
});
} else { // no deps
window.eval(data);
}
});
}
}
})();
Why not look into a script loader like yepnope.js or require.js
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.