Efficiency of Browserify with multiple bundles - javascript

I'm new to Browserify and I'm trying to figure out how to make it more efficient with regards to how much the client needs to download.
I have a web app, that uses many different 3rd party libraries and custom code. With Browserify, it seems like the general approach people suggest is to wrap everything up into one big bundle.js. This seems horribly inefficient to me for several reasons:
For example, lets say your bundle.js contains lib1, lib2, lib3, customLib.
If a part of your web app only needs lib1 the client still has to download a huge bundle.js and it ends up not using 75% of it. Wasted bytes downloaded. Unnecessarily increased page load time.
If your customLib is a piece of code that you iterate upon often, then every time it changes, your clients have to redownload bundle.js, again downloading a ton of 3rd party libraries that haven't changed...
Other parts of your web app may use lib2 and lib3 but the client may or may not ever go to there, in which he definitely wasted bandwidth downloading the entire bundle.js.
I've seen suggestions to split up your bundle into multiple bundles. But to what end? If one page uses lib1, another page uses lib1 and lib2 and another page uses lib2 and lib3, then how do you split it up? The more you split it up into multiple bundles aren't you getting away from the advantages of bundle.js?
Browserify seems to be highly regarded so I hope that I am just missing something here. What is the proper approach to bundling together many libraries and custom scripts together? People call Browserify a "script loader" but every script loader I've seen in the past (like yepnope etc), use logic to determine which scripts to download, which seems like a much more efficient solution, while Browserify appears to want the client to download everything...

Not sure if the answer fits SO format well. But nevertheless...
Partitioning Section of handbook describes 2 following techniques
factor-bundle factors 2 or more entry points placing common dependencies into a single bundle.
partition-bundle same as factor-bundle but with runtime loading using async loadjs function.
Factor bundle
<script src="/bundle/common.js"></script>
<script src="/bundle/x.js"></script>
Partition bundle with async loading fallback
loadjs(['./x'], function(x){...});

Substack just published this gist explaining how to split bundles. He suggests to use factor-bundle like this:
browserify x.js y.js -p [ factor-bundle -o bundle/x.js -o y.js ] \
-o bundle/common.js

Related

What are the benefits of consolidating application code with vendor code?

On my current project we have our gulp build process dropping our Angular application to two Javascript files; one for anything in the app (things we wrote), and one for vendor files (basically anything brought in; e.g. bower included).
Recently a request came from a more abstract influence on the project to consolidate the app.js and vendor.js (and CSS equivalents) into one file to reduce HTTP requests.
Now, I don't really have a lot of experience with gulp, but our original implementation was setup for the two files. My question is: is there actual benefit in consolidating the two, or is there a technical or practical reason for them to be separate? Perhaps this was the way the initial (probably Yeoman) scaffold laid them out, and if so, is there an architectural reason?
Thanks much in advance for any and all advice or experiences you can provide.
Gulp will have no trouble compiling your vendor and app code into a single file. The benefit of this is it would reduce the number of requests your browser needs to make to a single script request.
However, two files are often used to make it more obvious where errors are coming from if they occur. It also means that compiling your app code is faster since it doesn't need to re-compile the vendor code whenever your app code changes. Typically, the vendor code is more stable so it shouldn't need frequent compiling (or even watching).
Additionally, with the advent of HTTP2 and its ability to do multiplex downloads, concatenating your code into one large file is a worse option. This is because even a small change results in the entire concatenated blob needing to be re-downloaded.

Why use requireJS instead of an ordered include list?

I've been using a grunt file to concatenate all my JS into a single file which is then sent to the client. What advantage do I have in using require calls then? The dependencies are inherent from the concatenation order and I don't have to muddy all my JS with extra code and another third-party library.
Further, backbone models (for example) clearly state their inheritance in their definitions. Not to mention that they simply wouldn't work if their dependencies weren't included anyway.
Also, wouldn't maintenance be easier if all comments related to dependencies were in one place (the grunt file) to prevent human error and having to open every JS file to understand its dependencies?
EDIT
My (ordered) file list looks something like:
....
files: [
"js/somelib.js",
"js/somelib2.js",
"js/somelib3.js",
"js/models.js",
"js/views.js",
"js/controllers.js",
"js/main.js"
], ...
So perhaps requireJS isn't worth it for small projects anyway.
Using require.js allow you to break down each part of your application into reusable modules (AMD) and to manage those dependencies easily. It is not easy to manage dependencies in a javascript application with 100 classes, for example.
Also, if you don't want all the overhead of require, check this out (developed by the same guy who created require.js): https://github.com/jrburke/almond
The answer depends on the size of your app and the end use case..
A single site.min.js payload for the front end (client) generally aims for small file sizes and simple architectures (1 single file generated from maybe 10).
back end based (server) apps are usually much bigger and complicated and therefore may warrant the use of another tool to help with managing large code libraries and dependencies (50 files for example).
In general, RequireJS is worthwhile but only if you have many files and dependencies. An alternative for use in the client would be almond. Again, using a tool like this must warrant the need (many files and dependencies).
The answer from orourkedd is also worth reading.

Relevance to compile several js files in one for a production site

I have ten js files used in different pages of my website but never all together.
Is it possible to compile all js files into a single file?
I wish to avoid that the client browser has to load several js files.
How would I achieve this and what is the best practice in terms of loading performance?
You could try using an AMD module loader such as requirejs. It has the capability to concat and uglify all your scripts into one file so it downloads everything in a single request.
If you do not want to use AMD modules, you could just concat and minimize your files manually. Minimizing is mainly done to compress your code and to obfuscate the source, even though there are tools to reverse the minimized code. Have a look at Google's closure compiler and UglifyJS.
Another thing you could to is to make your web server gzip it's responses for application/javascript MIME type.
Really worth looking at Grunt, and specifically grunt concat task
This is just one way Grunt is helpful, very much worth your time to get your head around!
There are also plugins for Require, which is very helpful.

Use RequireJS optimizer for partial optimization

I am trying to optimize a significant number of javascript files with RequireJS, but I am having trouble wrapping my head around how to properly build the scripts with the optimizer and load them in the browser in the desired way.
While the following description is rather specific, I would imagine quite a few other people are encountering the same challenges. (Or they have made wiser choices in their requirements!)
I am using bower to download a catalog of scripts, and I would like to include those scripts (or parts of them) in my web-page.
Additionally, while testing I essentially never want to have the browser retrieve the individual bower scripts. The local test framework responds to requests serially, so this is quite slow. I would like to use the RequireJS optimizer, or some other method, to combine all the downloaded bower scripts into one file.
In contrast, my own code been broken out into a long list of Coffeescript files, and I would like to use the RequireJS CS plugin to compile them for the browser.
When developing then, I would expect my browser to load something like the following:
components.js
main.js
csmain.coffee
my_module.coffee
The components.js would consist of the following files from bower's components directory e.g.
jquery: jquery/jquery
jqueryui:
jquery-ui/ui/jquery.ui.core
jquery-ui/ui/jquery.ui.datepicker
amplify:
amplify/core/amplify.core
amplify/request/amplify.request
bootstrap:
bootstrap/js/bootstrap-transition
bootstrap/js/bootstrap-alert
bootstrap/js/bootstrap-button
bootstrap/js/bootstrap-carousel
bootstrap/js/bootstrap-collapse
lodash: lodash/lodash
In production, the browser would load one file, say all.js.
So my question is: if I use RequireJS what goes into the browser main.js and build script to achieve the partial and completely optimized builds. I have spent a disproportionate amount of time on this problem, and the number of inexplicable and arcane errors from RequireJS has been tragically lengthy - to the point where I could not identify severable prohibitive issues. It just doesn't seem to be the tool for the job, but I would be happy to be corrected.
What I have for an optimization script resembles the following (in YAML notation):
baseUrl: "../media/my-scripts/"
optimize: none
out: build/all.js
stubModules:
- cs
- coffee-script
paths:
cs: "../../scripts/components/require-cs/cs"
'coffee-script': "../../scripts/components/require-cs/coffee-script"
usf: "./main"
components: "../compiled/components"
name: usf
logLevel: 0
shim: # ...
It seems that the problem I wish to solve is rather straightforward, yet the solution not forthcoming. RequireJS, albeit brilliant, is dramatically more complex than what I need. Almond.js is an alternative for loading the modules - but the problem rests with the lack of an alternative suitable optimizer.
I would be grateful for any thoughts on what options may be available for using r.js to achieve the above, or alternatively what suitable alternative optimization solutions may exist.
Not having found an answer, I wrote YAMDO to solve this problem EDIT I have since deprecated that project and come to rest upon the awesome Browserify project.

When to use Requirejs and when to use bundled javascript?

This may be a dumb question for web guys. But I am a little confused over this. Now, I have an application where I am using a couple of Javascript files to perform different tasks. Now, I am using Javascript bundler to combine and minify all the files. So, at runtime there will be only one app.min.js file. Now, Requirejs is used to load modules or files at runtime. So, the question is if I already have all things in one file, then do I need requirejs? Or what is a use case scenario where I can use requirejs and/or bundler?
Please let me know if any further details are needed.
Generally you only use RequireJS in its loading form during development. Once the site is done and ready for deployment, you minify the code. The advantage here is RequireJS knows exactly what your dependencies are, and thus can easily minify the code in the correct order. Here is what it says on the RequireJS website:
Once you are finished doing development and want to deploy your code for your end users, you can use the optimizer to combine the JavaScript files together and minify it. In the example above, it can combine main.js and helper/util.js into one file and minify the result.
This is a hotly contested issue among many proficient javascript developers. Many other languages have a "compilation" phase where the entire program is bundled up for deployment (JBoss's .WAR files come to mind). Programmers that come from more traditional backgrounds often favor this approach.
Javascript has seen such growth in recent years that it is difficult to chart exact best practices, but those that appreciate the more functional nature of Javascript often prefer the module loading approach (like require.js uses).
I wrote Frame.js which works much like require.js, so my bias is towards the module loader approach.
To answer your question directly, yes, it is one or the other.
Most that argue for packing your scripts into a single file believe it enables more compression and is thus more efficient. I believe the efficiency advantages of packaging are negligible in most cases because: (1) module load times are distributed over the entire session, (2) individual modules can be compressed to nearly the same percentage, (3) individual modules can be cached by the server and routers separately, and (4) loading scripts only when they are needed ultimately allows you load less code for some users and more code overall.
In the long run, if you can see an advantage to dynamic script loading use it. If not, bundle your scripts into a single file.
It depends on your application. If you're making a server-side app with only modest javascript (less than 100kb minified) then go for total bundling, you're probably going to be fine.
But if you're making a javascript app and have a ton of code in it, then your needs are going to be different.
For example, in my app I bundle all the core files. There's jQuery, underscore, backbone, my main app files, my user login system, my layout system, my notifications and chat system, all are part of my big initial file.
But I have many other modules as well that isn't part of the initial bundle, that are loaded after those.
The forums, the wiki, the wysiwyg, color picker, drag/drop, calendar, and some animation files are part of the second category. You need to make reasonable decisions about what's commonly used and needed immediately vs what can be delayed.
If I include everything immediately I can get above a meg of javascript, which would be insane and make the initial boot unacceptably slow.
The second category starts downloading after initSuccess event fires from the initial file.
But the second category is more intelligent than the first in that it loads what's more important first. For example if you're looking at the wiki it'll load the wiki before it loads the color picker.

Categories

Resources