🚗 Sidecar for a Code splitting
Tags: codesplitting, javascript, react
Published: 2019-05-06 12:36:50

---
title: 🚗 Sidecar for a Code splitting
published: true
description: A new way to vertical "interactivity" code spiting.
tags: code-splitting, javascript, react
cover_image: https://thepracticaldev.s3.amazonaws.com/i/u6v4df8p31bblr522x13.jpg
series: A split second later 
---
Code splitting. Code splitting is everywhere. However, why? Just because there is __too much of javascript__ nowadays, and not all are in use at the same point in time.

JS is a very _heavy_ thing. Not for your iPhone Xs or brand new i9 laptop, but for millions(probably billions) of _slower_ devices owners. Or, at least, for your watches.

So - JS is bad, but what would happen if we __just disable it__ - the problem would be gone... for some sites, and be gone "with sites" for the React-based ones. But anyway - there are sites, which could work without JS...  and there is something we should learn from them...

# Code splitting
Today we have two ways to go, two ways to make it better, or to not make it worse:

## 1. Write less code
That's the best thing you can do. While `React Hooks` are letting you ship a bit less code, and solutions like `Svelte` let you generate just less code than _usual_, that's not so easy to do. 

It's not only about the code, but also about _functionality_ - to keep code "compact" you have to keep it "compact". There is no way to keep application bundle small if it's doing so many things (and got shipped in 20 languages).

There are ways to write _short and sound_ code, and there are ways to write the opposite implementation - _the bloody enterprise_. And, you know, both are legit.

![](https://thepracticaldev.s3.amazonaws.com/i/owpecb2mbhg4bg2bck7s.png)

But the main issue - the code itself. A simple react application could easily bypass "recommended" 250kb. And you might spend a month optimizing it and make it smaller. "Small" optimizations are well documented and quite useful - just get `bundle-analyzer` with `size-limit` and get back in shape.
There are many libraries, which fight for every byte, trying to keep you in your limits - [preact](https://preactjs.com/) and [storeon](https://github.com/storeon/storeon), to name a few.   

But our application is a bit beyond 200kb. It's closer to __100Mb__. Removing kilobytes makes no sense. Even removing megabytes makes no sense.

> After some moment it's impossible to keep your application small. It will grow bigger in time.

## 2. Ship less code
Alternatively, `code split`. In other words - __surrender__. Take your 100mb bundle, and make twenty 5mb bundles from it. Honestly - that's the only possible way to handle your application if it got big - create a pack of smaller apps from it.

> As long as we're discussing it, you may want to make sure you're up on the latest and greatest when it comes to React code-splitting in 2019. Or just read about some implementation details.

{% link https://dev.to/thekashey/react-code-splitting-in2019-3cmg %}

But there is one thing you should know right now: whatever option you choose, it's an implementation detail, while we are looking for something more reliable.

# The Truth about Code Splitting

The truth about code splitting is that it's nature is __TIME SEPARATION__. You are not just _splitting_ your code, you are splitting it in a way where you will __use__ as little as possible in a single point of time.

Just don't ship the code you don't need right now. Get rid of it.

![seee yaa](https://thepracticaldev.s3.amazonaws.com/i/5hh0jid2m3la0t8o5b2x.png)

Easy to say, hard to do. I have a few heavy, but not adequately split applications, where any page loads like 50% of everything. Sometimes `code splitting` becomes `code separation`, I mean - you may move the code to the different chunks, but still, use it all. Recall that _"Just don't ship the code you don't need right now"_,– I _needed_ 50% of the code, and that was the real problem.

> Sometimes just adding `import` here and there is not enough. Till it is not __time__ separation, but only __space__ separation - it does not matter at all.

There are 3 common ways to code split:
1. Just dynamic `import`. Barely used alone these days. It's more about issues with tracking a _state_.
2. `Lazy` Component, when you might postpone rendering and loading of a React Component. Probably 90% of "react code splitting" these days.
3. _Lazy_ `Library`, which is actually `.1`, but you will be given a library code via React render props. Implemented in [react-imported-component](https://github.com/theKashey/react-imported-component#library-level-code-splitting) and [loadable-components](https://www.smooth-code.com/open-source/loadable-components/docs/library-splitting/). Quite useful, but not well known.

## Component Level Code Splitting

This one is the most popular. As a per-route code splitting, or per-component code splitting. It's not so easy to do it and maintain good _perceptual results_ as a result. It's death from `Flash of Loading Content`.

The good techniques are:
- load `js chunk` and `data` for a route in parallel.
- use a `skeleton` to display something similar to the page before the page load (like Facebook).
- `prefetch` chunks, you may even use [guess-js](https://github.com/guess-js/guess) for a better prediction.
- use some delays, loading indicators, `animations` and `Suspense`(in the future) to soften transitions.

And, you know, that's all about _perceptual_ performance.

![](https://thepracticaldev.s3.amazonaws.com/i/4tl08n169vx1ziat7nhc.png)
> Image from [Improved UX with Ghost Elements](https://blog.angularindepth.com/https-medium-com-thomasburleson-animated-ghosts-bfc045a51fba)

# That doesn't sound good

You know, I could call myself an expert in code splitting - but I have my own failures.

Sometimes I could fail to reduce the bundle size. Sometimes I could fail to improve resulting performance, as long as `the _more_ code-splitting you are introducing - the more you spatially split your page - the more time you need to _reassemble_ your page back`*.  It's called a __loading waves__.
> * without SSR or pre-rendering. Proper SSR is a game-changer at this moment.

![loading waves](https://thepracticaldev.s3.amazonaws.com/i/evzfftae04h5t868xhyw.jpeg)

Last week I got two failures:
- I've lost in [one library comparison](https://github.com/mui-org/material-ui/issues/15450), as long as my library was better 😉, but MUCH bigger than another one. I have failed to __"1. Write less code"__. 
- optimize a small site, made in React by my wife. It was using route-based component splitting, but the `header` and `footer` were kept in the main bundle to make transitions more "acceptable". Just a few things, __tightly coupled__ with each other skyrocketed bundle side up to 320kb(before gzip). There was nothing important, and nothing I could really remove. __A death by a thousand cuts__. I have failed to __Ship less code__.

> `React-Dom` was 20%, `core-js` was 10%, `react-router`, `jsLingui`, `react-powerplug`... 20% of own code... We are already done.

![](https://thepracticaldev.s3.amazonaws.com/i/vxnjfmzn6z63o9qhdlg6.png)

## The solution

I've started to think about how to solve my problem, and why _common solutions_ are not working properly for my use case.

> What did I do? I've listed all crucial location, without which application would not work at all, and tried to understand why I have the rest.

It was a surprise me - the problem was in CSS. In vanilla CSS transition I've used for a smoother UI, and the way I implemented it. Long story short - an underlying DOM node has to exist before transition animation.

Here is the code
- a _control_ variable - `componentControl`, eventually would be set to something `DisplayData` should display.
- once value is set - `DisplayData` become visible, changing `className`, thus triggering fancy transition. Simultaneusly `FocusLock` become active making `DisplayData` a __modal__.
```js
<FocusLock
 enabled={componentControl.value} 
 // ^ initially it's "disabled". And when it's disabled - it's dead.
>
  {componentControl.value && <PageTitle title={componentControl.value.title}/>}
  // ^ it's does not exists. Dead-dead
  <DisplayData
    data={componentControl.value}
    visible={componentControl.value !== null}
    // ^ would change a className basing on visible state
  />
  // ^ that is just not visible, but EXISTS
</FocusLock>
```
I would like to code split this piece as a whole, but this is something I cannot do, due to two reasons:
1. the information should be visible immediately, once required, without any delay. A business requirement. So it's better not to code split __information__.
2. the information "skeleton" should exist before, to property handle CSS transition.

This problem could be partially solved using [CSSTransitionGroup](https://github.com/reactjs/react-transition-group) or [recondition](https://github.com/theKashey/recondition) - first create hidden, then apply a _visible_ classname - but, you know, fixing _one code_ adding _another code_ sounds weird, even if actually _enought_. I mean adding more code could help in removing even more code. But... but...

> There should be a better way!

TL;DR - there are two key points here:
- `DisplayData` has to be __mounted__, and exists in the DOM prior.
- `FocusLock` should also exist prior, to contain `DisplayData`, but it's __brains are not needed__ in the beginning.

---

So let's change our mental model

# Batman and Robin

Let assume that our code is Batman and Robin. Batman can handle most the bad guys, but when he can't, his sidekick Robin comes to the rescue..

> Once again Batman would engage the battle, Robin will arrive later.

This is Batman:
```diff
+<FocusLock
- enabled={componentControl.value} 
+>
-  {componentControl.value && <PageTitle title={componentControl.value.title}/>}
+  <DisplayData
+    data={componentControl.value}
+    visible={componentControl.value !== null}
+  />
+</FocusLock>
```

This is his sidekick, Robin::
```diff
-<FocusLock
+ enabled={componentControl.value} 
->
+  {componentControl.value && <PageTitle title={componentControl.value.title}/>}
-  <DisplayData
-    data={componentControl.value}
-    visible={componentControl.value !== null}
-  />
-</FocusLock>
```

Batman and Robin could form a _TEAM_, but they actually, are two different persons.

And don't forget - we are still talking about __code splitting__. And, in terms of code splitting, where is the sidekick? Where is Robin?

![Robin is in sidecar](https://thepracticaldev.s3.amazonaws.com/i/647ij80gvo56g2apw3tv.png)
> in a sidecar. Robin is waiting in a __sidecar chunk__.

# Sidecar

- `Batman` here is all visual stuff your customer must see as soon as possible. Ideally instantly.
- `Robin` here is all logic, and fancy interactive features, which may be available a second after, but not in the very beginning.

It would be better to call this a __vertical code splitting__ where code branches exist in a parallel, in opposite to a common __horizontal code splitting__ where code branches are _cut_.

- in [some lands](https://github.com/respond-framework/rudy), this trio was known as `replace reducer` or other ways to lazy load redux logic and side effects as they needed.
- in [some other lands](https://developers.facebook.com/videos/2019/building-the-new-facebookcom-with-react-graphql-and-relay/), it is known as `"3 Phased" code splitting`.

> It's just another separation of concerns, applicable only to cases, where you can defer loading some part of a component, but not another part.

![phase 3 code spliting](https://thepracticaldev.s3.amazonaws.com/i/96yww94ggedak03dphz4.jpeg)
> image from [Building the New facebook.com with React, GraphQL and Relay](https://developers.facebook.com/videos/2019/building-the-new-facebookcom-with-react-graphql-and-relay/), where `importForInteractions`, or `importAfter` __are the `sidecar`__.

And there is an __interesting__ observation - while `Batman` is more valuable for a customer, as long as it's something customer might _see_, he is always in shape (and has a secret abs)... While `Robin`, you know, he might be a bit _overweight_, and require much more bytes for living.

As a result - Batman alone is something much be bearable for a customer - he provides more value at a lower cost. You are my hero Bat!

## What could be moved to a sidecar:
- majority of `useEffect`, `componentDidMount` and friends.
- like all _Modal_ effects. Ie `focus` and `scroll` locks. You might first display a modal, and __only then__ make Modal _modal_, ie "lock" customer's attention.
- Custom `Selects` - they are naturally split into Batman(Input) and Robin(Dropdrown). Custom `Calendars` or any other UI component with displays another (the biggest and most complex) part or click/hover - are the same.
- Forms. Move all logic and validations to a sidecar, and block form submission until that logic is loaded. The customer could start filling the form, not knowing that it's only `Batman`.
- Some animations. A whole `react-spring` in my case.
- Some visual stuff. Like [Custom scrollbars](https://github.com/theKashey/React-stroller), which might display fancy scroll-bars a second later. 🤷‍♂️ Designers 🤷‍♂️

Also, don't forget - Every piece of code, offloaded to a sidecar, also offload things like core-js poly- and ponyfills, used by the removed code.

![batman and robin](https://thepracticaldev.s3.amazonaws.com/i/kknd3t392m1lbxiy7hro.jpg)

Code Splitting can be smarter than it is in our apps today. We must realize there is 2 kinds of _code_ to split: 1) visual aspects 2) interactive aspects. The latter can come a few moments later. `Sidecar` makes it seamless to split the two tasks, giving the _perception that everything loaded faster_. And it will.

## The oldest way to code split

While it may still not be quite clear when and what a `sidecar` is, I'll give a simple explanation: 

> `Sidecar` is __ALL YOUR SCRIPTS__. Sidecar is the way we _codesplit_ before all that frontend stuff we got today.

I am talking about Server Side Rendering(__SSR__), or just plain __HTML__, we all were used to just yesterday. `Sidecar` makes things as easy as they used to be when pages contained HTML and logic lived separately in embeddable external scripts (separation of concerns).

We had HTML, __plus__ CSS, __plus__ some scripts inlined, __plus__ the rest of the scripts extracted to a `.js` files.

`HTML`+`CSS`+`inlined-js` was `Batman`, while external scripts were `Robin`, and the site was able to function without Robin, and, honestly, partially without Batman (he will continue the fight with both legs(inlined scripts) broken). That was just yesterday, and many "non modern and cool" sites are the same today.

---

If your application supports SSR - try to __disable js__ and make it work without it. Then it would be clear what could be moved to a sidecar.
If your application is a client-side only SPA - try to imagine how it would work, if SSR existed.

> For example - [theurge.com](https://theurge.com/en-au/), written in React, is fully functional __without any js enabled__.

There is a lot of things you may offload to a sidecar. For example:
- comments. You might ship code to `display` comments, but not `answer`, as long as it might require more code(including WYSIWYG editor), which is not required initially. It's better to delay a _commenting box_, or even just hide code loading behind animation, than delay a whole page. 
- video player. Ship "video" without "controls". Load them a second later, the customer might try to interact with it.
- image gallery, like `slick`. It's not a big deal to __draw__ it, but much harder to animate and manage. It's clear what could be moved to a sidecar.

> Just think what is essential for your application, and what is not quite...

# Implementation details
## (DI) Component code splitting
The simplest form of `sidecar` is easy to implement - just move everything to a sub-component, you may code split using an "old" ways. It's almost a separation between Smart and Dumb components, but this time Smart is not _contaniting_ a Dumb one - it's opposite.
```js
const SmartComponent = React.lazy( () => import('./SmartComponent'));

class DumbComponent extends React.Component {
  render() {
    return (
      <React.Fragment>
       <SmartComponent ref={this} /> // <-- move smart one inside
       <TheActualMarkup />           // <-- the "real" stuff is here
      </React.Fragment>
  } 
}
```
That also requires moving _initialization_ code to a Dumb one, but you are still able to code-split the _heaviest_ part of a code.

> Can you see a `parallel` or `vertical` code-splitting pattern now?

## useSidecar
 [Building the New facebook.com with React, GraphQL and Relay](https://developers.facebook.com/videos/2019/building-the-new-facebookcom-with-react-graphql-and-relay/), I've already mentioned here, had a concept of `loadAfter` or `importForInteractivity`, which is quite alike sidecar concept.

In the same time, I would not recommend creating something like `useSidecar` as long you might intentionally try to use `hooks` inside, but code splitting in this form would break _rule of hooks_.

Please prefer a more declarative component way. And you might use `hooks` inside `SideCar` component.
```js
const Controller = React.lazy( () => import('./Controller'));
const DumbComponent = () => {
 const ref = useRef();
 const state = useState();
 
 return (
  <>
   <Controller componentRef={ref} state={state} />
   <TheRealStuff ref={ref} state={state[0]} />
  </>
 )
}
```
## Prefetching
Dont forget - you might use [loading priority hinting](https://medium.com/webpack/link-rel-prefetch-preload-in-webpack-51a52358f84c) to preload or prefetch `sidecar` and make it shipping more transparent and invisible.

Important stuff - prefetching scripts would load it via __network__, but not execute (and spend CPU) unless it actually required.

## SSR
Unlike _normal_ code-splitting, no special action is required for SSR. `Sidecar` might not be a part of the SSR process and not required before `hydration` step. It's could be postponed "by design".

Thus - feel free to use `React.lazy`(ideally something __without__ `Suspense`, you don't need any failback(loading) indicators here), or any other library, with, but better without SSR support to _skip_ sidecar chunks during SSR process.

# The bad parts
But there are a few bad parts of this idea

## Batman is not a production name
While `Batman`/`Robin` might be a good mind concept, and `sidecar` is a perfect match for the technology itself - there is no "good" name for the `maincar`. There is no such thing as a `maincar`, and obviously `Batman`, `Lonely Wolf`, `Solitude`, `Driver` and `Solo` shall not be used to name a non-a-sidecar part.

Facebook have used `display` and `interactivity`, and that might be the best option for all of us.

> If you have a good name for me - leave it in the comments

## Tree shaking
It's more about the separation of concerns from _bundler_ point of view. Let's imagine you have `Batman` and `Robin`. And `stuff.js`
```js
export * from `./batman.js`
export * from `./robin.js`
```
Then you might try _component based_ code splitting to implement a sidecar
```js
//main.js
import {batman} from './stuff.js'

const Robin = React.lazy( () => import('./sidecar.js'));

export const Component = () => (
  <>
   <Robin />  // sidecar
   <Batman /> // main content
  </>
)

// and sidecar.js... that's another chunk as long as we `import` it
import {robin} from './stuff.js'
.....
```
In short - the code above would work, but will not do "the job".
- if you are using only `batman` from `stuff.js` - tree shaking would keep only it.
- if you are using only `robin` from `stuff.js` - tree shaking would keep only it.
- __but__ if you are using both, even in different chunks - both will be bundled in a __first__ occurrence of `stuff.js`, ie the __main bundle__.

> Tree shaking is not code-splitting friendly. You have to separate concerns by files.

## Un-import
Another thing, forgotten by everybody, is the cost of javascript. It was quite common in the jQuery era, the era of `jsonp` payload to load the script(with `json` payload), get the payload, and __remove__ the script.

> Nowadays we all `import` script, and it will be forever imported, even if no longer needed.

As I said before - there is too much JS, and sooner or later, with _continuous navigation_ you will load all of it. We should find a way to un-import no longer need chunk, clearing all internal caches and freeing memory to make web more reliable, and not to crush application with out of memory exceptions.

Probably the ability to `un-import` (webpack [could do it](https://github.com/theKashey/wipeWebpackCache)) is one of the reasons we should stick with _component-based_ API, as long as it gives us an ability to handle `unmount`.

So far - ESM modules standards have nothing about stuff like this - nor about cache control, nor about reversing import action.

## Creating a sidecar-enabled Library

By today there is only one way to create a `sidecar`-enabled library:
- split your component into parts
- expose a `main` part and `connected` part(not to break API) via `index`
- expose a `sidecar` via a separated entry point.
- in the target code - import the `main` part and the `sidecar` - tree shaking should cut a `connected` part. 

This time tree shaking should work properly, and the only problem - is how to name the `main` part.
```js
//main.js
export const Main = ({sidecar, ...props}) => (
  <div>
    {sidecar} 
    ....
  </div>
);

// connected.js
import Main from './Component';
import Sidecar from './Sidecar';

export const Connected = props => (
  <Main
    sidecar={<Sidecar />}
    {...props}
  />
);

//index.js
export * from './Main';
export * from './Connected';

//sidecar.js
import * from './Sidecar';

// -------------------------

//your app BEFORE
import {Connected} from 'library'; //

// -------------------------

//your app AFTER, compare to `connected.js`
import {Main} from 'library';
const Sidecar = React.lazy(import( () => import('library/sidecar')));
// ^ all the difference ^

export SideConnected = props => (
  <Main
    sidecar={<Sidecar />}
    {...props}
  />
);

// ^ you will load only Main, Sidecar will arrive later.
```
Theoretically `dynamic import` could be used inside node_modules, making _assemble process_ more transparent.

> Anyway - it's nothing more than `children`/`slot` pattern, so common in React.

## The Final Form

With all the principles listed above the final `sidecar` form is:

```js
import {Main} from 'library';
const Sidecar = React.lazy(import(/* webpackPrefetch: true */ () => import('library/sidecar')));

export SideConnected = ({enabled, props}) => (
  <Main
    sidecar={enabled && <Sidecar />}
    {...props}
  />
);
```

It __prefetches__ sidecar chunk and uses not when component just "used", but when it used in a "active" form (if that form exists).

Without extraction of "active form" sidecar would improve Time-To-Render, separating it from Time-To-Interactive, keeping the second a bit delayed as long as "interactivity" would be loaded by `the main bundle` itself.

> This "a bit" could be a whole time required to load main chunk and render your application for the first time.

Keep in mind - extracting small "cars", required just after initial rendering could be not the best idea. In my case I was able to "extract" almost 70% of the code greatly improving Time-To-Render.

# The future

`Facebook` proved that the idea is right. If you haven't seen [that video]((https://developers.facebook.com/videos/2019/building-the-new-facebookcom-with-react-graphql-and-relay/)) - do it right now. I've just explained the same idea from a bit different angle (and started writing this article a week before F8 conference). 

Right now it requires some code changes to be applied to your codebase. It requires a more explicit separation of concerns to actually separate them, and let of codesplit not horizontally, but vertically, shipping _lesser_ code for a _bigger_ user experience.

`Sidecar`, probably, is the only way, except old school SSR, to handle BIG code bases. Last chance to ship a minimal amount of code, when you have a lot of it.

> It could make a BIG application smaller, and a SMALL application even smaller.

10 years ago the medium website was "ready" in 300ms, and was _really_ ready a few milliseconds after. Today seconds and even more than 10 seconds are the common numbers. What a shame.

Let's take a pause, and think - how we could solve the problem, and make UX great again...

![should vs could](https://thepracticaldev.s3.amazonaws.com/i/j2ux5xt0hrka9wuoz3iq.jpg)

# Overall
`sidecar` provides __time__ and/or __space__ separation. You can `import` all scripts you need a bit later... a bit later using dynamic import, or you can `require` them, when you need them. In the second time you will make things simpler, and more _synchornios_ but still be able to save some initial bundle starting time, deferring modules evaluation [example](https://github.com/theKashey/react-focus-on/blob/master/src/Combination.tsx#L5-L8).

```js
// time and space separation
const ImportSidecar = sidecar( () => import("./sidecar"));

export function ComponentCombination(props) {
  return (
    <ComponentUI
      {...props}
      sideCar={RequireSideCar}
    />
  );
}


// only time separation
const RequireSideCar = (props: any) => {
  const SideCar = require('./sidecar').default;
  return <SideCar {...props} />;
};

export function ComponentCombination(props) {
  return (
    <ComponentUI
      {...props}
      sideCar={RequireSideCar}
    />
  );
}
```

- 1. Component code splitting is a most powerful tool, giving you the ability to _completely_ split something, but it comes with a cost - you might not display anything except a blank page, or a _skeleton_ for a while. That's a horizontal separation.
- 2. Library code-splitting could help when component splitting would not. That's a horizontal separation.
- 3. Code, offloaded to a sidecar would complete the picture, and may let you provide a far better user experience. But would also require some engineering effort. That's a vertical separation.

__Let's have a conversation about this__.

## Stop! So what about the problems you tried to solve?

> [react-focus-lock](https://github.com/theKashey/react-focus-lock), [react-focus-on](https://github.com/theKashey/react-focus-on) and [react-remove-scroll](https://github.com/theKashey/react-remove-scroll) have implemeneted this pattern.

Well, that was only the first part. __We are in the endgame now__, it would take a few more weeks to write down the second part of this proposal. Meanwhile...

![](https://thepracticaldev.s3.amazonaws.com/i/kpjsy69niqycdo17kp4u.png)