Replies: 2 comments 1 reply
-
Something to consider with the web components is deciding what's worth converting from our current design system. For instance, we have a Button component, but does it really make sense to build a This is where CDN CSS + web components will really shine imo. If we can pare down our UI library to creating more complex UI web components and documenting how to style native components, it reduces bundle size even more because we're leveraging what the browser already offers. |
Beta Was this translation helpful? Give feedback.
-
Another thing I've gone back and forth on is whether we want to provide an option for requesting JavaScript from the CDN component-by-component. Downsides right now are...
|
Beta Was this translation helpful? Give feedback.
-
Problem
Websites built with React require a baseline amount of JavaScript code in order to run. This is code that is part of the React framework itself. All frontend frameworks have this overhead, but how much varies from framework to framework. For applications that don't already use React, adding our React-based component library also means adding the React framework, which isn't ideal for performance. Every bit of JavaScript an application uses has to be shipped over networks to our end-users' browsers. The larger the payload, the slower it loads. If we could reduce this overhead, it would not only reduce friction for non-React products wanting to adopt our design-system component library, but it could also shrink the bundle size for existing React applications.
Solution
Results of discovery
The Preact library is a smaller alternative to React that claims to be fully compatible with React. We explored with a prototype whether it's feasible to convert our React components to Preact components to achieve smaller bundle sizes and still allow teams to use React if they wish.
Through prototyping, we found that we can actually keep our components as they are now and swap React for Preact at build time to achieve the same end. We can generate a Preact version of the JavaScript bundle distributed through the CDN and of the JavaScript modules distributed through our npm package. We can use Preact in our Storybook stories. We can use Preact in our unit tests. And all those things can be done without changing our component source code. A bonus discovery was that we could repackage these Preact components as web components with relatively little effort. Each web component will require some thought and care to craft an ergonomic API because HTML attributes do not have the same capabilities as React/Preact "props", but we can at least use the same underlying components. Overall, we're convinced that it's both feasible and profitable to start offering Preact components.
Before moving on, I want to share the numbers. Our CDN bundle contains all of our components, which is a sizeable amount of JavaScript. The React framework is only a fraction of the total bundle size. That being said, switching to Preact saves us 92 kilobytes of data uncompressed (34 kilobytes gzipped) or about 16% of the total bundle size.
Take a look at the Preact discovery branch for working Preact examples using our design system.
Moving forward
The discovery went well, but how do we move forward with implementation? There are a few questions that need to be addressed in an implementation plan like, how will we organize and distribute these different versions of our libraries? how will teams use them? and what's our rollout strategy for web components?
Organizing our packages
Because each package—whether we consolidate the packages or continue to have child design system packages—now has ES5/CJS files, ES Modules, and a bundle for each of React, Preact, and possibly web components, we're going to need to organize the
dist
differently. Here's what we had before:with a mapping in our
package.json
that looked like this:For more information about how those mappings work and what they're there for, take a look at the following documentation and examples:
If we plan to distribute our library for three frameworks for multiple build and runtime environments, we'll want to keep it organized and easy for teams to specify the right version. These are the kind of import statements I envision us having:
Under the hood, we can have the following directory structure and package config:
My reason for including all of the above is to illustrate that we can build many permutations of our library while still providing a simple and straightforward interface to access them. A product team's build system will find the appropriate format of the code assets within a certain framework that a team will specify with their import statements. Each design system library would be structured in this fashion; however, another option to consider at this time is consolidating our design system packages into the core
@cmsgov/design-system
package.How teams can make use of our new offerings
One of the reasons we're exploring Preact specifically is because we can continue to innovate without disrupting our existing React users. I actually like React a lot, and I think it helps people build maintainable applications. Preact has the potential to give us web components, which would improve the developer experience for a subset of our users. They are easy to use in other frameworks or with no framework at all. However, Sarah made an important point once that accessibility-wise a move to web components is more of a lateral move than an upward one, and sometimes it can actually be a downgrade for accessibility. We don't want to go backwards. We want to move forwards and provide the best tools we can for teams on a variety of tech stacks to deliver high-quality experiences for everyone. We want to give our users options instead of simply migrating from one framework to another, and we want to do so without adding a completely new component library that we have to maintain alongside our own one.
Strategy for rolling out web components
It's going to take some time to go through our components and intentionally craft web component interfaces for them. Like I mentioned in the discovery results overview, HTML attributes do not have the same capabilities as React/Preact "props", and web components are simply custom HTML elements. For instance, we often pass things like functions, arrays, and booleans to our React components, but HTML attributes are all strings. That means that if we want to accept these more complex properties, we need to create some alternate interface for those properties and translate them into props for our React components. That process takes time and intentionality.
In my experience, things like this are best rolled out incrementally. We can release a few components and then get feedback that will inform how we handle the rest of the components. Right now we distribute one bundle for all our React components. First we'll want to start building a bundle for each framework. Because our React users are more likely to work within the npm ecosystem, it's unclear whether the React bundle would still be needed if we have a lighter-weight Preact bundle. The web-components bundle can start off with only a few components, and we'll add them as we make them.
Conclusion
Updating our build system and other tooling to support Preact with our existing React components would be an easy performance win. Additionally, Preact provides a clear path to offering a library of web-components alongside our current offerings. Overall, it's a good move for our design system.
Beta Was this translation helpful? Give feedback.
All reactions