Thinking of your website design as a collection of loosely-coupled, independent components which can be placed anywhere, nested, and reused, is one of the most exciting developments in the practice of building for the web.
Component-based design systems are at the forefront of major leaps forward in the architecture used to enable agile, scalable codebases. Techniques such as “island architecture” and “hydration” have entered into the modern vernacular. We increasingly see the shift from “page-level” to “component-level” thinking as projects unfold.
Bridgetown provides three environments for writing components:
Use the Liquid template engine to write simple components without a lot of custom logic or for maximum compatibility with all template engines. Liquid components are not recommended when complexity is required for frontend logic.
Use a Ruby-based template engine in conjunction with a dedicated Ruby class to facilitate more comprehensive scenarios and take full advantage of Ruby’s feature set and object-oriented nature. Bridgetown also supports a compatibility shim for the ViewComponent library, a popular Rails extension created by GitHub.
Lit (Web Components) #
After installing the Lit Renderer plugin, you can write “hybrid” components which support both a backend lifecycle (during SSG & SSR) and a frontend lifecycle (via Hydration). This technique is recommended for components which must support a high degree of interactivity or data timeliness. You can also take full advantage of web component APIs such as the “shadow DOM” for encapsulated styling (meaning your component styles won’t “leak out” and accidentally effect other parts of the website).
So pick your flavor and dive in, or keep reading for more conceptual overview of Bridgetown’s component architecture.
New! Declarative Shadow DOM #
An emerging technology which has the potential to change how we approach development of layout and modular composition on the web is called Declarative Shadow DOM (DSD). Starting in Bridgetown 1.3, you can utilize DSD in your layouts and components for increased separation between presentation logic and content, scoped styles which won’t inadvertently affect other parts of the page (or other templates), and many other benefits. Check out our documentation on DSD for further details.
Here’s an example file structure showing all three environments in use:
. └── src └── _components ├── blog_entry.liquid ├── products │ ├── buy-now.lit.js │ ├── buying.rb │ ├── product-cart.lit.css │ └── product-cart.lit.js └── shared ├── navbar.erb ├── navbar.js ├── navbar.rb └── navbar.css
A rundown of the various component types:
- The “blog entry” component is a single
.liquidfile. Even though it only outputs HTML, we still call this a component because the none of the outside variables of any other template or component can be accessed or mutated. You must pass all necessary data into the component it needs to render content.
product-cartcomponents are both Lit-powered web components. The cart component uses a sidecar CSS file. There’s also a
Products::BuyingRuby component which serves as a “wrapper” to the buy now component.
Now let’s talk about the lifecycle of these components.
- The Liquid component’s lifecycle is static-only. The HTML is rendered out during the build process and that’s it.
Regarding that last item, due to various performance concerns both on the static-build/server-side and the client-side, it should be noted that you likely wouldn’t want pepper pages with dozens (or hundreds!) of Lit component renders. Instead you’d want to create what’s called an “island” within your page, using the
lit helper. You can read more about this on the Lit components page.
Ready to dive more into a particular component flavor? Let’s go!