Skip to content
This repository was archived by the owner on May 22, 2023. It is now read-only.
This repository was archived by the owner on May 22, 2023. It is now read-only.

Add code splitting on page boundaries #35

Open
@jpommerening

Description

@jpommerening

TL;DR:
This adds the ?split option to laxar-loader to automatically create webpack chunks for each page.


I implemented a prototype the other day to enable webpack's bundle splitting at page boundaries.
For that I created a file that looked like this:

import definition from './application/flows/main.json';
import artifacts from 'laxar-loader/artifacts?theme=my-theme';

artifacts.aliases.flows.main = 0;
artifacts.flows = [ { descriptor: { name: 'main' }, definition } ];

proxy( 'pages', 'my-page', () => import( /* webpackChunkName: "my-page" */ 'laxar-loader/artifacts?page=my-page&theme=my-theme' ) );

function proxy( bucket, ref, fn ) {
   let index;
   Object.defineProperty( artifacts.aliases[ bucket ], ref, {
      get() {
         if( index === undefined ) {
            index = artifacts[ bucket ].length;
            artifacts[ bucket ][ index ] = fn()
               .then( makeSureTheRequestedRefIsPresentInTheBundle )
               .then( mergeTheReceivedBundleIntoArtifacts )
               .then( () => artifacts[ bucket ][ index ] ); // the promise we stored earlier has now been replaced with a plain JS object
         }
         return index;
      }
   } );
}

This is more-or-less what the loader now generates.
The proxy and merge functions have been moved to split-base.js and handle a few more edge cases and are structured in such a way that makes the calls easy to generate, while allowing to "proxy" more than one single ref with a call.

For example:

// we could generate this call:
proxy( artifacts, { pages: [ 'intro', 'home' ], flows: [ 'sub-flow' ] },
  () => import( /* webpackChunkName: "start" */ 'laxar-loader/artifacts?pages[]=intro&pages[]=home&flows[]=sub-flow' ) );

// … and webpack would split out the pages 'intro' and 'home' as well as everything referenced
// from them and from the flow 'sub-flow' into a chunk named 'start'

Usage:

  • Make sure you're using the right laxar-loader version:
    $ test -f "node_modules/laxar-loader/lib/split-base.js" && echo "ready to split!"
  • Make sure laxar-loader uses laxar-tooling@^2.0.3:
    $ grep "version.*2\.0\.[3-9]" "node_modules/laxar-loader/node_modules/laxar-tooling/package.json"
  • Just add ?split to your artifacts-bundle-import:
    import artifacts from 'laxar-loader/artifacts?flow=main&theme=app&split';
    //                                                                ^^^^^

This should work with any webpack version >= 2, but you get extra benefits from webpack 4+ because the new version is super clever when splitting code. It does, for example, identify common dependencies of some (but not all) chunks and splits them into a separate bundle that is imported when needed. To find out more about that, read this blog post.

Open for discussion:

We could customize the splitting strategy. Theoretically we could split the bundle at any artifact boundary. I guess pages make the most sense. Maybe we could allow the user to group pages into a single chunk? Perhaps by adding a property to the page description? Or a configuration option?

/cc @x1B @alex3683 @jonaswjs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions