There are a few different „traditional” ways of lazy loading of images. They all require JavaScript needing to figure out if an image is currently visible within the browser’s viewport or not. Traditional approaches might be:
Listening to scroll and resize events on the window
Using a timer like setInterval
Both of these have performance problems.
Why traditional approaches are not performant?
Both of those approaches listed above are problematic because they workrepeatedly and their function triggers **forced layout while calculating the position of the element with respect to the viewport, to check if the element is inside the viewport or not.
To combat these performance problems, some libraries throttle the function calls that do these things, limiting the number of times they are done.
Even then, repeated layout/reflow triggering operations consume precious time while a user interacts with the site and induces „junk” (that sluggish feeling when interacting with a site that nobody likes).
There is another approach we could use, that makes use of a new browser API designed specifically to help us with things like lazy loading: the Intersection Observer API.
That’s exactly what my own library, Lozad.js, uses.
What makes Lozad.js performant?
Intersection Observers are the main ingredient. They allow registration of callback functions which get called when a monitored element enters or exits another element (or the viewport itself).
While Intersection Observers don’t provide the exact pixels which overlap, they allow listening to events that allow us to watch if elements enter other elements by X% (configurable), then the callback gets fired. That is exactly our use case when using Intersection Observers for lazy loading.
Quick facts about Lozad.js
Light-weight: just 535 bytes minified & gzipped
No dependencies
Uses the IntersectionObserver API
Allows lazy loading of dynamically added elements as well (not just images), though a custom load function
In your HTML, add a class to any image you wish to lazy load. The class can be changed via configuration, but „lozad” is the default.
<img class="lozad" data-src="image.png">
Also note we’ve removed the src attribute of the image and replaced it with data-src. This prevents the image from being loaded before the JavaScript executes and determines it should be. It’s up to you to consider the implications there. With this HTML, images won’t be shown at all until JavaScript executes. Nor will they be shown in contexts like RSS or other syndication. You may want to filter your HTML to only use this markup pattern when shown on your own website, and not elsewhere.
In JavaScript, initialize Lozad library with the options:
const observer = lozad(); // lazy loads elements with default selector as ".lozad"
observer.observe();
Read here about the complete list of options available in Lozad.js API.
There is a natural connection between Data Visualization (dataviz) and SVG. SVG is a graphics format based on geometry and geometry is exactly what is needed to visually display data in compelling and accurate ways.
SVG has got the „visualization” part, but SVG is more declarative than programmatic. To write code that digests data and turns it into SVG visualizations, that’s well suited for JavaScript. Typically, that means D3.js („Data-Driven Documents”), which is great at pairing data and SVG.
You know what else is good at dealing with data? React.
The data that powers dataviz is commonly JSON, and „state” in React is JSON. Feed that JSON data to React component as state, and it will have access to all of it as it renders, and notably, will re-render when that state changes.
React + D3 + SVG = Pretty good for dataviz
I think that idea has been in the water the last few years. Fraser Xu was talking about it a few years ago:
I like using React because everything I use is a component, that can be any component writen by myself in the project or 3rd party by awesome people on NPM. When we want to use it, just import or require it, and then pass in the data, and we get the visualization result.
That components thing is a big deal. I’ve recently come across some really good libraries smooshing React + D3 together, in the form of components. So instead of you leveraging these libraries, but essentially still hand-rolling the actual dataviz components together, they provide a bunch of components that are ready to be fed data and rendered.
Victory is a set of modular charting components for React and React Native. Victory makes it easy to get started without sacrificing flexibility. Create one of a kind data visualizations with fully customizable styles and behaviors. Victory uses the same API for web and React Native applications for easy cross-platform charting.
Philip Walton suggests making two copies of your production JavaScript. Easy enough to do with a Babel-based build process.
<!-- Browsers with ES module support load this file. -->
<script type="module" src="main.js"></script>
<!-- Older browsers load this file (and module-supporting -->
<!-- browsers know *not* to load this file). -->
<script nomodule src="main-legacy.js"></script>
He put together a demo project for it all and you’re looking at 50% file size savings. I would think there would be other speed improvements as well, by using modern JavaScript methods directly.
You’re a developer working on a „large JavaScript application” and you’ve noticed some issues on your project. New team members struggle to find where everything is located. Debugging issues is difficult when you have to load the entire app to test one component. There aren’t clean API boundaries between your components, so their implementation details bleed one into the next. Updating your dependencies seems like a scary task, so your app doesn’t take advantage of the latest upgrades available to you.
One of the key realizations we made at Bitovi was that „the secret to building large apps is to never build large apps.” When you break your app into smaller components, you can more easily test them and assemble them into your larger app. We follow what we call the „modlet” workflow, which promotes building each of your components as their own mini apps, with their own demos, documentation, and tests.
Article Series:
The Key to Building Large JavaScript Apps: The Modlet Workflow (You are here!)
Improve Your Development Workflow with StealJS (Coming soon!)
Following this pattern will:
Ease the on-boarding process for new developers
Help keep your components’ docs and tests updated
Improve your debugging and testing workflow
Enforce good API design and separation of concerns
Make upgrades and migrations easier
Let’s talk about each of these benefits one by one to see how the modlet workflow can help your development team be more effective.
Ease the onboarding process for new developers
When a new developer starts on your project, they might be intimidated by the amount of files in your app’s repository. If the files are organized by type (e.g. a CSS folder, a JS folder, etc.), then they’re going to be searching across multiple folders to find all the files related to a single component.
The first step to following the modlet workflow is to create folders for each of your components. Each folder, or modlet, should contain all of the files for that component so anyone on your team can find the files they need to understand and develop the component, without having to search the entire project.
Additionally, we build modlets as their own mini apps by including at least the following files in their folders:
The main source files (JavaScript, stylesheets, templates, etc.)
A test JavaScript file
A markdown or text file for docs (if they’re not inline with your code)
A test HTML page
A demo HTML page
Those last two files are crucial to following the modlet workflow. First, the test HTML page is for loading just the component’s tests in your browser; second, the demo HTML page lets you see just that component in your browser without loading the entire app.
Improve your debugging and testing workflow
Creating demo and test HTML pages for each component might seem like overkill, but they will bring some great improvements to your development workflow.
The demo HTML page:
Lets you quickly see just that component without loading the entire app
Gives you a starting place for reproducing bugs (and reduces the surface area)
Offers you an opportunity to demo the component in multiple scenarios
That last item can be leveraged in a couple ways. I’ve worked on projects where we’ve:
Had multiple instances of the same component on a single page so we could see how it behaved in a few key scenarios
Made the demo page dynamic so we could play with dozens of variables to test a component
Last but not least, debugging issues will be easier because the component is isolated from the rest of the app. If you can reproduce the issue on the component’s demo page, you can focus your attention and not have to consider unrelated parts of your app.
The test HTML page gives you similar benefits to the demo HTML page. When you can run just a single component’s tests, you:
Don’t need to litter your test code with .only statements that will inevitably be forgotten and missed during code review
Can make changes to the component and focus on just that component’s tests before running the app’s entire test suite
Enforce good API design and separation of concerns
The modlet workflow also promotes good API design. By using each component in at least two places (in your app and on the demo page), you will:
Consider exactly what’s required by your component’s API
Set clear boundaries between your components and the rest of your app
If your component’s API is intuitive and frictionless, it’ll be painless to create a demo page for your component. If too much „bootstrapping” is required to use the component, or there isn’t a clean separation between the component and how it’s used, then you might reconsider how it’s architected.
With your component’s API clearly defined, you set yourself up for being able to take your component out of its original repository and make it available in other applications. If you work in a large company, a shared component library is really helpful for being able to quickly develop projects. The modlet workflow encourages you to do that because each of your components already has its own demos, docs, and tests!
Help keep your components’ docs and tests updated
A common issue I’ve seen on projects that don’t follow the modlet workflow is that docs and tests don’t get updated when the main source files change. When a team follows the modlet workflow, everyone knows where to look for each component’s docs and tests: they’re in the same folder as the component’s source code!
This makes it easier to identify missing docs and tests. Additionally, the files being in the same folder serve as a reminder to every developer on the team to update them when making changes to that component.
This is also helpful during code review. Most tools list files by their name, so when you’re reviewing changes for a component, you’re reminded to make sure the docs and tests were updated too. Additionally, flipping between the implementation and tests is way easier because they’ll be close to each other.
Make upgrades and migrations easier
Last but not least, following the modlet workflow can help you upgrade your app to new versions of your dependencies. Let’s consider an example!
A new major version of your JavaScript framework of choice is released and you’re tasked with migrating your app to the new version. If you’re following the modlet workflow, you can start your migration by updating the components that don’t use any of your other components:
The individual demo and test pages are crucial to making this upgrade. You can start by making the tests pass for your component, then double check it visually with your demo page.
Once those components work, you can start upgrading the components that depend on those:
You can follow this process until you get all of your app’s components working. Then, all that’s left is to test the actual app, which will be far less daunting because you know the individual components are working.
Large-scale migrations are easier when components are contained and well defined. As we discussed in an earlier section, the modlet workflow encourages clear API boundaries and separation of concerns, which makes it easier to test your components in isolation, making an entire app upgrade less intimidating.
Start using the modlet workflow in your app today
You can get started with the modlet workflow today—first, if your team is still organizing files by type, start grouping them by component instead. Move the test files to your component folders and add some HTML pages for demoing and testing your component. It might take your team a little bit of effort to transition, but it’ll be worth it in the long run.
Some of the suggestions in this article might seem intimidating because of limitations in your tooling. For example, if you use a module loader & bundler that requires you to create a separate bundle for each individual page, adding two HTML pages per component would require an intimidating amount of build configuration.
In the next article in this series, we’ll discuss how you can use a module loader and bundler called StealJS to load the dependencies for each of your components without a separate build for each HTML page.
Let me know what you think in the comments! If you follow a similar organization technique, then let me know what’s worked well and what hasn’t worked for you.
Article Series:
The Key to Building Large JavaScript Apps: The Modlet Workflow (You are here!)
Improve Your Development Workflow with StealJS (Coming soon!)
A lot of (web) developers use a local .dev TLD for their own development. … In those cases, if you browse to http://site.dev, you’ll be redirect[ed] to https://site.dev, the HTTPS variant.
That means your local development machine needs to;
Be able to serve HTTPs
Have self-signed certificates in place to handle that
Have that self-signed certificate added to your local trust store (you can’t dismiss self-signed certificates with HSTS, they need to be 'trusted’ by your computer)
This is probably generally A Good Thing™, but it is a little obnoxious to be forced into it on Chrome. They knew exactly what they were doing when they snatched up the .dev TLD. Isn’t HSTS based on the entire domain though, not just the TLD?
But what if we don’t really need React, or any other fairly-large-ish JavaScript framework?
What if the only thing we want is the ability to render HTML templates and also really efficiently re-render them when we need to, like React is known for?
As far as I understand it, that’s what projects like lit-html are for. As I write, it’s a pretty new library from Google and the Polymer folks.
It allows you to define an HTML template with regular template literals, like this:
And this is where lit-html shines. It’s smart enough to only update the parts of the DOM it needs to.
Here’s a little comparison where some data is changed, then the templates re-rendered. If we innerHTML the whole thing, well, the entire DOM is changed. With lit-html it just changes smaller inner parts.
Here’s a little video where you can see the DOM-updating difference:
lit-html on the left, „regular” on the right. Demo project.
There is another project along these lines too. I don’t know quite enough to judge, but it’s a bit older and I believe it’s a bit more robust. It’s called HyperHTML.
HyperHTML also allows you to create templates and render them. And most importantly rerender them efficiently.
Here’s a demo where the data comes from the Quotes on Design API and inserted into a template:
Kinda cool that these mini-libraries exist that do useful things for us, so when situations arise that we want a feature that a big library has, but don’t want to use the whole big library, we got smaller options.
This little website pulls in all the main stories from CNN and strips almost everything from the design; styles, images, fonts, ads, colors. Nada, zilch, gone. At first it looks like nothing but hypertext and it feels like an extraordinary improvement but Sam Saccone made a thread about potential improvements that the team could use to make that experience even faster such as server side rendering and replacing the React framework with something smaller, like Preact.
Either way this approach to news design is refreshing. However, I can’t find anything more about the the motivations for building this version of CNN.com besides the announcement on Twitter. It would certainly be fascinating to learn if CNN built this specifically for people caught in disastrous situations where battery life and load time might be a serious matter of life and death.
Because performance matters so much and there is so much opportunity to get clever with performance, we’ll see innovation in getting our code bases to production. Tools like webpack (tree shaking, code splitting) are already doing a lot here, but there is plenty of room to let automated tools work magic on how our code ultimately gets shipped to browsers.
Tom also says:
This is a loss in some ways (who else got their web development start with View Source?) but is a huge win for users, particularly in emerging markets.
It seems to me today’s world of GitHub, StackOverflow, and the proliferation of learning resources more than make up for learning via our own website spelunking, not to mention how insightful today’s DevTools are, even if what they are looking at isn’t hand-authored.