I have a single file, 'core.js', with a collection of my sites JavaScript. I like to combine my script this way so I can cut down on HTTP requests. My problem is, page specific code's, obviously, getting run on pages it needn't.
Without splitting 'core.js' into separate scripts, what's the best solution for ensuring my page specific code only gets run on the page it's supposed to be run on?
Many thanks!
The simplest way is to make everything in core.js be functions and then put one inline function call in each given page to call the code specific to that page. That makes core.js a resource and each page decides what functions in that resource to call.
I've also seen it done where you put a trigger class name on the body tag and then the code in core.js examines the classes on the body tag to decide what initialization code to run. This works best when you have a small number of types of pages and you want to run the same initialization code on all pages of the same type, but I don't think it's all that good if each page has different JS. In that case, I think it's better to use the first technique of let the page decide what JS initialization function to call.
Related
I have a small application with two pages: the login page and the main page. My problem is that when I use just one main JavaScript file for both pages (like it's recommanded) I get a lot of ReferenceError because some variables on a page are not defined on the other one...
e.g:
Line of code for the login page
copyrightYear.textContent = new Date().getFullYear();
Main page complains
Uncaught TypeError: Cannot set property 'textContent' of null
How can I fix that? Don't tell me I have to say if(copyrightYear) { do stuff } everytime, it's just a nightmare if I have to do that for every variable
Two answers for you:
The recommendation isn't a dictate
My problem is that when I use just one main JavaScript file for both pages (like it's recommanded)
That's a very general recommendation. It doesn't apply to every situation. There's no point in loading code in a page that won't use that code.
If you have code that you use in both pages, and also page-specific code, it's absolutely fine to have a file that both pages share and also page-specific files:
<script src="main.js"></script>
<script src="page1.js"></script>
If you're really worried about the extra HTTP request (much less of an issue these days than it used to be), use modules and a bundler like Webpack or Rollup that will create a bundle combining the main module with page 1's module for page 1 and another bundle combining the main module with page 2's module for page 2.
But even then, the extra HTTP request may be better for your users, if you expect them to go from page1 to page2 in a reasonable timeframe. The reason is that if you have main.js and page1.js/page2.js and you allow caching of them, when the user goes to page1 they get main.js and page1.js, and then when they go to page2 main.js comes out of their local cache and they only have to load page2.js. In contrast, if you had a single bundle file for each page, they'd have to re-download all of that common code when going from page1 to page2 (or vice versa). But if you expect a visitor to visit either page1 or page2 but not the other one, you save the HTTP request by using page-specific bundles.
There's really no one-size-fits-all solution. :-) There are all sorts of considerations.
Note that HTTP/1.1 made additional HTTP requests more efficient and is nearly universally supported, and HTTP/2 makes them a lot more efficient, effectively eliminating the case for reducing the number of HTTP requests as part of the page startup. All major modern browsers support HTTP/2 as do up-to-date web servers.
Put the code for each page in a function
If you really want to keep a single page, put the code that's specific to each page in functions for those pages, and then have code in the main part of the file call the appropriate function based on location.pathname.
You figured it out, you have to check this for every variable. But generally it's much more convenient to use functions and only call these functions when you need them.
So for example, say you want to set some copyrightYear (even tough this shouldn't be set via JS, you should generate this on Backend side to have it in the source code)
You have something like this:
function updateYear() {
// here you do your magic of selecting the element, setting the year, whatever.
}
// another function, totally unrealted to updateYear()
function toggleMenu() {
// some function where you toggle the menu if you click somewhere
// like: button.addEventListener('click', () => {} );
}
And in your JS file you have one block where you call all these functions:
if (document.querySelectorAll('.elementForYear') {
updateYear(); // here we call it because we are sure this element exists... so everything inside function must work
}
if (document.querySelector('.myMenu') {
toggleMenu(); // if the element myMenu exists, we know we can add these toggle Functionality.
}
You can also add these if inside the function and call the function regardless of if it's needed or not, that's up to you and up to coding guidelines.
Generally I find it makes sense to have one function only rely on one (or max two to three elements if it's some toggling of other elements) ... And then you just check for one element. And if this one element exists you can go ahead and call the function.
I am building a multi-page front end for a web application. There is minimal javascript for the UI, but I know there will a great deal of javascript to handle the back-end, so I am doing my best to keep it as sparse and limited as possible.
I want to conditionally execute javascript synchronously while using only one minified js file. I have some global functions, but most of the code is page specific. Each page has the id of the page in the body element. For example, about.html has the following code <html>...<body id="about">...</body></html>.
I am aware of various async methods to load javascript, such as require.js or even $.getScript, but for various reasons, I am trying to avoid that route. Because I am preprocessing the HTML, I also don't want to break the scripts up per page (though I could), because it is a small file, and I don't want to have to create a bunch of different <script> tags. My current solution is to conditionally execute the required javascript per page, and I am doing it like the example below:
$(document).ready(function(){
//global.js code
if(document.body.id==='about'){
// about.js code
}
if(document.body.id==='home'){
//home.js code
}
// etc.
});
During the build process, all js is stored in seperate files, so it's not as visually asinine as it looks here, because there is only a single include filename.js inside the body of the conditional.
The conditionals prevent unnecessary code from executing on each page. However, it dawned on me while I was doing this that there might not actually be any benefit to doing it this way. I read that $(window).load or $('body').load events might cause conflicts with $(document).ready, and they are both definitely slower - as is window.onload (I tested). That would've been my preferred way of going about this I suppose. Is what I read true? And / or, is what I'm doing in anyway useful?
For page specific events, why not just add the body ID in the element reference?
$( '#about .do-something' ).on()...
And if you're actually executing non event based code on a per page basis
if( $( '#about' ).length ) { // trigger your code here }
It's not too dissimilar to your solution except it doesn't require you to keep a manifest of sorts about what code to execute where. Either way, both solutions get cached.
Ok So I know it always depends on the situation but I have, thus far, combined my jquery files/plugins into a single compressed file.
Now I am wondering what I should do with my page specific js/jQuery code. Should I have a single file with one Document.Ready function and my entires sites js code inside of it? Or split it up into seperate js files per page with a document ready call in each?
These files will inclide things such as .Click handlers and other jquery code specific to certain pages.
Whats the best practice here to optimize load times and maintainabilty?
One way to do it would be to use require.js and then have an array with files and page types. Give each body tag an ID and use it to reference what files should be loaded in.
<body id="pageName">
Keep your global files everything you need for the core functionality to work and then lazy load in the features that aren't required for your site to run faster. I've seen huge speed improvements from this technique.
http://requirejs.org/
We can do this in multiple ways , i did in the following way.
Aggregate your files broadylyas following
1) Aggregate all the files required for all the pages
2) aggregate the pages specific to the page.
Include all the common aggregated file for all the pages , and include other aggregated files conditionally on the page
1) jquery and other plugins common to all pages so // it will go to all files
2) homepage-aggregation /// for homepage
3) gallerypage-aggregation // for gallery page.
If you include the same file for all the pages ,it may not necessary for all the files.
I did it recently , let me know if you need anything else
Because you're almost certain to want to have different things executed in the Document.Ready function depending on what page you're on I don't think that having one function that is executed on every page is helpful.
Personally I mix my $.ready calls in with my HTML. These are simple calls to functions stored in a single, minimizing javascript file so don't take up too many bytes, and prevent the need for a separate Javascript file per page. It also allows me to initiate the Javascript where I create the markup, so it's all in one place.
If you're minimizing your javascript and serving it with the correct headers you've got most of the benefits already, don't compromise readability more than you have to.
It also depends on the server side technology you are using. You may find tools to assist you on this task. If you are coding a Java server side, you may try JAWR. It allows the creation of separated JS/CSS files, merging and compressing them server-side, turning all the separate files into a single file.
About Document.Ready, I prefer to keep specific code page in separate files, avoiding incorrect code execution and behavior. It is also cleaner and easier to maintain.
I've been trying to get this sorted all day, but really cant figure it out. I've got a page with <div id="ajax"></div> that is populated off a tab based menu pulling in a snippet of HTML code stored in an external file that contains some javascript (mainly form validation).
I've seen in places that I need to eval() the code, but then on the same side of things people say its the last thing to do.
Can someone point me in the right direction, and provide an example if possible as I am very new to jQuery / JavaScript.
Many thanks :)
pulling in a snippet of HTML code stored in an external file that contains some javascript (mainly form validation).
Avoid doing this. Writing <script> to innerHTML doesn't cause the script to get executed... though moving the element afterwards can cause it to get executed, at different times in different browsers.
So it's inconsistent in practice, and it doesn't really make any sense to include script anyway:
when you load the same snippet twice, you'd be running the same script twice, which might redefine some of the functions or variables bound to the page, which can leave you in extremely strange and hard-to-debug situations
non-async/defer scripts are expecting to run at parse time, and may include techniques which can't work when inserted into an existing document (in the case of document.write this typically destroys the whole page, a common symptom when trying to load third-party ad/tracking scripts).
Yes, jQuery tries to make some of this more consistent between browsers by extracting script elements and executing them. But no, it doesn't manage to fix all cases (and in principle can't). So don't ask it to. Keep your scripts static, and run any binding script code that needs to happen in the load callback.
If you fetch html via Ajax, and that html has a <script> tag in it, and you write that html into your document via something like $('#foo').append(html), then the JS should run immediately without any hassle whatsoever.
jquery automatically processes scripts received in an ajax request when adding the content to your page. If you are having a particular problem then post some code.
See this link
dataType: "html" - Returns HTML as
plain text; included script tags are
evaluated when inserted in the DOM.
What is the general developer opinion on including javascript code on the file instead of including it on the script tag.
So we all agree that jquery needs to be included with a script file, like below:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"
type="text/javascript"></script>
My question is, in order to get functions on a page that is not on all pages of a site. Do we include the functions like below in the same page or in a global include file like above called mysite.js.
$(document).ready(function(){
$(".clickme").click(function(event){
alert("Thanks for visiting!");
});
});
ok. So the question is: if the code above is going to be called in every class="clickme" on a specific pages, and you have the ability to call it either from an include separate file called mysite.js or in the content of the page. Which way will you go?
Arguments are:
If you include it on the page you will only call it from those specific pages that the js functionality is needed.
Or you include it as a file, which the browser cached, but then jquery will have to spend x ms to know that that function is not trigger on a page without "clickme" class in it.
EDIT 1:
Ok. One point that I want to make sure people address is what is the effect of having the document.ready function called things that does not exist in the page, will that trigger any type of delay on the browser? Is that a significant impact?
First of all - $("#clickme") will find the id="clickme" not class="clickme". You'd want $(".clickme") if you were looking for classes.
I (try to) never put any actual JavaScript code inside my XHTML documents, unless I'm working on testing something on a page quickly. I always link to an external JS file to load the functionality I want. Browsers without JS (like web crawlers) will not load these files, and it makes your code look much cleaner to the "view source".
If I need a bit of functionality only on one page - it sometimes gets its own include file. It all depends on how much functionality / slow selectors it uses. Just because you put your JS in an external JS file doesn't mean you need to include it on every page.
The main reason I use this practice - if I need to change some JavaScript code, it will all be in the same place, and change site wide.
As far as the question about performance goes- Some selectors take a lot of time, but most of them (especially those that deal with ID) are very quick. Searching for a selector that doesn't exist is a waste of time, but when you put that up against the wasted time of a second script HTTP request (which blocks the DOM from being ready btw), searching for an empty selector will generally win as being the lesser of the two evils. jQuery 1.3 Performace Notes and SlickSpeed will hopefully help you decide on how many MS you really are losing to searching for a class.
I tend to use an external file so if a change is needed it is done in one place for all pages, rather than x changes on x pages.
Also if you leave the project and someone else has to take over, it can be a massive pain to dig around the project trying to find some inline js.
My personal preference is
completely global functions, plugins and utilities - in a separate JavaScript file and referenced in each page (much like the jQuery file)
specific page functionality - in a separate JavaScript file and only referenced in the page it is needed for
Remember that you can also minify and gzip the files too.
I'm a firm believer of Unobtrusive JavaScript and therefore try to avoid having any JavaScript code in with the markup, even if the JavaScript is in it's own script block.
I agreed to never have code in your HTML page. In ASP.net I programmatically have added a check for each page to see if it has a same name javascript file.
Eg. MyPage.aspx will look for a MyPage.aspx.js
For my MVC master page I have this code to add a javascript link:
// Add Each page's javascript file
if (Page.ViewContext.View is WebFormView)
{
WebFormView view = Page.ViewContext.View as WebFormView;
string shortUrl = view.ViewPath + ".js";
if (File.Exists(Server.MapPath(shortUrl)))
{
_clientScriptIncludes["PageJavascript"] = Page.ResolveUrl(shortUrl);
}
}
This works well because:
It is automagically included in my files
The .js file lives alongside the page itself
Sorry if this doesn't apply to your language/coding style.