Saturday, 7 April 2018

Custom building bootstrap and jQuery with webpack


When using bootstrap its always been simple to slim down the css by removing some '@imports' in your less or scss files. Getting rid of that extra bloat in js can be done in the same way thanks to webpack. If you're not familiar with webpack it packs js modules into common js assets. Each component of bootstrap and jQuery are split into modules, using webpack loaders we can import only the modules we are using.

The two loader we will need is amd-define-factory-patcher-loader for jQuery and rollup-loader. If you haven't don't already have the babel-loader we will need that too for bootstrap. A sample module config now looks like this.

....
module: {
    rules: [
        {
            test: /\\.js$/,
            use: [
                {loader: 'babel-loader', options: {presets: ['env']}},
                {loader: 'rollup-loader'},
                {loader: 'amd-define-factory-patcher-loader'},
            ]
        },
    ]
},
....

When bootstrap imports jQuery it uses the full version but doesn't use it all. To get around this we can use aliases to resolve 'jquery' to our built version, and 'jQuery' to the nodemodules version, notice the uppercase "Q" to define the two versions

resolve: {
    alias: {
        bootstrap: 'bootstrap/js/src',
        jQuery: 'node_modules/jquery',
        jquery: 'js/lib/jQuery.js'
    },
}

Our directory structure is now

app
├── js
│ ├── index.js
│ └── lib
│   ├── bootstrap.js
│   └── jQuery.js
└── node_moduels

In 'bootstrap.js' and 'jQuery.js' it now looks a lot more like our scss imports file where we can just comment put the modules we are not using. Just the same as I always do with the "jubotron" css component.

// app/js/lib/jQuery.js

// require('jQuery/src/ajax/jsonp');
// require('jQuery/src/ajax/load');
// require('jQuery/src/ajax/script');
// require('jQuery/src/ajax/xhr');
// require('jQuery/src/attributes');
// require('jQuery/src/callbacks');
// require('jQuery/src/core/ready');
// require('jQuery/src/deferred');
// require('jQuery/src/deferred/exceptionHook');
// require('jQuery/src/deprecated');
// require('jQuery/src/dimensions');
// require('jQuery/src/effects');
// require('jQuery/src/effects/animatedSelector');
// require('jQuery/src/event/ajax');
// require('jQuery/src/event/alias');
// require('jQuery/src/event/focusin');
// require('jQuery/src/exports/amd');
// require('jQuery/src/exports/global');
// require('jQuery/src/manipulation');
// require('jQuery/src/manipulation/_evalUrl');
// require('jQuery/src/offset');
// require('jQuery/src/queue');
// require('jQuery/src/queue/delay');
// require('jQuery/src/selector');
// require('jQuery/src/serialize');
// require('jQuery/src/wrap');

var jQuery = require('jQuery/src/core');
require('jQuery/src/ajax');
require('jQuery/src/attributes/classes');
require('jQuery/src/css');
require('jQuery/src/css/hiddenVisibleSelectors');
require('jQuery/src/data');
require('jQuery/src/event');
require('jQuery/src/event/trigger');
require('jQuery/src/traversing');

module.exports = jQuery;
// app/js/lib/bootstrap.js

// require('bootstrap/alert');
// require('bootstrap/carousel');
// require('bootstrap/dropdown');
// require('bootstrap/modal');
// require('bootstrap/popover');
// require('bootstrap/scrollspy');
// require('bootstrap/tab');
// require('bootstrap/tooltip');

require('bootstrap/button');
require('bootstrap/collapse');

Finally in our 'index.js' we can require out custom build of bootstrap and intern will only require the js modules we are actually using.

// app/js/index.js

require('./lib/bootstrap');

// code ...