DEV Community

Natalia Venditto
Natalia Venditto

Posted on

2 1

Lazy-loading components (part II - Composites)

Welcome to Part II where we are going to speak about our first decoupling task, in this case, I chose the styles to be the first to be decoupled. We will do now do a more in-depth analysis of how to decide what is a common dependency and can be extracted to a package, and how to manage those dependencies.

Deciding what are common dependencies?

You will see that there are other architecture decisions deeply connected. The first question you will want to ask yourself is...

What is a component?

Let's propose a teaser as an example. What will the markup of a teaser look like? Traditionally a teaser displays an image, a title, and a subtitle, a description, and a link or button. It may also show tags, categories, social media likes, etc.

Let's propose a simple one with an image, a title and a button. If you were going to put it together, it would look something like this.

Disclaimer: This is a very simplified markup output. It's likely your components will include a lot of dynamic and configurable attributes.

<!--
This is the teaser monolithic.
All goes in one file, which prevents you from decoupling and reusing styles.
:(
-->
<div class="teaser__base teaser__align--center">
<div class="teaser__outerWrapper">
<div class="teaser__wrapper">
<img class="teaser__img" src="https://loremflickr.com/480/240" alt="random image"/>
</div>
<div class="teaser__wrapper">
<h2 class="teaser__hl">Teaser Headline</h2>
<button class="teaser__button">
<span class="teaser__buttonLabel">Click me!</span>
<span class="teaser__icon">
<!-- svg stuff would go here -->
</span>
</button>
</div>
</div>
</div>

Now if you want to style it, your CSS (we will be writing scss in these articles), would look something like this.

.teaser {
&__base {
display: inline-block;
padding: 30px 0;
border: 1px solid grey;
}
&__outerWrapper {
display: flex;
flex-direction: column;
padding: 0 15px;
}
&__wrapper {
padding: 0 15px;
}
&__hl {
padding: 10px 0;
font: normal bold 25px sans-serif;
}
&__button {
font: normal 18px sans-serif;
margin-top: 10px;
min-width: 130px;
cursor: pointer;
height: 30px;
border: 2px solid red;
background-color: red;
color: white;
&:hover,
&:focus {
border: 1px solid red;
color: red;
background-color: white;
}
}
&__img {
width: 100%;
height: auto;
}
}

You can see it here too: https://codepen.io/frontendnat/pen/zYvYoWX

But look at it, and think about it. Particularly when you're working with a strict design system or guidelines, (that's always the case in enterprise applications, but also products and even smaller apps developed by professionals), it is likely that all buttons in your app, will look the same. At least you will have a set of them, all looking alike.

Your headlines will also respond to certain UI/UX rules, in order to organize content efficiently and help with accessibility optimization.

Your images will all be responsive in the same way, so they will probably have global constraints all alike.

If you style your button, your image, and your headlines every time in each of the components stylesheets, you will end up with a lot of code repetition! So it won't matter if you lazyload each component independently...you will have a lot of code over and over

That is extremely unnecessary! Let alone hard to maintain: let's suppose the design changes, you will have to change definitions multiple times, once per component!

It will also be a lot more difficult to reuse code on a different platform or even tenant. The number of changes to be made would make it impracticable.

Helper classes

Now you may say, ok, you can delegate those styles to helper classes. That's correct. You may. But then you will have a lot of non-corresponding classes in the markup of your component. And a lot of backend/template logic, to make those classes dynamic.

When we're talking of multi-tenant architectures. Where components markup is shared by different tenants, this pattern is very difficult to maintain.

I propose you explore, a different solution...

Split and composite

If you think about it, the teaser is not a feature in itself. It's more like a container. The actual features are the members that compose it. In our example, the image, the title, and the button.

The teaser container

<!-- This is just the dynamic wrapper of the teaser -->
<div class="teaser__base">
<!-- I added an additional wrapper to have more room for maneuver. We can now create different layouts using flexbox -->
<div class="teaser__outerWrapper">
<div class="teaser__wrapper"></div>
<div class="teaser__wrapper"></div>
</div>
</div>
view raw teaser.html hosted with ❤ by GitHub

The image

<!-- This is the markup output -->
<picture class="picture__base">
<source srcset="image-cropped?witdh=480" media="(min-width: 480px)">
<source srcset="image-cropped?witdh=768" media="(min-width: 768px)">
<source srcset="image-cropped?witdh=1024" media="(min-width: 1024px)">
<img class="picture__img" src="cropped?witdh=480.png" alt="image-alt">
</picture>
view raw image.html hosted with ❤ by GitHub

The headline

<!-- This headline should be dinamic, so you can choose the hN, as appropriate -->
<h2 class="title__hl">
<span class="title__title">Some title here</span>
</hl>
view raw title.html hosted with ❤ by GitHub

The button

<!--
Let's describe a button with their respective css classes, in BEM
This is the output, you probably have a framework of some sort, dnamically outputting this
particularly the svg icon.
We are not reflecting accesibility labels or other attributes.
-->
<button class="button__base" type="button">
<span class="button__label">Click me!</span>
<svg class="button__icon icon-class">
<use xlink:href="#icon-class"></use>
</svg>
</button>
view raw button.html hosted with ❤ by GitHub

So now you have identified components you may be using over and over, and decided to create composites out of them.

Now you can reuse your button anywhere you need it by importing its markup and configurations, and that means you can also extract and reuse its common styles.

Again, why not helper classes or atomic classes?

Let's elaborate a bit more on why this solution may not be so efficient.
First of all, if you put together a set of helper classes, *you will need to import them to be concatenated with the output you ship to the client. All of it. *

In a dynamic environment like an enterprise CMS, for example, it is unlikely you need all those classes on every page since pages have different sets of components. But you will still be sending all that CSS to the user, which plays against your site's performance and the user's data quota.

What you need to do is transform common definitions into abstracts!

Read the next part, to learn more about abstracts, how you write them, and how you import them!

Top comments (0)

Cloudinary image

Optimize, customize, deliver, manage and analyze your images.

Remove background in all your web images at the same time, use outpainting to expand images with matching content, remove objects via open-set object detection and fill, recolor, crop, resize... Discover these and hundreds more ways to manage your web images and videos on a scale.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay