Tutorial - Next.js, Storybook, and Lerna: Build a Monorepo Structure
source link: https://buttercms.com/blog/nextjs-storybook-and-lerna-build-a-monorepo-structure
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
In this article, we’ll learn about how to build a monorepo using Lerna . We’ll be building a Next.js application which will import components from a separate package. We’ll also be using Storybook to showcase those components.
What is Lerna?
Lerna is a tool for managing projects which contain multiple JavaScript projects. It’s similar to yarn workspace as it helps us manage a monorepo while making it easy to build all the packages separately.
Get Started Building with Next.js, Storybook, and Lerna
We can bootstrap our Lerna project by globally installing it:
npm install --global lerna
Next, we need to create a new git repository:
git init building-monorepos-using-lerna && cd building-monorepos-using-lerna
Now, we can run the init command which will create a new Lerna repo or upgrade an existing repo to the current version of Lerna:
lerna init
This will generate the following structure:
Creating the Front-end Package
We’ll be creating the front-end package inside the packages directory. So, let’s change our directory and install the Next.js application:
cd packages && yarn create next-app
This will generate the following structure:
Please note that while creating the Next.js application, I chose the name front-end . Hence, all the files were installed inside that directory. If you choose a different name for your Next.js application, you’ll see that directory instead.
Creating the Components Package
We’ll be creating the components package inside the packages directory. In this package, we’ll be building React components which will be consumed by our Next.js application ( front-end package).
We’ll also use Microbundle for bundling our modules. Let’s create the package using Lerna:
lerna create components
Now, the structure of our application should be like the following:
Let’s add microbundle to our components package:
cd packages/components && yarn add microbundle -D
The above command will add microbundle as a dev-dependency.
Learn how your Marketing team can update your Next.js app with ButterCMS.
Let’s add one script inside our components package’s package.json file:
// packages/components/package.json "scripts": { .. "dev": "microbundle watch --jsx React.createElement" }
Also, we need to add a source to the package.json file:
// packages/components/package.json "source": "lib/index.js",
Let’s create one file called index.js inside our packages/components/lib directory.
Running Our Packages
Until now, we’ve created two packages: front-end and components . Both of them have a dev script defined in their respective package.json files:
// packages/components/package.json "scripts": { .. "dev": "microbundle watch --jsx React.createElement lib/*.js" },
// packages/front-end/package.json "scripts": { .. "dev": "next dev", },
We can run both these scripts from the root using the following command:
lerna run dev
We can now view our Next.js application running on http://localhost:3000/ .
More information regarding lerna run command is available here .
We can also run the following command to get the logs about our server:
lerna run dev --parallel
If we want to run a command for only one package we use the following command:
lerna run dev --scope front-end
Connecting Our Front-end Package with Our Components Package
Let’s now connect our front-end package with our components package. To do that, we can simply add the components package in the front-end package’s package.json file:
// packages/front-end/package.json "dependencies": { .. "components": "0.0.0" }
We’ve defined the version 0.0.0 as that’s the version defined in the components package’s package.json file:
// packages/components/package.json { "name": "components", "version": "0.0.0", .. }
Let’s import a dummy function from the components package into our front-end application:
// packages/front-end/pages/index.js import Head from "next/head"; import dummy from "components"; dummy(); // function log something from components package const Home = () => ( .. )
Let’s update our component package’s lib/index.js file to ensure that the dummy function that we imported from it is working fine:
// packages/components/lib/index.js "use strict"; module.exports = components; function components() { console.log("Front components package!"); }
We can immediately see that our packages compiled:
Now, if we visit http://localhost:3000/ , we should be able to see the console.log output on the browser’s console:
So, we’ve successfully connected our Next.js application with our components package. Next, we’ll build a few React components using Storybook. Then, we’ll import them in our Next.js application.
Integrating Storybook With Our Components Package
We’ll now install Storybook and build our React components with it.
cd packages/components && npx -p @storybook/cli sb init --type react
The above command will do the following:
- Adds the Storybook dependencies
- Generates example stories
- Adds two storybook scripts
"scripts": { .. "storybook": "start-storybook -p 6006", "build-storybook": "build-storybook" },
Our application structure will now look like the following:
Now, we’ll create a Button component and import it in our Storybook application. Let’s create a simple Button component in our components package:
// packages/components/lib/button/index.js import React from "react"; const Button = ({ onClick, children }) => { return <button onClick={onClick}>{children}</button>; }; export default Button;
Now, we can import this in our Button story. We already have an example Button story. We just need to replace the Button component present in that story with our Button component:
// packages/components/stories/1-Button.stories.js import React from "react"; import { action } from "@storybook/addon-actions"; import Button from "../lib/button"; export default { title: "Button", component: Button }; export const Text = () => ( <Button onClick={action("clicked")}>Hello Button</Button> ); export const Emoji = () => ( <Button onClick={action("clicked")}> <span role="img" aria-label="so cool"> :grinning: :sunglasses: :+1: :100: </span> </Button> );
We can now run our Storybook application and check our Button component:
cd packages/components && yarn storybook
Our Storybook application will now be up and running at http://localhost:6006/ . We can also view our Button component there:
Learn how your Marketing team can update your Next.js app with ButterCMS.
Importing Button From Our Components Package
Until now, we have created a Button component in our components package. Let’s export that component from our package:
// packages/components/lib/index.js "use strict"; import Button from "./button"; module.exports = { Button };
Now, we can import this component in our front-end package:
// packages/front-end/pages/index.js import Head from "next/head"; import { Button } from "components"; const Home = () => ( <div className="container"> .. <Button onClick={() => console.log("button clicked!")} > Click me </Button> .. </div> ); export default Home;
We can see our Button component appearing below the Welcome to Next.js! text. If we click on the button, we can also see that it’s logging “button clicked!” in the browser’s console:
Adding Styles to Our Components
Let’s add styles to our Button component. We’ll be using emotion for styling. First, let’s install the necessary dependencies:
cd packages/components && yarn add @emotion/styled @emotion/core
Now, let’s update our Button component:
// packages/components/lib/button/index.js import React from "react"; import styled from "@emotion/styled"; const Button = styled.button` padding: 12px 24px; background-color: #121a3e; font-size: 16px; border-radius: 4px; color: #fff; cursor: pointer; `; const _Button = ({ onClick, children }) => { return <Button onClick={onClick}>{children}</Button>; }; export default _Button;
If we visit our Next.js application on http://localhost:3000/ , we can see the updated Button component:
Our Storybook application should also show the new Button component as well:
Conclusion
We’ve seen how easy it is to create an application with a design system using Lerna. The code for this project is available on Github . This repository can be the starting point for your next monorepo project.
I hope this tutorial helps you in your future projects. Please feel free to share your feedback in the comments section below.
Recommend
-
91
Monerepo with lerna At Kudobuzz we have lots of services in N odes,js , this naturally comes with writing many reusable packages. No...
-
7
In this post, I will walk you through how to use Lerna to manage, and publish, two packages under the same monorepo. Publishing will be done to my private GitHub repository under the GitHub packages registry. I decided to keep it as s...
-
6
How to Use Lerna to Create a Monorepo for Multiple Node PackagesCreate two packages, hello-world, and aloha-world (with the default options):0 reactionslerna create hello-world lerna create aloha-worl...
-
7
上古时期,前端没有工程化的概念可言,复用代码也不过是将某些 css、js 代码片段保存到笔记,需要时复制到项目中,仅此而已。参考:55 个提高你 CSS 开发效率的必备片段,或是
-
7
Things I have learned while maintaining JavaScript monorepo with...
-
15
Prerequisites Some Javascript and Git knowledge and a Github account. Also,
-
12
Repository with full code if you want to follow like thathttps://github.com/KevBeltrao/microfrontend-monorepo-article What do I expect from you
-
4
Monorepo Javascript Projects with Yarn Workspaces and Lerna Monorepo is a software development strategy in which a single repository contains code for multiple projects with shared dependencies. It has a...
-
8
How to add Storybook and Chromatic to your Angular monorepoDecember 19, 2022Storybook is an amazing tool, and you should use it if you’re thinking about starting a reusable component libra...
-
5
在开发中,我们可能会遇到多个项目有相同或高度相似的业务场景页面,这里我们可能会进行复制粘贴已有的组件,但是,这种解决方案并不值得提倡,那么本文我们探索一种比较优雅的解决方案。最近有个项目,有着多个代码库,其中有插件、业务组件等相互依赖,...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK