Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Building component library with Docz and Lerna
Alex K.
Alex K.

Posted on • Edited on • Originally published atclaritydev.net

     

Building component library with Docz and Lerna

The article was originally posted onmy personal blog.

Component libraries are all the rage these days, with many companies rolling out their own solutions or sticking to a bunch of open source alternatives. Leveraging a component library for UI development, particularly in large teams, has a lot of cool benefits. It allows to take full advantage of modular and reusable UI components, which brings increased speed of development and unifies styles across multiple teams and apps. Combine that with a robust design system, and the handover from design to development teams becomes smooth and more efficient. 

Frameworks/libraries like React, Vue, etc are perfectly suited for this purpose since there are designed to be highly modular. In this post React and Styled components are used as main tools of choice for developing components.

There are also some helpful tools, that could be leveraged to speed up the development process and deployment of the library. Embracing the modular approach, it would make sense that each component would be an own npm package, the whole library being a monorepo. That's whereLerna will be used to manage multiple packages inside the project, as well as to keep track of their versioning and publishing process. 

In order to test and document the components, Docz is used (as an alternative toStorybook). It allows documenting components withMDX, which is a format that combines JSX and Markdown, basically making it possible to import React components inside Markdown files. Moreover, Docz version 2 runs onGatsbyJS, which brings increased development and build speeds and enables access to Gatsby's vast network of plugins and tools.

Lerna setup

We'll start by creating a new project, titleduikit, and installing the required dependencies.

$npm i-g lerna$mkdiruikit&&cd$_$yarn add docz react react-dom styled-components
Enter fullscreen modeExit fullscreen mode

With the core dependencies installed, it's time to initialize the Lerna project.

$lerna init
Enter fullscreen modeExit fullscreen mode

This will create the following project structure:

 

    ui-kit/      packages/      package.json      lerna.json
Enter fullscreen modeExit fullscreen mode

The UI components will be stored in thepackages folder.

Now let's examine the generatedlerna.json, which serves as a configuration file for Lerna. By default there isn't much going on, and after a few customizations the config will look as follows.

{"npmClient":"yarn","version":"independent","packages":["packages/*"],"useWorkspaces":true}
Enter fullscreen modeExit fullscreen mode

The most important changes here are selectingyarn as npm client, specifyingindependent versioning, so the package versions can be changed independently of each other, and enablingYarn workspaces.  Thepackages option points to the location of our library packages, for which we'll keep the default setting. The more extensive list of configuration options is available on Lerna'sGithub page.

Additionally, we'll need to add workspaces-related options to the rootpackage.json.

{"name":"uikit","license":"MIT","workspaces":{"packages":["packages/*"]},"private":true,"dependencies":{"docz":"^2.2.0","lerna":"^3.20.2","react":"^16.12.0","react-dom":"^16.12.0","styled-components":"^5.0.0"},"devDependencies":{"prettier":"^1.19.1"}}
Enter fullscreen modeExit fullscreen mode

Here we specify the path toworkspaces, which is the same as the one inlerna.json. Also we have to make the package private, otherwise workspaces won't work.

Creating the first component

To kick things off with the dev work, let's add the first package -Typography, with the necessary base font components. As a result, the project's structure will be updated as follows.

    ui-kit/      packages/        typography/          src/            index.js          CHANGELOG.md          package.json      package.json      lerna.json
Enter fullscreen modeExit fullscreen mode

Before actually writing the font components, let's make a few modifications to the typography's package.json.

{"name":"@uikit/typography","version":"1.0.0","description":"Base fonts","main":"dist/index.js","module":"src/index.js","files":["dist","CHANGELOG.md"],"author":"","license":"MIT"}
Enter fullscreen modeExit fullscreen mode

The most interesting here aremain,module andfiles fields. We'll pointmain to thedist folder, where the transpiled files will be stored and later used in the installed package. Themodule will point to thesrc folder, so the packages can be imported directly from the source folder during development and the changes will be reflected immediately without needing to bootstrap packages again or run build script. Finally thefiles property contains the list of the files, which will be included in the published package.

Now we can setup some basic font styles intypography'sindex.js. Those will be made as styled components.

// typography/src/index.jsimportstyled,{css}from"styled-components";constfontFamily="sans-serif";constfontWeights={light:300,regular:400,bold:600};constbaseStyles=css`      font-family${fontFamily};      margin: 0;      padding: 0;       -webkit-font-smoothing: antialiased;      font-weight:${({fontWeight})=>fontWeights[fontWeight]||fontWeights.regular};    `;exportconstH1=styled.h1`${baseStyles};      font-size: 62px;      letter-spacing: -3px;      line-height: 62px;    `;exportconstH2=styled.h2`${baseStyles};      font-size: 46px;      letter-spacing: -3px;      line-height: 46px;    `;exportconstH3=styled.h3`${baseStyles};      font-size: 30px;      letter-spacing: -2px;      line-height: 30px;    `;exportconstH4=styled.h4`${baseStyles};      font-size: 24px;      letter-spacing: -1.5px;      line-height: 24px;    `;exportconstH5=styled.h5`${baseStyles};      font-size: 20px;      letter-spacing: -1px;      line-height: 20px;    `;exportconstH6=styled.h6`${baseStyles};      font-size: 18px;      letter-spacing: 0;      line-height: 18px;    `;exportconstText=styled.p`${baseStyles};      font-size: 16px;      letter-spacing: 0;      line-height: 16px;    `;exportconstSmallText=styled.small`${baseStyles};      font-size: 12px;      letter-spacing: 0;      line-height: 12px;    `;
Enter fullscreen modeExit fullscreen mode

Note thatcss helper fromstyled-components is used to define reusable parts of the styles, which are then extended by other components. The components also accept afontWeight property for customization, which defaults toregular

Trying out Docz's playground

This seems like a good time to try these components out in action and that's whereDocz will be used to document their usage. In order to do that, we'll need to add an.mdx file somewhere in the project with the component documentation, and one of those files needs to point toroute: / and will be used as the front page. Let's create thisindex.mdx in the root of thepackages.

    // index.mdx    ---    name: Welcome    route: /    ---    # Welcome to the awesome UI Kit    Select any of the components from the sidenav to get started.
Enter fullscreen modeExit fullscreen mode

After runningyarn docz dev, we can navigate tolocalhost:3000 and see the front page of the library.

To add documentation to the typography, we'll create adocs folder inside the package and addtypography.mdx there.

    ui-kit/      packages/        typography/          docs/            typography.mdx           src/            index.js          CHANGELOG.md          package.json      package.json      lerna.json
Enter fullscreen modeExit fullscreen mode

To document components, we'll use a special docz component, called Playground. Wrapping it around the components will allow editing them right below where they are displayed.

    ---    name: Typography    menu: Components    ---    import { Playground } from 'docz';    import { H1, H2, H3, H4, H5, H6, Text, SmallText } from '../src/index';    # Base Typography    <Playground>        <H1>Heading 1</H1>        <H2>Heading 2</H2>        <H3>Heading 3</H3>        <H4>Heading 4</H4>        <H4 fontWeight='bold'>Heading 4 bold</H4>        <H5>Heading 5</H5>        <H6>Heading 6</H6>        <Text>Text</Text>        <SmallText>SmallText</SmallText>    </Playground>
Enter fullscreen modeExit fullscreen mode

After refreshing the page, or restarting dev sever if necessary, we'd be able to see our typography components. And the best thing is that we can directly edit the code on the page and see the updated results immediately! 

Adding custom fonts

This works well for built-in fonts, but what if we want to load a custom font, say from Google fonts? Unfortunately, since v2 of Docz has been released quite recently and due to it being a major rewrite of v1, there's still no clear, documented way to do that. However, there's onesolution, which also nicely demonstrates the extendability of Gatsby configuration and a concept, known asComponent shadowing.

For Gatsby-specific components we'll need to create asrc folder in the root of the project, where the theme-specific components, among others, will be stored. Since we're extending gatsby-theme-docz, a folder with this name needs to be created inside thesrc. Lastly, we'll create awrapper.js file inside of it to have the following project structure.

    ui-kit/      packages/        typography/          docs/            typography.mdx          src/            index.js          CHANGELOG.md          package.json      src/        gatsby-theme-docz/          wrapper.js      package.json      lerna.json
Enter fullscreen modeExit fullscreen mode

Insidewrapper.js we'll add a very simple component, the only task of which is to pass down its children.

// src/gatsby-theme-docz/wrapper.jsimportReact,{Fragment}from"react";exportdefault({children})=><Fragment>{children}</Fragment>;
Enter fullscreen modeExit fullscreen mode

It seems quite pointless to make a component which only forwards the children, however the reason for this is that we can now includecss styles in this component, which will be applied globally. For that, let's createstyles.css alongsidewrapper.js and import there one of the selected fonts. In this tutorial, we'll be using Montserrat.

 

/* src/gatsby-theme-docz/styles.css */@importurl('https://fonts.googleapis.com/css?family=Montserrat:300,400,600&display=swap');
Enter fullscreen modeExit fullscreen mode

Now we just need to import this file intowrapper.js and update thefontFamily constant for the typography.

// src/gatsby-theme-docz/wrapper.jsimportReact,{Fragment}from"react";import"./style.css";exportdefault({children})=><Fragment>{children}</Fragment>;
Enter fullscreen modeExit fullscreen mode
// ./packages/typography/src/index.jsimportstyled,{css}from"styled-components";constfontFamily="'Montserrat', sans-serif";// ...
Enter fullscreen modeExit fullscreen mode

The changes should be visible immediately (if not, might need to restart the dev server). This might not be the cleanest approach, but it gets the job done, and since it's no longer possible to load custom fonts viadoczrc.js, this might be one of the few viable solutions. 

Customizing the documentation site

Talking aboutdoczrc.js, which is used to configure a Docz project. The list of configuration options can be found on the project'sdocumentation site. Since we're now using Montserrat font for UI kit's typography, it would make sense if our documentation website used the same font. To do that, we'll add a themeConfig property to the doczrc.js, where the styles for the most commonly used text elements will be applied.

constfontFamily="'Montserrat', sans-serif";exportdefault{title:"UI Kit",description:"UI Kit - Collection of UI components",themeConfig:{styles:{h1:{fontFamily:fontFamily},h2:{fontFamily:fontFamily},body:{fontFamily:fontFamily}}}};
Enter fullscreen modeExit fullscreen mode

Since we need to keep our project configuration separate from the components, we'll have to declare the font family separately here and use it for specific text elements. Additionally, we can customize the project title and description here. The defaultthemeConfig can be found on theDocz's Github page. More options to customize the project, like adding a custom logo, are described in thedocumentation.

Adding Buttons

Finally it's time to add a React component, Buttons, which will also make use of the typography for better illustration of how components can be used together. As before, we'll make a new package, so the project's structure will be as follows.

    ui-kit/      packages/        typography/          docs/            typography.mdx          src/            index.js          CHANGELOG.md          package.json        buttons/          docs/            buttons.mdx          src/            index.js            Buttons.js          CHANGELOG.md          package.json      src/        gatsby-theme-docz/          style.css          wrapper.js      package.json      lerna.json
Enter fullscreen modeExit fullscreen mode

Thepackage.json forbuttons will look almost identical to the one fromtypography, with a few small exceptions. The most notable one is thatbuttons hastypography package as a dependency.

{"name":"@uikit/buttons","version":"1.0.0","description":"Button components","main":"dist/index.js","module":"src/index.js","files":["dist","CHANGELOG.md"],"dependencies":{"@uikit/typography":"^1.0.0"},"author":"","license":"MIT"}
Enter fullscreen modeExit fullscreen mode

Now, after we runlerna bootstrap, it will install all the required packages and symlink the dependencies inside the packages folder. One nice benefit of this is that if we make any changes to thetypography package and use that package insidebuttons, the changes will be immediately reflected in both packages without needing to rebuild or publish any of them. This makes the development experience really fast and efficient! 

After all the dependencies have been installed, we can start writing code for the buttons.

// packages/buttons/src/Buttons.jsimportReactfrom"react";importstyledfrom"styled-components";import{SmallText}from"@uikit/typography";exportconstButtonSmall=({text,...props})=>{return(<Button{...props}><SmallText>{text}</SmallText></Button>);};exportconstButton=styled.button`      border-radius: 4px;      padding: 8px 16px;      color: white;      background-color: dodgerblue;      border-color: dodgerblue;    `;// packages/src/buttons/index.jsexport*from"./Buttons";
Enter fullscreen modeExit fullscreen mode

Here we define two very basic button components. TheButton component has a few base styles, which could be further extended.ButtonSmall has a predefined text component and therefore accepts button text as a separate prop. Additionally we export everything fromButtons.js insideindex.js as a convenience. This will ensure a single point of export for each package, particularly helpful when there are multiple files per package. Now let's try these new components out in the playground.

    // packages/buttons/docs/buttons.mdx    ---    name: Buttons    menu: Components    ---    import { Playground } from 'docz';    import { Button, ButtonSmall } from '../src/index';    # Buttons    ## Base button    <Playground>        <Button>Test</Button>    </Playground>    ## Small button    <Playground>        <ButtonSmall text='Click me'/>    </Playground>
Enter fullscreen modeExit fullscreen mode

Navigating back tolocalhost:3000 we can confirm that the buttons work as expected. With that we have a properly documented, functioning component library, which can be easily extended. 

Deploying the docs and publishing packages

So far the we have been focusing mostly on development side of the component library, however there are a few other important steps that need to happen before the library becomes usable. 

Publishing packages

To publish all the packages that have been changed since the last publishing took place (and after they have been transpiled withBabel), we can uselerna publish command. It will prompt to specify versioning for each package before publishing them. The version can be specified directly with the publish command, which will apply the same versioning to all the changed packages and will skip the prompts, e.g.lerna publish minor. For publishing to work, aregistry needs to be added inlerna.json.

"command":{"publish":{"registry":"https://mypackageregistry/"}}
Enter fullscreen modeExit fullscreen mode

Building the docs and serving them

Docz comes with a few built-in scripts that make it easier to view and deploy the documentation. It can be built and served locally by runningyarn docs build && yarn docz serve. To deploy the documentation online Docz's site has a handy example ofdoing it with Netlify. After Netlify site has been setup, deploying is easy via running netlify deploy --dir .docz/dist.

If you want to have a look at the boilerplate code for the component library, it's available on myGithub.

Top comments(2)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss
CollapseExpand
 
learnwithparam profile image
Paramanantham Harrison
I help beginners to become a pro software engineers through backendchallenges.com
  • Location
    Tallinn, Estonia
  • Work
    Head of Engineering at Jobbatical
  • Joined

Thanks Alex, it was really helpful. I was thinking about exploring yarn workspace and lerna. Is it possible to push this to npm as library.

May be a next article to automate that 😉

CollapseExpand
 
clarity89 profile image
Alex K.
Full Stack/ Front End web developer. React/Redux, Styled components, Node.js, Django.
  • Location
    Helsinki
  • Work
    Frontend developer
  • Joined

Thank you for the feedback! The boilerplate is actually available on my Github, but I forgot to link it to the article, I'll do it now. Thanks for reminding ;)

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Full Stack/ Front End web developer. React/Redux, Styled components, Node.js, Django.
  • Location
    Helsinki
  • Work
    Frontend developer
  • Joined

More fromAlex K.

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp