 All right, let's get started. Everybody, this is front-end architecture for scalable design systems. Just a quick note before we get started, if anyone would like to download a copy of today's slides or just wanted to follow along, check out the bit.ly URL up on the screen, bit.ly slash bolt design system. Also, I know this year's triple con sessions are quite a bit shorter than normal, so given the amount of material we're trying to cover today, if anyone had any questions or feedback and doesn't get a chance to actually ask that during today's session, please hit me up on Twitter and I'd be happy to have a chat with you. Now then, let's dive right in. Let's get into the nuts and bolts of scalable design system architecture. AKA, how do you build the progressively decoupled external design system that has more maintainable documentation, allows components to be individually installed, works with other frameworks out there, things like Vue.js or React, and partially automates how twig templates get integrated, all of this while still being Drupal and Pattern Lab friendly. In 30 minutes or less. I'm Salem Gowary, I'm lead front-end architect at Pegasystems based out of Cambridge, Massachusetts. I've been working in the front-end dev space for the past seven plus years, the last four plus of which have been almost exclusively focused on building design systems and pattern libraries. Oh, this is the first Drupal kind I've ever spoken at. Thank you. Um, thanks. I'm also one of the core Pattern Lab PHP and Pattern Lab node contributors, where more recently I've been focusing on getting PHP based twig components working in Pattern Lab node. And if anyone's really interested in that, you should totally check out Evan Loveli's definitive guide to Pattern Lab session later today. One thing in particular to kind of call out is the Pattern Lab UI modernization project. It's something I'm really excited about. If this sort of thing interests you, come chat later at the Pattern Lab buff we have going on. Mostly for the past three years plus, I've been working on the Bolt design system. It's our open source pattern lab based system we've been using internally for around two years now to power most of our internal Drupal sites. We'll be chatting about Bolt in just a little bit, but first we kind of need to set the stage on how we got here. When I first came to PEGA three years ago, the front end code on our Drupal sites wasn't great. So like many teams, large and small, we used some of the best tools and techniques out there, tools like Pattern Lab to build their very first Drupal friendly design system. And you know what? It was pretty good. We implemented tons of best practices for the time, things like inline SVG icons and asynchronous font loading. We used approaches like Atomic Design and its CSS, inverted triangle CSS for a CSS architecture. And we took advantage of some of the best tools out there, things like Webpack, Gulp, SAS, and of course, Pattern Lab. We even managed to implement virtually every best practice out there, everything that the Drupal cons of yesteryear have talked about. All those best practices for building a Drupal friendly Pattern Lab integrated design system. Things like building your components straight inside of Pattern Lab and mapping them back to Drupal via the components module. We documented our components via component demos that lived in Pattern Lab, in addition to using markdown to document best practices and usage. We even had our design system partially decoupled from Drupal itself by having our front end code live as an external Git repo that was then pulled into Drupal via Composer. And keep in mind, this was three years ago. So needless to say, a lot of our Drupal sites use this. And for a while, things were great. Unfortunately, as we found out the hard way, our first design system started to have some problems, major scalability problems. For starters, we had problems related to poor documentation with questions being asked like, how come these component docs are out of date? Or what data should I pass along to this particular component? We had problems related to how the design systems code was published and then pulled into Drupal. Problems like teams needing to pull in just one component's updates, but we're really not able to pull in either everything or none of them. Effectively, a one-size-fits-all solution. We kept hitting issues related to component fragmentation. Once things were shipped and getting used outside of Drupal, out in the real world, components were getting hard-coded. Components were getting hacked together. Components were getting forked without us even knowing about it. And finally, on top of all this, we had issues with our integration process. They were fragile. Sure, we were using the components module in Drupal, but we found out that if you change, say, a component's folder name and pattern lab, just rename it so that your front-end code is a little bit more tidy, well, things can unexpectedly break unbeknownst to you in Drupal. Unfortunately, this fragmentation problem we had got so bad, like one of our Drupal sites ended up getting stuck on using the first version of our design system from the very beginning on half the pages, and then the other half getting stuck using the latest version of the design system on the other half of the pages. At that point, we realized that our first design system for all intents and purposes was dead, so we rebuilt. We picked up the pieces from our first system, we scrubbed off the dirt, and we gave it another go. Only this time, we had to address directly the main problems that tore our first design system apart. Scalable design systems need to solve two main problems. You have the maintainability problem. How do you systematically maintain your components, supporting them, documenting them, and improving them over time? And this includes things like fixing bugs, getting testing coverage, refactoring, new enhancements, et cetera. Also, how do you do a fragmentation? The design systems code, this collection of components, visual styles, tooling, et cetera, it's only useful if other teams out there, developers, designers, and content authors are using these things. Once you've shipped your code out into the real world, how do you ensure that that code doesn't start to fall apart at the seams over time? Because as we found out, if you can't update, your system is pretty much screwed. So when it came time to reboot and create Bolt, I think Drew's actually gave us a quick little shout out this morning with the video, we had four main goals that we needed to figure out. And keep in mind, this is for us, but these can be applied to any design system, any team out there. The first of these goals that we came up with was make documentation easy to update and easy to maintain. Second, components need to be rugged, flexible, and encapsulated, at least enough for the real world usage. Third, our design systems code really cannot be a one-size-fits-all solution. Your code needs to be installable a la carte, so picking and choosing the individual pieces a developer downstream wants to pull in in order to make sure we have maximum flexibility for the developers using the design system. And finally, triple integrations need to be automated and as easily as humanly possible. Hard coding each individual template's path multiple times even just doesn't scale. And goals are great, but practically we need to be able to actually solve these with real world examples. And for starters, let's talk about API documentation, specifically API powered documentation. Step one, make your code be exportable, friendly to exporting essentially. For example, anyone here use SAS? We do too. So we're using a SAS map here on the right. We're just structuring our color palette to be a single kind of group of data related to colors. Step two, export that data. So we use Webpack for a build process, but there's many tools out there that do the same essential thing. We have a custom function that we added to SAS when things are compiling to take this structured data in our code and spit out a JSON file with all the color palette related information all there. Step three, teach other systems about your design system. For example, and don't worry about so much the specifics, this is just more the gist of the code. We realize that if we could teach Twig, not Drupal, not Pattern Lab, Twig, this is where our data lives. Not just color palette data, but all the data. Well then, if Twig could just look there, grab your data and make it globally available, then we can do things like this. We can have automatically generated, always up to date, evergreen color palette documentation that's never going to become obsolete. We can also do really cool things like this. This is actually an automatically generated accessibility check that we have built right into our code that goes through all of our color palette swatches and make sure that the text on top of that particular swatch color is accessible, large text, small text, dark text, light text. And again, no one has to maintain this because this is always wired up to the source of truth. Next up, let's talk about schemas. Anyone here know what schemas are? Okay, put your hands over yours for the rest of everyone else. Schemas essentially are a set of rules to power your components. The rules that both humans and computers can understand. Schemas allow certain things to be required in a particular component or optional. They allow you to set up maybe default configurations if no one passes the long data or they can set up a required list of items you need to pick either option one, option two, or option three that's predefined. How do you do it? Well, for starters, you write schemas, crazy. You write your schemas for your components, like the button component in that previous example. And with most systems out there having quite a number of different components, step two really is aggregating that data to make it easy to just pull in it all at once. You might have 30, 40, 100 components and having each component constantly getting this re-require of data can become a little bit troublesome with performance. So we figured glob it all together into one single chunk of data and our webpack build process actually does this just automatically with every build. And then like we went through with the first example, Twig automatically pulls in any of the data in a particular folder. So same idea here, our schema data, our aggregated schema data, just gets pulled into Twig globally without having to do any extra work. Next, we need to make sure that systems like Twig can understand the schema data that's available. So for example, we actually use one of the libraries from Basalt, one of our agencies we partner with to automatically, not automatically, but we teach Twig how to actually interpret and understand schema data. So this allows us to do things like pull in the data, validate it at that Twig template level, maybe add defaults to that data that's getting pulled in. Just basically teach your system the rules on how to deal with this type of thing. And keep in mind this also applies to other languages as well. This isn't a Twig specific thing. So JavaScript, same idea. Add a library to help validate and interpret schemas, and then you can have the schema data apply to your JavaScript powered components as well. Once your component schemas are all wired up, you can start to do some really powerful things like this as an example. Most of our demos in Pattern Lab are automatically generated. You update, say, the button components size options that are available, and your documentation in Pattern Lab automatically stays up to date. For developers, and I know it's a little hard to see the outline here, but we have tables. We have tables of our different component API options for developers, designers, and content authors. So anyone who's looking at our Pattern Lab pages, our Pattern Lab docs, knows these are the available options for a component. Here's what's required, here's what's not. Here are the available options. Automatically up to date. You can also do really powerful things like this outside of Twig, where we're actually, these are just tests. If anyone's familiar with the React, heavy but not React exclusive testing library, Jest. We actually have our Twig templates being rendered in a Jest test and use those same schemas to go through each option when running our tests. Same thing, you update the options available for, say, our button component. Your tests themselves will automatically be up to date with the things to check for. And I mentioned this before, but it's worth pointing out. Schema validation is really powerful and really important. It allows you, say, in the command line to know when a particular option is required but isn't getting passed along. Or even in Drupal, you could actually kind of bark out at the console when a particular component isn't meeting its own end of the bargain here. It isn't actually meeting your validation rules. And we can also do some really cool things with this idea of component-based schemas. This is using the Mozilla React.JSON schema form library on NPM. And essentially it looks at the schema data, it automatically generates our form UI and then whenever you go in the browser and update the form field data, it does a request to our Twig rendering service that we have under the hood, returns back HTML that we just put right back in the browser. Basically real-time in-browser component editing, even for components that don't normally support this. Really, you could think of schemas as this super-powered type of documentation that can power anything from validation to testing, setting component defaults, generating component documentation, automatically generating a people-friendly preview of what the heck you should expect when pulling something into Drupal, and demos in Pattern Lab. Schemas are really this one source of truth to rule them all as far as documentation's concerned. Next up, let's talk about Twig and web component integration. Now, this is a short talk, so unfortunately we don't have enough time to go into all of the nitty-gritty details about web components. For that, I'd strongly recommend checking out one of the other Drupal con sessions this year on web components for a deeper dive. Or you can also swing by the bof I'm running tomorrow morning on web components as well. But I'll give you the quick high level. Web components are browser technologies, four of them specifically, to allow component-like behavior and functionality, the things that other frameworks out there like React, View, Angular have been doing for years, but with actual browser-specific first-class support. We have custom elements which allow custom HTML tags, things like bolt button or bolt icon that allow content authors and developers to very simply and very easily include a component and configure it without really requiring them to understand here's the build process, here's all this extra complex overhead. It's just simple HTML tags that just work. You have ShadowDom, which essentially is encapsulation with full browser support. This allows you to do things like take your HTML internally with your CSS classes, your styles themselves, kind of bake it right into the component. So from the outside, you might just have bolt-button, but from the inside, you actually have all of the internal structure hidden away so that it can't get accidentally updated and cause updates downstream from not coming in. You have HTML templates, which we don't actually use too much of. At least we don't. Our library that we use, Skate.js and lit.html, they'd use it. You could think of HTML templates as really a way to stamp out a component structure, the semantic HTML that gets used and allow for repeated use of that. And then you have ES modules. So think of sharing those component bits and pieces in between components. It lets you pull them in as a dependency. Now, I mentioned before that web components are not like a framework. They're actually an in-browser baked standard. And that means that you can use a framework if you want, things like View.js, React, Angular, Skate.js, oops, sorry, React, Angular, Preact, View. All of those kind of big players in the framework area, they all support web components natively. And then there's other libraries that are a little bit slimmer. Things like lit.html, Skate.js, which we use, lit.element, and stencil.js that are more like lightweight versions that get you the power of web components without requiring you to adopt the whole JavaScript framework in the process. And worth mentioning that JavaScript support for this, cross-browser support, rather, it's actually quite good. Chrome, Safari, and Firefox all natively support web components without any polyfills required. Edge requires maybe two polyfills. They're currently working on getting custom element and shadow DOM support right now, but with some extra polyfill libraries, you can get full support. And if you're like us and require IE11 support, polyfills can help you there too. We actually ship web component support across the board for all of our components. And we've been doing this for almost a year and a half, two years now. So with this approach, you get true component interoperability. You get all the power of modern JavaScript powered components in the browser while still having cross interoperability between different languages. Things like twig, HTML, JavaScript, all sharing one single source of truth from different angles. This allows you to package up your HTML for developers, designers, and content authors that can customize and use without interfering in design system updates and improvements from happening. Really quick, this is one of the other cool things that we've been figuring out. This is the idea of progressive rendering. So we have our twig template, our button component here, getting data passed along, text, URL, et cetera. The twig template spits out vanilla HTML with CSS classes baked right in so that if you turned off JavaScript in the browser, things still work, links still click, buttons still submit. But what we're doing here is actually setting up this initial HTML to be set up for the browser's JavaScript once things boot up. Then once the top right, there we go, this guy here. Once the JavaScript's booted up, because we've structured our HTML in a way to say keep this HTML, toss this one, this is important, this isn't, we can then kind of get back visually the starting point that we want without giving up on accessibility and progressive enhancement. Also worth mentioning, ShadowDom, so one of the four main pillars of web component tech. IE 11, we found out in practice, although we can get support with polyfills, there's a huge performance kind of penalty that we found we have to take. So what we decided was, okay, why don't we make all components optionally be ShadowDom renderable? That's what we have here. If you support ShadowDom either natively in the browser or if a component isn't specifically told not to use ShadowDom or a component's getting used in a finicky place that doesn't support ShadowDom easily, things like forms, you'll get full component encapsulation baked right into your markup. And then in modern browsers and older browsers, if you don't support ShadowDom or can't use it because of a third party library or an integration, you could just flip it off. You don't need to rewrite your template, you don't need to redo your logic. It's the single source of truth component templating that just works across the board. And finally, worth mentioning, this is also the same kind of tech that we're kind of experimenting with for things like Vue.js integration. So if you want to go headless, this could actually literally be the way the components get packaged up, but internally it's still using web components in Vue or whatever other library you want to use. All right, eight minutes, two more sections than what we've done. Number four, we need to rethink how we're actually publishing out our components and integrating into Drupal. Specifically, the old way of integrating our design system is broken. So monoreboats. Monoreboats are essentially a repository of different components, packages, libraries, et cetera, that are all related. Just one code base, all your code lives there. Some of the most popular JavaScript libraries and frameworks out there, things like Babel, Gatsby, Vue CLI, Storybook, these big players are actually using monorepos out in the wild. And believe it or not, I realized this only somewhat recently. Some of the bigger players in the PHP world, players like Symphony and Laravel, they're actually using the same exact monorepo idea. They're using different tools to split out those separate pieces, but it's the same approach. So what do you do this? Well, for starters, you have a more maintainable code base. It's easier to manage and share your dependencies between your different pieces. You can coordinate interrelated component updates and it allows you to unify your tooling and build process. Basically, all your different pieces live in one code base. You publish them to NPM and then you pull them in as pieces for consumers like Drupal to actually use and use and consume. I'm gonna go through how to do it in 20 seconds tops. Basically, there's great tools like Lerna that solve this main problem for you. We use Lerna plus yarn workspaces. You say here's where my components live. You tell it to publish and then it publishes to NPM. We realized that this also required us to rethink how we organize our code. So essentially we had to downgrade pattern lab. Instead of having pattern lab be the source of truth, pattern lab was actually just reflecting the demos of our source of truth. This essentially allows pattern lab to consume the pieces of our system the same way as Drupal or say, GravCMS or any other consumer of your design system would go about doing that. Components, build tools, config, everything that's gonna get published lives in one bucket of things and then everything else that gets published, that doesn't get published rather, your supporting code, things like your website, your documentation, your example integrations, all those internal things, those just live in a separate folder in your repo that doesn't get published for mass consumption. And finally, before you ask about it, we don't do this with our PHP specific dependencies. We only do this with our components, our tooling, really the very front end heavy things in our system. Things that are PHP specific, like the Drupal module that we have that I'll talk about in just a second, and our custom tweak extensions, those still get published out to packages automatically any time that we're doing a release. And finally, let's talk about integrations. Basically, with this approach that we've been taking for the past two years, you NPM install just the components that you need and you have built tools that take those components, tell Drupal about where they live, what the folder structure is, what their path is. And then in Drupal, you enable what components you wanna use. So you can NPM install the button, but then tell the button component, yes, I want to use this in my system. So you actually set up the build tools to switch on the things that you wanna use. And then we have this BoltConnect module on packages that really just takes, let the build tells it, it takes the path for your components, the dependencies, et cetera. And it just tells Drupal's Twig instance under the hood. Here's my source of truth. Here's where all my components live. Whenever component's path updates, Drupal now knows about them automatically because we're not teaching Drupal about the design system, we're teaching the systems in Drupal even deeper about the design system. So you list out the components you want and this is a package.json file, NPM install, puts them in the node modules folder inside of your Drupal theme code base. And this is the config I've mentioned briefly where now that you've NPM installed your components, they're living in your node modules folder, you list out which of those components you wanna actually enable. That tells the build process, go add these to our kind of manifest of all the different components to use. And that's pretty much it. Once you do that, internally, Drupal now knows every Twig namespace that you have, every custom Twig extension your system's using. It just works. And we have this Drupal lab example actually in the Bolt Design System code base, if you wanna check it out. This is really just a super, super simple 60 second pop up Drupal instance to show how with a few components you can get this approach up and running very quickly. So, I know we've covered a tremendous amount of material in such a short amount of time. We went through how schemas are this very powerful but easy to read way to essentially document your components, your rules, your options, your required fields, et cetera. We talked about how Twig enabled web components allow us to build more resilient, more rugged components for cross platform compatibility. We touched on progressively decoupling our system. So pattern lab and Drupal now are wired up to our source of truth at the same level. Next, we talked about how our design system is now getting into the decoupled realm where we publish out the pieces that we want to share to NPM and then downstream, consumers can pull in just the parts that they want. And finally, we automate the Twig namespaces and Twig extensions so we can further reduce frictions between Drupal and pattern lab and make this process a heck of a lot easier for everybody. Check us out on GitHub, bolt design system slash bolt. And if anyone has more questions or wants to pick my brain, Evan and Lovely and I, one of the other pattern lab maintainers, we have a design system pattern lab buff going on later today. And then first thing tomorrow morning, I have another buff specifically about web components. And check us out on boltdesignsystem.com. Thanks. Just quick shout out about Drupal Contributions on Friday and be sure to take the survey, let us know what you think. So think about it like this. Our first design system needs scale, but we still use most of the front end code. We just had to fix a lot of the other issues. So it's not so much the components, it's been like,