Paulund
2018-06-09 #javascript

Using Webpack Code Splitting

In this tutorial we're going to investigate a webpack feature called code splitting.

Code splitting will allow you to reduce the size of your main JavaScript file by splitting it up into different files and lazy load these as and when they're required.

This is a very important feature when building a single page application as your JavaScript file could be very large, this means that your page will need to wait for this to downloaded before the page can be started.

Using code splitting you can split up your code into multiple files and only download the files your app needs to display the page. For example if you only use a component on a single page you don't need to load in that component on every page of your app, using code splitting Webpack can lazy load in that component only when it is needed.

To be able to load in script dynamically you'll need to use the Javascript feature of import but not the keyword as this is static, the function import().

First you'll need to install a babel plugin for dynamic import.

npm install babel-plugin-syntax-dynamic-import --save-dev

When this is installed you'll need to add a .babelrc file to the root of your project and add the following config.

{
    "presets": [
        "babel-preset-env"
    ],
    "plugins": [
        "babel-plugin-syntax-dynamic-import"
    ]
}

To import a file in Javascript it's very straightforward you simply use import Module from './location-of-module.js'.

With the import() syntax it will accept a single argument of what you want to import, this will return a promise that will allow you to resolve the module contents.

For example to use this to import a Vue component you will use the following syntax.

Vue.component('search', (resolve) => {
    import('./components/Search.vue')
      .then((Search) => {
        resolve(Search.default)
      })
  })

When you build your Javascript by using something like npm run dev you will see your normal main Javascript built plus there will be a new 0.js file.

DONE  Compiled successfully in 871ms

     Asset     Size  Chunks                    Chunk Names
      0.js  75.9.8 kB       0  [emitted]  [big]
/js/app.js   900.7 kB       1  [emitted]         /js/app

This 0.js file will consist of your search component and webpack will fetch this file only when the component needs to be displayed on your app.

Vue Single File Component

To use this with your Vue single file component the syntax is even easier you just need to use the import function where you define the component.

const app = new Vue({
    el: '#app',
    components: {
      Search: () => import('./components/Search.vue'),
    }
});

Using With vue-router

If you have a single page app that using Vue Router to define what components to display on the page you can still use code splitting with the same technique as above.

export function createRouter () {
  return new Router({
    mode: 'history',
    routes: [
      { path: '/', component: () => import('./components/Home.vue') },
      { path: '/item/:id', component: () => import('./components/Item.vue') }
    ]
  })
}

Changing The Public Path

One of the problems I found with using code splitting is that on different environments the JavaScript files were stored in a different location.

To solve this problem you can tell webpack where your public folder is located so you can change this per environment.

const ASSET_PATH = process.env.ASSET_PATH || '/';
mix.webpackConfig({
  output: {
    publicPath: ASSET_PATH
  }
})

Prefetch A Module

If you have a component that you're going to lazy load into your app, you can speed up browser processing by telling it to prefetch this file.

For example let's say you have a Login button that will pop-up with a Login modal, this Login modal could be in it's own component file and you can code split it out using the abve technique. When you define the action for the login modal you'll have it inside the login button component and import the login modal.

Using a webpack comment annotation you can tell webpack to prefetch this by using the following code.

import(/* webpackPrefetch: true */ "LoginModal");

Webpack will then automatically append <link rel="prefetch" href="login-modal.js"> into the head of the page which will tell the browser to prefetch this script as it will be needed if the user clicks on the login button.

Now you can use this functionality in your project to split up the code and automatically lazy load these components only when they're needed.