Loading groups of dependencies in Webpack - javascript

Webpack makes it really easy to bundle things together, and also asynchronously requiring single chunks.
However I can't quite work out how to delay requiring a set of dependencies needed by only a few parts of my app.
Since it's an SPA, I'd like to avoid using a <script> tag and have it load a set of larger (namely brace, esprima, lodash etc) dependencies when the user reaches the relevant parts of the app.
This is similar to the vendor split approach, except I only need the essential modules for navigation, signup, login etc. When using chunks out the box it duplicates these dependencies for each chunk, so they are common dependencies - but I'd like to have more than one common bundle; and be able to load it asynchronously when needed.

This is called code splitting. (Webpack Code Splitting) Take a look at the Webpack site for a "brief" breakdown of how it works. Most of the tutorials out there reference code splitting for critical path rendering, but the concept is the same and should be applicable for your situation.
I would recommend creating an entry for the your dependency bundles, and then reference that withing each module. While you should theoretically be able to just pull in dependencies for each module independent of the "bundled dependencies", I have ran into issues with webpack where dependencies are reinitialized when referenced by separate bundles, which causes issues for dependencies that are meant to be singletons.

Related

React.js best workflow for multiple independent modules

I just wondering let's say I already have a website. If I would like to inject some react modules into it lets say MODULE-A, MODULE-B, MODULE-C. At some situations, MODULE-A and MODULE-B are on the same page. All modules are sharing react, axios but also they have their own dependencies. what is actually the best approach to prepare build for it?? I actually like create-react-app. Is there any smart way to make modules only load required dependencies? so I can include them separately and if both exist on the page they will not clone dependency in code.
I want to avoid the situation that I have 20 small modules and all of them use react inside built code. So 60% of the code will be duplicated dependencies.
You have not many options
You can leverage code-splitting as referred here https://webpack.js.org/guides/code-splitting/ so let's say you have
ModuleA -> [depA, depB, depC]
ModuleB -> [depA]
ModuleC -> [depC]
now you can code split to 4 javascript files which will be
moduleAbundle.js
mobuleBbundle.js
mobuleCbundle.js
vendors.js
vedors will be concatenation of depA, depB, depC but ofcourse when you will load moduleB and ModuleC on 1 page you will be also loading depB as it's included in vendors.js you will need to think and play a lot with orchestration of this.
But what you can actually do you can think of most critical parts and most shared deps and list them, let's say all of your packages are using react, react-dom, lodash you will make bundle for vendors with only those libraries, any other library will be bundled with module itself and yes you can't 100% elimate "double-loading" but if you will double load library which has several kB it's fine, when it's larger, ship it with vendors.js
or you can have some complex mechanism on backend side when you will exactly specify and orchestrate loaded dependencies because you know which modules are rendered and what are they dependencies. But there are no any ways of on-the-fly bundling and sending only needed and requested dependencies, it would be very slow to do that on-the-fly and you need to flush quick response to the browser not slow it down with additional compilation process. So it's most likely a manual job to correctly prepare and split code in logical chunks which makes sense.
I dont know answer for React but for the future, maybe you can think about using Angular instead, and its ngModule capability into splitting application to multiple independent modules with their own dependences.
https://angular.io/guide/ngmodules

How to integrate Webpack in a multi-page PHP application

I'm working on an old Codeigniter website where the Javascript codebase is messy and poorly structured and I would like to use Webback to manage the scripts. My goal would be start using it to bundle the code I have the way it is, and gradually refactoring it to make use of modules and imports.
At the moment I'm using Gulp on development (but mostly to minify the files) and Carabiner (a Codeigniter library) to insert the scripts in the views.
The scripts, which are all written as IIFEs are not bundled, so in every controller function I have an array of the scripts needed in that page. For example:
public function homepage()
{
$this->carabiner->js([
['libraryThatIOnlyNeedHere.min.js'],
['myscript1.js'],
['myscript2.js'],
['myscript3.js'],
]);
I would like to use Webpack to create a series of bundles so that I end up loading maximum two files on every page: one for the libraries and one for my scripts.
All the practical examples I've seen with Webpack, though, are for Single Page Applications where it's quite easy to bundle everything together.
What would be the best approach in my case? Considering that the code is still not ready to properly use modules and imports, shall I create many entry points in the Webpack configuration file, possibly one for every page and list every script needed in that page?
Main idea behind webpack is to build modules graph from provided sources and then to combine it into bundles. If your code doesn't have explicit dependencies - it may be good idea to start with creating a module from every file using any of available approaches (AMD, CommonJS, etc). You will need to create module identifiers and define dependencies for every module. It may be worth to read this article for example.
As intermediate step you may want to use some loader like Require.JS to load your modularized code.
Until this step will be done - there is not much use of Webpack.

Automatic vendor chunk with dynamic code splitting

How my application is split into chunks
My applications main and only entry chunk contains some common logic that is reused throughout the application such has layouting or helper methods and components related to authentication such as login/registration dialogs. This chunk has react, react-dom, redux, react-router and some other libs from node_modules directory in its dependency tree because they are being used by the authentication components.
All those dependencies are bundled into an app.js file that is always initially loaded. Whenever the user starts to use some part of the application that requires a logged in user - such as dashboards, forms and other app functionality, additional javascript chunks comprising that functionality are loaded. Those additional chunks are automatically generated by webpack because of import() calls distributed throughout the applications code.
When a new user loads the app and is not logged in, app.js is loaded and the user is presented with a login mask. After a user has successfully logged in and is redirected to the main dashboard, the code of the dashboard is asynchronously loaded. This code, automatically built into a dashboard.js chunk by webpack, also depends on a lot of the libraries already baked into the app.js chunk (e.g. react, react-dom etc). Because the dashboard.js chunk does not duplicate those libraries, it is quite small compared to the app.js.
To make good use of browser caching, all of those chunks (in this simplified
example: the entry chunk app.js and the dynamic chunk dashboard.js) have a
[chunkhash] in their name. In comparison to library code from node_modules, both the code of the dynamic chunks and the parts of the app.js that are actual application code change quite a lot.
What i would like to do
I would like to configure webpack in a way that detects which libraries from
node_modules are used in more than 2 (or any configurable number) of chunks and
automatically split those into an additional chunk, vendor.js.
This chunk should contain the library parts of the current app.js that don't change often so the user doesn't often re-download library code.
From what i've understood, something like this can be done with
CommonsChunkPlugin when manually adding lots of entry chunks. Can i also do
this with dynamic code splitting performed with import() calls?
Example
I might use lodash.partialRight somewhere in in dashboard.js. As long as it is only used there, i want it to be bundled with dashboard.js. The moment i also use it in the login/registration process, it should not be bundled into the
app.js the way it is now but should instead automatically be bundled into vendor.js with other libraries that are re-used across chunks.
You'll have to list out the libraries that you want to be added to vendor.js explicitly. https://webpack.github.io/docs/code-splitting.html#split-app-and-vendor-code
The rest of your code and node_modules that are not listed in "vendor" will be split automatically by webpack. So the more libraries you list in
vendor: ["jquery", "underscore", ...],
the larger vendor.js file is but with less frequent re-download from your users.

How to get r.js optimizer to combine all modules in a project into one file?

From experimenting with the r.js optimizer, it seems that there is no way for your final index.html file to just reference a single script and never make any async calls to other scripts during the lifetime of a user's session (unless they reload the page of course). From my experience, it looks like it creates a bunch of combined groups of optimized files which can be referenced when needed? This seems counterintuitive to most combine scripts where you end up with just one combined/optimized js file that is in the correct order. Can anyone help explain my issue?
Yeah, that's how r.js works, it optimize your dependencies into one or multiple file (you'd use include option to get all your file togheter).
Although, this build will keep require.js script file out of the build. But, after the build, you can combine require.js (or minimal AMD implementation like almond.js) at the top of your builded file and it will all work mostly fine (some problem may occur depending on how you bootstrap your app, but most of the time those issues are pretty easy to resolve).
To combine the files easily, you can use tools like grunt.js (I really recommend it to you as it can do much more and is really a must have in frontend developpement workflow). If you work with backbone app, you can checkout (Backbone Boilerplate)[https://github.com/tbranyen/backbone-boilerplate] and their grunt implementation.

what are the advantages of using an AMD like requirejs or commonjs modules in javascript?

I've read a lot of articles on AMD solutions like RequireJS or module loaders that follow CommonJS style in Javascript.
Let's say I have an app splitted in this parts:
App definition that rely on the framework i use
Model 1 that rely on App definition and framework
Model 2 that rely on App definition, Model 1 and my framework
I may write each part as a RequireJS module or a common JS module and split my project in how many files I want but what's the advantage of writing each part as a module or splitting them in many files and then load them in the right order (to avoid dependency problems) maybe concatenatening all the files in a big one to reduce HTTP requets (as done by r.js optimizer)?
In my opinion, there are three rather important reasons:
You can create and re-use modules without polluting the global namespace. The more polluted your global namespace is, the bigger the chance of a function/variable collision. That means you define a function called "foo" and another developer defines the function "foo" = one of the functions gets overwritten.
You can structure your code into separate folders and files and requirejs will load them asynchronously when needed, so everything just works.
You can build for production. RequireJS comes with its own build tool called R.JS that will concat and uglify your javascript modules into a single (or multiple) packages. This will improve your page speed as the user will have to make less script calls and load less content (as your JS is uglified).
You can take a look at this simple demo project: https://c9.io/peeter-tomberg/requirejs (in cloud9ide).
To build your modules into a single app, all you have to do is have requirejs npm package installed and run the command: r.js -o build/build.properties.js
If there are any questions, ask away.
Edit:
In development, having all modules in separate files is just a good way to structure and manage your code. It also helps you in debugging (e.g. error on "Module.js line 17" instead of "scripts.js line 5373").
For production, you should use the build tool to concat and uglify the javascript into a single file. This will help the page load quicker as you are making less requests. Every request you make to load something slows down your page. The slower your page, the less points Google gives you. The slower the page, the more frustrated your users will be. The slower your page, the less sales you will get.
If you wish to read more about web page performance, look at http://developer.yahoo.com/performance/rules.html

Categories