Setup Next.js, Storybook and Tailwind on a Stackomate Dev-Container

rafaelcalpena

Rafael Calpena

Posted on September 1, 2023

Setup Next.js, Storybook and Tailwind on a Stackomate Dev-Container

In this tutorial we will see how to setup a reproducible web development stack containing Next.js, Storybook and Tailwind inside a dev-container.

Using a dev-container provides a reproducible environment for your team, and guarantees the isolation of your project files. For example, different projects may contain different Node.js and/or Python versions. We will be using the Stackomate CLI, a global npm package capable of generating templates for development containers for variable purposes.

Creating a Dev-Container

First, let's create our new dev-containers with the Stackomate CLI by running
npx -y stackomate@latest dev-container create and following the default instructions. You will be prompted to select a container type. Below we explain the differences between two common options:

Option 1 - Node.js Dev-Container

You may select the node dev-container to achieve smaller image sizes and faster startup times. The developer can connect to the container via the terminal.

⚠️ Specifically for our web stack, internal ports 3000 and 6006 will be used by Next.js and Storybook servers, respectively, and thus they must be published to the host. This can be achieved by adding the following lines to the dev.docker-compose.yml file created by the stackomate cli:

ports:
  - 3000:3000
  - 6006:6006
expose:
  - 3000
  - 6006
Enter fullscreen mode Exit fullscreen mode

Option 2 - Full Desktop Dev-Container

The desktop-web type contains a Ubuntu desktop interface with Node.js and a built-in reverse proxy installed. The developer can access Firefox, a default terminal and a simple file manager on the browser. It is a great choice for larger projects requiring complex configuration, such as website stacks requiring the generation of local SSL certificates. The desktop interface will be published internally on port 6080, by default. If you need another port, you can change the following lines in the generated dev.docker-compose.yml file:

ports:
  - 6080:6080
expose:
  - 6080
Enter fullscreen mode Exit fullscreen mode

ℹ️ Note: you may create both container types for your web stack, if desired. You may also run them both at the same time.

Once you have created and edited your dev-containers, follow instructions in the generated README.md files to start them. For example, the node dev-container can be started by running cd ./dev-container/node && ./dev.sh (or ./sudo-dev.sh, if your Docker installation requires sudo permissions).

Creating Your Next.js App

Now that we have our container running, it is time to start creating our Next.js app inside of it:

  • Access /app inside your container terminal: cd /app;
  • Call the create-next-app cli: npx -y create-next-app@latest;

We recommend using the following options, except for the project name, which may be chosen arbitrarily. With these settings, Next.js will spare us from installing Tailwind and ESLint separately, and our project structure will contain a src folder and the latest App Router:

What is your project named? › my-test-app
Would you like to use TypeScript? › No / (Yes)
Would you like to use ESLint? › No / (Yes)
Would you like to use Tailwind CSS? › No / (Yes)
Would you like to use `src/` directory? › No / (Yes)
Would you like to use App Router? (recommended) › No / (Yes)
Would you like to customize the default import alias? › (No) / Yes
Enter fullscreen mode Exit fullscreen mode

ℹ️ If you ever want to add Tailwind to an existing Next.js project, you can follow their official guide for more instructions.

⚠️ If you have created the Next.js project without the src folder, please make sure to update all imports in the next parts of this article to reflect the folder structure changes. For example, the src/app/globals.css file would otherwise be located in app/globals.css.

  • Wait for the bootstrapping process to be complete;
  • cd /app/my-test-app;

ℹ️ You can ignore linting warnings at the ./src/app/globals.css file, such as Unknown at rule @tailwindcss(unknownAtRules). If you really want to fix it though, you can follow this solution to add customAt rules.

Installing Storybook

We have Next.js and Tailwind installed, and now we must install Storybook and integrate all three:

  • Run npx -y storybook@latest init

ℹ️ Storybook should automatically detect the Next.js project type. It should also detect ESLint and ask:

We have detected that you're using ESLint. Storybook provides a plugin that gives the best experience with Storybook and helps follow best practices: https://github.com/storybookjs/eslint-plugin-storybook#readme

Would you like to install it? › (Y/n)
Enter fullscreen mode Exit fullscreen mode

Choose Y to proceed with the Storybook ESLint Plugin installation.

Once Storybook has finished installing, it will automatically start on port 6006.

Now Storybook has been seamlessly integrated with Next.js. You can check your package.json file for a @storybook/nextjs dependency. More details about all Next.js features supported by Storybook can be viewed on their package documentation page.

Adding Support for Tailwind on Storybook

Although Storybook has detected and integrated with our Next.js project, it has not detected Tailwind by default.

ℹ️ You can verify it by editing the src/stories/Header.tsx file: add the bg-red-500 class to the element containing className="storybook-header". If the header background does not turn red, then Tailwind is not working with Storybook yet.

Now, we integrate Tailwind with Storybook:

  • Include the src/stories directory in your tailwind.config.js, so that Tailwind can find and target React components in that folder:
const config: Config = {
  content: [
    './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
    './src/components/**/*.{js,ts,jsx,tsx,mdx}',
    './src/app/**/*.{js,ts,jsx,tsx,mdx}',
    './src/stories/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  // ...
Enter fullscreen mode Exit fullscreen mode

⚠️ Before proceeding, we recommend to commit your git changes in the project directory: for example, run git add -A and git commit -m 'chore: add storybook and tailwind'.

  • Stop storybook, and install the @storybook/addon-styling package in your project:
npm i -D @storybook/addon-styling
Enter fullscreen mode Exit fullscreen mode
  • Now run a codemod to help with the integration:
npx addon-styling-setup
Enter fullscreen mode Exit fullscreen mode

You should see an output like this:

=========================================

 🧰 Configuring @storybook/addon-styling

=========================================

(1/3) Project summary
  • Built with webpack
  • Styled with tailwind

(2/3) .storybook/main.ts
  • Registering @storybook/addon-styling.

(3/3) .storybook/preview.ts
  • Adding import for withThemeByClassName decorator
  • Adding import for stylesheet
  • Adding withThemeByClassName decorator to config

✨ Done
Enter fullscreen mode Exit fullscreen mode
  • Go to .storybook/preview.ts, and adjust the line below:
/* TODO: update import to your tailwind styles file. If you're using Angular, inject this through your angular.json config instead */
import '../src/index.css';
Enter fullscreen mode Exit fullscreen mode

to

/* Import for our tailwind global styles file */
import '../src/app/globals.css';
Enter fullscreen mode Exit fullscreen mode
  • Remove the styles generated by Next.js from the src/app/globals.css file, and just leave the Tailwind imports:
@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode
  • Open your storybook again by running npm run storybook

🎉 Now, you should now see the Header.tsx component with the red background in the Header story! 🎉

Integrating Tailwind Themes with Storybook

Tailwind can allow the user to change the appearance of a website using light and dark themes. However, some minor changes must be made if you want to toggle themes in the Storybook preview, which we will see next.

ℹ️ To verify support for dark themes, add dark:bg-yellow-600 to your Header.tsx component, and then toggle from light theme to dark theme in the top dropdown many times. Notice how only one of the background colors is used. This happens because, by default, Tailwind "uses the prefers-color-scheme CSS media feature" (source). Instead, we want to toggle it programatically:

  • Go to tailwind.config.ts and set the darkMode property to support manual toggling by class:
const config: Config = {
  darkMode: 'class',
  content: [
    // ...
}
Enter fullscreen mode Exit fullscreen mode

Now, you should see the Header.tsx component change its background color from red to yellow depending on the theme you choose!

🎉 You can now develop your Next.js website with Tailwind and Storybook, happy coding! 🎉

ℹ️ Once you want to exit your dev-container, use CTRL+C to exit the storybook server, and type exit to stop and remove the development-container. Don't worry about your project files, they will not be lost as they are being mapped to the host 🙂.

If desired, we can further push our dev-containers to GitHub, and distribute them with other people in the team.

Conclusion

In this tutorial, we described a series of steps to create a complex project stack using Next.js, Tailwind and Storybook, along with some challenges and fixes to integrate the existing tools. We have used the Stackomate CLI to help us generate a dev-container and redistribute our development environment in a more predictable way. In the next articles, we will see further improvements that our stack can use to support more common features desired during development.

💖 💪 🙅 🚩
rafaelcalpena
Rafael Calpena

Posted on September 1, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related