I'm currently working on an EJS webpage for a single module. In this framework, a set of default scripts are included for all modules, as well as a set of module-specific scripts. I can't change what is included.
I'm having issues getting a certain Highchart to be generated. Long story short, the common scripts included a Highchart library located at the framework's common library path. The module itself included a script to another Highchart library located at the module's local 3rd party library path. The name of these two scripts are different - I'm unable to tell if they are the same version whatsoever.
I'm in the process of troubleshooting but that's not the main point of this question. What I want to know is whether the existence of two different scripts of the same library being included in the same HTML page would cause problems?
It totally depends on the library, and specially, what else is executed between the first and second time the library is being initialized.
Short answer is yes, it is very likely to cause problems.
Related
I am developing pretty big SPA (final ~30MB) and unfortunately one of requirements is that an app has to be released as one big html file. I use webpack to connect all pieces together.
Currently I am facing a problem with performance (some libraries are quite big ones). They "eat" a lot of ram and affects loading time due to code evaluation in browser. I would like to postpone it and evalute only these modules which are necessary at main screen of app.
My idea is to use the same mechanism like webpack does for sourcemaps:
https://webpack.js.org/configuration/devtool/ (eval-source-map)
Webpack simply puts code within eval("code of module") which prevents automatic evaluation by Javascript engine. Of course this code can't be minified and there is also sourcemap attached as base64 to the end. I would like to do same without sourcemaps and including uglification. Moreover I have an idea to reduce size of application by compressing sources so eventually it would be eval(gz.decompress("code of module")).
It will be a huge change in application so before I am going to reinvent a wheel I would like to ask you:
Does it make sense from problem point of view?
Do you know any existing solutions?
Do you suggest to use any existing components from webpack like:
https://webpack.github.io/docs/code-splitting.html
or write own solution from scratch (loader/plugin).
Don't do that what you want!
If you do want to find a weird trick to get what you want, try including your big JS file dynamically. See here or google jquery getscript. No additional Webpack actions required.
If not, please, continue reading.
You're dealing with the problem from the wrong perspective.
First, make sure you are doing all the obvious HTML/HTTP stuff:
You're downloading the gzip-ed version of the file (if not, google http script gzip)
You're including the <script> tag at the end of the body. This will start downloading and parsing JS only after HTML has been rendered.
Then, the most important, try to figure out where is the 30MB coming from. It's unlikely a fair sum of all your big fat dependencies. Usually, it's a particular bloated library (or two). Make sure you use got instead of request because the least is bloated. Find alternatives for the out-sized dependencies.
No single SPA in the world should have a 30MB JS bundle. I'm assuming your project isn't very large because otherwise it would be business critical and you would invest into providing a decent back-end strategy (e.g. code splitting, dead code elimination, etc.).
1) The similar problem can be solved with Webpack code splitting functionality.
The idea is that you don't load route specific code and libraries until the user accesses the specific page.
2) Take a look at this: script-ext-html-webpack-plugin, looks very promising to do these kinds things. For example, defer options would be for modules or scripts that you want to delay the execution. Async would be for scripts that you want to execute as HTML gets executed. Be careful though about race conditions.
3) You mentioned that you use libraries that are so big, make sure you use Webpack with tree shaking. If you use the old Webpack (version 1.*) which does not have tree shaking, you should try to optimize imports manually. For example, instead of import _ from 'lodash' it would be import map from 'lodash/map'.
4) You also mentioned that it is the ram that is the problem, so how compression can help ram? compression can help the browser to retrieve it faster.
5) The other idea would be:
Load the scripts that you need for the home page
execute them. at this point, the user sees the functioning page
then behind the scenes load other scripts slowly without the user to notice it.
evaluate loaded code as it will become needed for the user.
TL,DR: How to load css and javascript files independent of Meteor assumptions about alphabetical order (which is far from how it works in practice.)
Stackoverflow tells me this question might be subjective but I hope not.
Meteor loads files based on alphabetical order (and other rules.)
So to force it to load the CSS and JS files in the order I wanted, I had to start the fiels with numbers that indicate the load order. If I have jquery.js and bootstrap.js, Meteor will load bootstrap.js before jquery.js. But bootstrap depends on jquery so jquery must be loaded first.
In order to solve this, the options are:
1. Put the files in the public directory and manually load them. But this didn't work as Meteor appears to be sending the files with text/html MIME type.
2. Create a Meteor package and specify the load order from there. I find this like hitting a fly with a hammer just for loading CSS and Javascript.
3. Put a number before every file. In the previous example, to load jquery before bootstrap, rename the fiels to 1.jquery.js and 2.bootstrap.js This works and is tedious but at least I get to load the files the way I want them to.
I am new to Meteor so I am wondering if there are recommended best practices concerning this. I was thinking of using AMD for javascript but that's limited to javascript.
Its an interesting question and this is probably one of the pitfalls of making a Meteor app.
You've mentioned all of the usable solutions such as creating an explicit package or renaming the files.
The best way I would think is to use the atmosphere packages. For example if you add bootstrap, jquery is a dependency of it so it will always load first. Most js libraries that involve load order are typically on atmosphere.
The other best way if there's no atmosphere package, though i'm not sure I would say is tedious is to put a number in front of the js file to indicate load order.
One thing is when you use the /public folder the files map to /, so you can load the js file yourself manually in the order you would want (in the root html file using /public. Meteor returns the text/html MIME type as its version of a 404 file not found error. This method is a bit troublesome though because the files are seperated in production and can cause trouble if one or the other dont load.
I'm working on a large web application which has about 10K lines of JavaScript code (without taking into account the third-party libraries). In order to speed up page loading it has been decided to automatically concatenate every script file into a large script that gets loaded (and cached) on the client the first time the application is accessed. This poses a problem due to the fact that each page had its own script which contained all JavaScript required in (essentially) the same function.
Now if an error occurs in one of the scripts it is really hard to tell where that error came from, since everything is rolled into the same script which is added to each page, as opposed to using explicit script declarations in each page as was done before.
Is there a JavaScript pattern for solving this issue? I'm thinking of something similar to the AngularJS modules that can be bound to certain containers inside a web application's pages.
However, I would like a simple, custom, solution, as we're short on time and we don't have time to implement a framework in our application. It should apply certain scripts (modules) only to their respective pages and it should allow developers to explicitly declare any other scripts (modules) that certain scripts rely on.
Also, implementing an exception handling system to notify users (in the Firebug console, for example) from which module an exception originated (if the page's module relies on other modules) would be great.
Is there a common means of solving such issues in JavaScript (without relying on frameworks)?
A possible solution to your problem could be the use of js source maps. Many concat/minify/uglify tools directly support this feature, while most modern browsers are capable of interpreting them.
You would still serve a single JS file containing all your code (even if this is most likely not the best idea to handle such large amounts of code - largely depending on your overall architecture)
But your browsers developer tools are now able to show you the original file name and line number of an error/console output/etc.
You might most probably not serve the source map file in production.
A good point to get into js source maps is this wiki.
Question 1:
Why do I need to asynchrously load my JavaScript files in a web page? I can see the rationale for it on the server side, but if I know all the files I need to load in the client, why shouldn't I concatenate all my source files into 1 file and load that on page load? Is the first initial page load so important that future operations may be slowed down due to latency in retrieving every JS file?
Question 2:
Assuming the answer to question 1 is that I need to load JS files separately:
AMD loads each JS file asynchrously, CommonJS loads synchronously. CJS is required for server-side loading (that's how Node.js works, if I'm not mistaken). AMD seems to be a better fit for the client. Thus, the only reason to use CJS in the client is to share code with the server.
Is there a way to make AMD and CJS play nicely, so that client JS files can be loaded asynchronously but still have CJS syntax?
(What exactly does require.js do? I cannot for the life of me read between the lines on their website.)
You do not "need" to load javascript files asynchronously or via some custom loader. Here are some reasons when asynchronous loading or custom loading might provide a benefit:
When the javascript file is not normally needed and you might want to load it upon demand rather than all the time
When the javascript file is not needed for initial page display and you want to maximize the speed of first display for your page
When you want to control the timing of exactly when the javascript file is loaded
When you are deciding, based upon some condition, whether to load the javascript file or not (for example, if loading from a CDN failed, you might load from a backup location)
When you want script loading to proceed in parallel with other things rather than serialized one after another
If you don't need any of these benefits or some other benefit provided by programmatic loading, then you can just use the normal <script> tags and let them load synchronously.
Part of the issue with just concatenating the file isn't the time spent downloading, it's the time spent compiling on every page.
If you've got a 20,000 line file, and you only need 600 of those lines to get everything up and running (assuming that everything is written to be modular and asynchronous, using any pattern at all for managing the resources), then you're going to save yourself what might be half a second or more, if you serve the core program and extend as-needed (or on a delayed timer, serving large chunks of functionality which are closely related to one another).
The overall time spent downloading is higher.
The overall number of HTTP connections used is higher.
But the time required to make the page visible to the user is lower.
The time required to add base-functionality to the page is lower.
Then extra functionality can be streamed in, either after the load and initialization, or just-in-time, as-requested by the user, and in both cases, as long as the code you've streamed in is focused on doing that one thing, and isn't calling for a half-dozen other dependencies, the time between the request and the addition of the functionality is going to be minimal.
RequireJS uses a promise system, basically.
It allows you to declare dependencies up front, and hand in the code (as a callback) to be implemented, after all of its dependencies are handled.
If those dependencies have any dependencies, then they won't be initialized until their dependencies are loaded.
If you just want it loaded and order isn't important, then you don't need to give it dependencies.
The overall moral is, if you've got a system where all of your files are small, the overall weight of JS on the page is very small, you only needed a few hundred lines to do everything you wanted on the page... ...plus, you know where all of your dependencies are, you have a system on the server to make sure they're in the right order, et cetera (plus you've got great documentation, or you're the only one who touches this code, and you live inside of it, day to day)...
...then there's nothing at all wrong with doing what you're doing.
You might not see any difference at all, if the compile time is outweighed by the number of HTTP requests you make.
But for overall applications which are tens (or hundreds) of thousands of lines long, where only a fraction of that functionality is needed on any one page, there can be big savings in terms of perceived time between when the page loads, and when the app is "ready" for basic interaction by the user.
If you want to load your entire javascript source for every page, sure, compile it into one file. If you load different code based on what actions the user takes, or based on what page has been loaded, use AMD loaded modules. The other alternative would be to list a bunch of script tags, which of course would only be loaded one at a time and could take a while.
AMD is not a specific library, it is actually a standard for loading javascript modules that most of the loaders you mentioned use. This means they all use similar syntax for defining and loading modules. They are considering making AMD part of the ECMA script spec. The usefulness of it is that you can also define dependencies, so if your code requires jQuery to run, you can list this as a dependency, and it will be loaded into your modules namespace.
define( [ 'jquery' ], function ( $ ) {
// use jquery in here without clouding up the global namespace
return {}; // return your module for use in a different module or whatever
};
In this example, the code in the defined module will not be run until the jquery module has been downloaded. It will then inject the jquery module directly into your newly defined module as an argument $.
You can now keep your code neatly organized into files which contain modules. None of your modules will cloud up the global namespace. All of your dependencies will be sure to have been loaded before your module runs (no loading race condition bugs for dependent pieces of code).
Another advantage is you can set up your loader to use different paths for the same module, so you can define the path for the jquery module to be 'https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js' in one spot in your code even though it may be used in almost every module. Now when I need to update my jquery version to 1.8.3, I can simply change the path in one spot in my code, and it will use this path for every module that uses jquery as a dependency. This can also be useful for easy switching when testing when you are using module stubs, or debug versions of certain modules.
Now this is not necessarily needed for tiny projects. The bigger your project gets however, the more sense this type of loading starts to make.
Do you localize your javascript to the page, or have a master "application.js" or similar?
If it's the latter, what is the best practice to make sure your .js isn't executing on the wrong pages?
EDIT: by javascript I mean custom javascript you write as a developer, not js libraries. I can't imagine anyone would copy/paste the jQuery source into their page but you never know.
Putting all your js in one file can help performance (only one request versus several). And if you're using a content distribution network like Akamai it improves your cache hit ratio. Also, always throw inline js at the very bottom of the page (just above the body tag) because that is executed synchronously and can delay your page from rendering.
And yes, if one of the js files you are using is also hosted at google, make sure to use that one.
Here's my "guidelines". Note that none of these are formal, they just seem like the right thing to do.
All shared JS code lives in the SITE/javascripts directory, but it's loaded in 'tiers'
For site-wide stuff (like jquery, or my site wide application.js), the site wide layout (this would be a master page in ASP.net) includes the file. The script tags go at the top of the page.
There's also 'region-wide' stuff (eg: js code which is only needed in the admin section of the site). These regions either have a common layout (which can then include the script tags) or will render a common partial, and that partial can include the script tags)
For less-shared stuff (say my library that's only needed in a few places) then I put a script tag in those HTML pages individually. The script tags go at the top of the page.
For stuff that's only relevant to the single page, I just write inline javascript. I try to keep it as close to it's "target" as possible. For example, if I have some onclick js for a button, the script tag will go below the button.
For inline JS that doesn't have a target (eg: onload events) it goes at the bottom of the page.
So, how does something get into a localised library, or a site-wide library?.
The first time you need it, write it inline
The next time you need it, pull the inline code up to a localised library
If you're referencing some code in a localized library from (approximately) 3 or more places, pull the code up to a region-wide library
If it's needed from more than one region, pull it up to a site-wide library.
A common complaint about a system such as this, is that you wind up with 10 or 20 small JS files, where 2 or 3 large JS files will perform better from a networking point of view.
However, both rails and ASP.NET have features which handle combining and caching multiple JS files into one or more 'super' js files for production situations.
I'd recommend using features like this rather than compromising the quality/readability of the actual source code.
Yahoo!'s Exceptional Performance Team has some great performance suggestions for JavaScript. Steve Souders used to be on that team (he's now at Google) and he's written some interesting tools that can help you decide where to put JavaScript.
I try to avoid putting javascript functions on the rendered page. In general, I have an application.js (or root.js) that has generic functionality like menu manipulation. If a given page has specific javascript functionality, I'll create a .js file to handle that code and mimic the dir structure on how to get to that file (also using the same name as the rendered file).
In other words, if the rendered page is in public/dir1/dir2/mypage.html, the js file would be in public/js/dir1/dir2/mypage.js. I've found this style works well for me, especially when doing templating on a site. I build the template engine to "autoload" my resources (css and js) by taking the request path and doing some checking for the css and js equivalents in the css and js directories on the root.
Personally, I try to include several Javascript files, sorted by module (like YUI does). But once in a while, when I'm writing essentially a one-liner, I'll put it on the page.
Best practice is probably to put it on Google's servers.
(Depends what you mean by "your" javascript though I suppose :)
This is something I've been wrestling with, too. I've ended up by using my back-end PHP script to intelligently build a list of required JS files based on the content requested by the user.
By organizing my JS files into a repository that contains multiple files organized by purpose (be they general use, focused for a single page, single section, etc) I can use the chain of events that builds the page on the back-end to selectively choose which JS files get included based on need (see example below).
This is after implementing my web app without giving this aspect of the code enough thought. Now, I should also add that the javascript I use enhances but does not form the foundation of my site. If you're using something like SproutCore or Ext I imagine the solution would be somewhat different.
Here's an example for a PHP-driven website:
If your site is divided into sections and one of those sections is calendar. The user navigates to "index.phhp?module=calendar&action=view". If the PHP code is class-based the routing algorithm instantiates the CalendarModule class which is based on 'Module' and has a virtual method 'getJavascript'. This will return those javascript classes that are required to perform the action 'view' on the 'calendar' module. It can also take into account any other special requirements and return js files for those as well. The rendering code can verify that there are no duplicates of js files when the javascript include list is built for the final page. So the getJavascript method returns an array like this
return array('prototype.js','mycalendar.js');
Note that this, or some form of this, is not a new idea. But it took me some time to think it important enough to go to the trouble.
If it's only a few hundred bytes or less, and doesn't need to be used anywhere else, I would probably inline it. The network overhead for another http request will likely outweigh any performance gains that you get by pulling it out of the page.
If it needs to be used in a few places, I would put the function(s) into a common external file, and call it from an inline script as needed.
If you are targeting an iphone, try to keep anything that you want cached under 25k.
No hard and fast rules really, every approach has pros and cons, would strongly recommend you check out the articles that can be found on yahoo's developer section, so you can make informed decisions on a case by case basis.