Creating an Angular app in minutes with Cypress, StoryBook, Tailwind CSS and Nx

Have you been asked to develop a coding exercise application for an interview? Or have you wanted to try new libraries or features in an application that you can control? Or do you want to have an application that you can showcase on GitHub?

Well, fear not; in this article, I will show you how to setup the workspace, application, shared UI library, and include Nx, Tailwind CSS, StoryBook, and Cypress.

It’s worth noting that this is only the first in a series of articles where I’ll delve more deeply into the architecture, libraries, and tools that will make the system simple to maintain and scale.

Creating the workspace

Nx is a powerful tool for making and managing Angular applications. It gives you a set of tools that work together to develop, build, and test Angular applications. Nx also gives you a powerful set of tools, such as static analysis, continuous integration, and automated testing, that can help you improve your applications.

It’s especially useful to use Nx on your app because it allows you to keep your code consistent, organized, and compliant with best practices across multiple apps and libraries from a single repository. If you still need convincing, though, you can read this article that details every benefit of using Nx in Angular:

20 Reasons to do Angular In Nx

Let’s begin by creating the Nx workspace with the following command:

npx create-nx-workspace@latest ng-demos

The CLI will ask you a set of questions about the workspace, but the most important thing is that you choose the option of “Integrated Monorepo”, since we want to be able to create multiple applications and libraries.

✔ Choose what to create · integrated
✔ What to create in the new workspace · angular-monorepo
✔ Application name · site
✔ Default stylesheet format · scss
✔ Enable distributed caching to make your CI faster · No

Once everything is installed, you run the app by using the command `nx serve site` and you should see something like this:

Nx default page in an Angular Application

🎉 That is it for the first step! I know, I know, it was super easy, but we will dig deeper in the following steps, and hopefully this shows you how easy it is to use Nx workspace for an integrated monorepo with an Angular application.

🤔 If you are stuck, make sure to check the commit here:

Initial commit · alfredoperez/ng-demos@b00c2ee

Adding Tailwind CSS

Tailwind CSS is a utility-first CSS framework that makes it easy to make custom designs without having to write any CSS. The library includes a set of utility classes that speed up the development process and allow developers to focus on creating custom designs rather than writing CSS.

There is a plugin for Nx that makes installing Tailwind CSS a breeze by allowing you to do so with a single command that takes care of all the necessary configuration settings:

nx generate @nrwl/angular:setup-tailwind -project=site

The next step is to implement a custom theme, making the app look different from the rest, and we will do that by customizing the “colors” prop in the configuration file:

//tailwind.config.js

const { createGlobPatternsForDependencies } = require(‘@nrwl/angular/tailwind’);
const colors = require(‘tailwindcss/colors’);
const { join } = require(‘path’);

/** @type {import(‘tailwindcss’).Config} */
module.exports = {
content: [
join(__dirname, ‘src/**/!(*.stories|*.spec).{ts,html}’),
…createGlobPatternsForDependencies(__dirname),
],
theme: {
extend: {
colors: {
primary: {
…colors.indigo,
DEFAULT: colors.indigo[600],
},
accent: {
…colors.slate,
DEFAULT: colors.slate[800],
},
warn: {
…colors.red,
DEFAULT: colors.red[600],
},
‘on-warn’: {
500: colors.red[’50’],
},
},
},
plugins: {},
},
};

We should be good to go, but before we move on, let’s add two buttons to the demo app to ensure that Tailwind is set up properly.

<!— apps/site/src/app/app.component.html —>

<div class=”mt-8 flex gap-x-4 sm:justify-center”>
<button
class=”inline-block rounded-lg px-4 py-1.5 text-base font-semibold leading-7 text-white shadow-sm bg-primary-600 ring-1 ring-primary hover:bg-primary-700 hover:ring-primary-700″
>
Get started
</button>
<button
class=”inline-block rounded-lg px-4 py-1.5 text-base font-semibold leading-7 text-gray-900 bg-accent-200 hover:ring-accent-300 ring-1 ring-gray-900/10 hover:ring-gray-900/20″
>
Live demo
</button>
</div>

If everything is okay, you should have the following buttons on the page:

Two buttons with Tailwind CSS styles

🎉 In this step, you added a custom theme to your app and set up Tailwind CSS.

🤔 Once again, if you get stuck, you can see a commit here.

Adds Tailwind · alfredoperez/ng-demos@e6889dd

Adding a shared UI library

One benefit of having a monorepo is that you can have different libraries and applications. In this step, we’ll add a component library where you can add all the components that you want to use in any or all of your applications.

To create the library, we will use the following command that will add `common-ui` library under the shared folder.

nx g @nrwl/angular:library.
–name=ui –prefix=ui –directory=shared
–buildable –simpleName –importPath=@ng-demos/ui
–unitTestRunner=jest –strict –linter=eslint
–addTailwind –skipModule –standalone –style=scss
–viewEncapsulation=Emulated –changeDetection=OnPush

I think it’s important to point out a few things about some of the options added:

addTailwind: Adds Tailwind to the project. We need to add it to the library, in order to allow StoryBook to load the components with the styles from Tailwind.buildable: Having this option will allow us to generate a buildable library. In this case is also necessary since we used the “ — addTailwind” option, you have to set either this or the option of publishable.directory=shared: This is to add the project under the `libsshared` folder. Putting it in the shared folder allows us to create a directory hierarchy in which we can have shared libraries with all apps or just one.standalone: Uses standalone components instead of modules. Of course! How can you miss the opportunity to try it out!strict: Creates the library with stricter type checking and build optimizations.prefix=ui: This is just to use a small prefix for the components.

Create your first component

Now that we have the library, we should take it for a spin by creating a component in it, and this is the perfect opportunity to move the buttons that were using Tailwind that we added on the previous step.

Execute the following command to add a component to the shared component library:

nx generate @nrwl/angular:component
–project=shared-ui –name=button –standalone
–viewEncapsulation=Emulated –changeDetection=OnPush
–style=scss –type=component –export

Now use the following code for the component:

// libs/shared/ui/src/lib/button/button.component.ts

import { CommonModule } from ‘@angular/common’;
import {
ChangeDetectionStrategy,
Component,
Input,
ViewEncapsulation,
} from ‘@angular/core’;

@Component({
selector: ‘ui-button’,
standalone: true,
imports: [CommonModule],
templateUrl: ‘./button.component.html’,
encapsulation: ViewEncapsulation.Emulated,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ButtonComponent {
@Input() type: ‘primary’ | ‘secondary’ = ‘primary’;
}<!— libs/shared/ui/src/lib/button/button.component.html —>
<button
class=”inline-block rounded-lg px-4 py-1.5 text-base font-semibold leading-7shadow-sm ring-1″
[ngClass]=”{
‘text-white bg-primary-600 hover:bg-primary-700 ring-primary hover:ring-primary-700’:
type === ‘primary’,
‘text-gray-900 bg-accent-200 hover:ring-accent-300 ring-1 ring-gray-900/10 hover:ring-gray-900/20’:
type === ‘secondary’
}”
>
<ng-content></ng-content>
</button>

Finally, let’s try swapping out the existing code on the page with the component from our new shared component library.

<div class=”mt-8 flex gap-x-4 sm:justify-center”>
<ui-button type=”primary”>
Get started
</ui-button>
<ui-button type=”secondary”>
Live demo
</ui-button>
</div>html

Just to not break the trend, here is the GitHub commit in case you want to compare:

Adds a shared UI Component Library · alfredoperez/ng-demos@624735f

Install StoryBook and Cypress in the shared library.

As this application should be professional and something you might want to share in your profile, let’s step it up a notch by including a couple of libraries in your component library that will really demonstrate your seriousness: StoryBook and Cypress

StoryBook and Cypress can help you make professional Angular apps by giving you a powerful set of tools for making, testing, and writing up components.

StoryBook lets you make UI components quickly and separately from the rest of the app. With a separate environment, you can quickly change components and test them in different ways. You can also document components with StoryBook to provide an easy way for other members of the team to understand how each component works.

Cypress automates UI tests for end-to-end testing from the user’s perspective and lets you make test suites to make sure that your application is stable and works well, even if it keeps changing.

To install StoryBook, you need to install the Nx plugin:

npm install -D @nrwl/storybook@latest

Next, we can setup Cypress and StoryBook with a single command:

nx generate @nrwl/angular:storybook-configuration
–name=shared-ui –configureCypress
–generateStories –generateCypressSpecs
–linter=eslint –tsConfiguration

🤩 Can you believe it? 🤩 That is all you need to do!!! So simple, right? Now you can run `nx run shared-ui-e2e:e2e` and ` nx run shared-ui:storybook`

Sharing Tailwind configurations

As the last part of this tutorial, since we added Tailwind to the library to allow StoryBook to load component styles, we will do some quick refactoring to share Tailwind configuration so we don’t have to set it up in every application and library and so StoryBook can use the same configuration.

Create a `tailwind-shared.config.js` to have the theme:

// tailwind-shared.config.js

const colors = require(‘tailwindcss/colors’);

module.exports = {
theme: {
extend: {
colors: {
primary: {
…colors.indigo,
DEFAULT: colors.indigo[600],
},
accent: {
…colors.slate,
DEFAULT: colors.slate[800],
},
warn: {
…colors.red,
DEFAULT: colors.red[600],
},
‘on-warn’: {
500: colors.red[’50’],
},
},
},
plugins: {},
},
};

Modify the Tailwind config files in the app `apps/site/tailwind.config.js` and the library `libs/shared/ui/tailwind.config.js` to use the theme from the root configuration file.

const { createGlobPatternsForDependencies } = require(‘@nrwl/angular/tailwind’);
const sharedTailwindConfig = require(‘../../../tailwind-shared.config’);
const { join } = require(‘path’);

/** @type {import(‘tailwindcss’).Config} */
module.exports = {
presets: [sharedTailwindConfig],
content: [
join(__dirname, ‘src/**/!(*.stories|*.spec).{ts,html}’),
…createGlobPatternsForDependencies(__dirname),
],
};

Add a `tailwind-imports.css` to the `.storybook` folder:

/*.storybook/tailwind-imports.css*/

@tailwind base;
@tailwind components;
@tailwind utilities;

Include a link to it in the “project.json”:

{
“storybook”: {
“options”: {

“styles”: [“.storybook/tailwind-imports.css”] 👈
},
},
“build-storybook”: {
“options”: {

“styles”: [“jo.storybook/tailwind-imports.css”] 👈
},
}
}

Create a Story

Add the following to the `button.stories.ts`:

// libs/shared/ui/src/lib/button/button.component.stories.ts
import { Meta, Story } from ‘@storybook/angular’;
import { ButtonComponent } from ‘./button.component’;

export default {
title: ‘Button’,
component: ButtonComponent,
} as Meta<ButtonComponent>;

const Template: Story<ButtonComponent> = (args: ButtonComponent) => {
const { type } = args;
return {
props: args,
template: `<ui-button [type]=”type”> Save </ui-button>`,
};
};

export const Primary = Template.bind({});
Primary.args = {
type: ‘primary’,
};

export const Secondary = Template.bind({});
Secondary.args = {
type: ‘secondary’,
};

Once you do this, StoryBook should look like the following:

GIF showing the two stories

Yes, yes, here is the last GitHub commit for this guide:

Installs StoryBook · alfredoperez/ng-demos@f36857f

Conclusion

So we are ready to go! In this article, you learned how to create a professional application using Nx, StoryBook, Cypress, and Tailwind CSS.

Remember that this is only the beginning; in subsequent articles, I will go into greater detail about using StoryBook, Cypress, Linters, and even how to add NgRx to your application.

So, follow me, stay tuned, and I hope this makes you want to make an app that you can use as your sandbox, show off tools and libraries, or just put in your profile.

JavaScript is not available.

Join us at ng-conf 2023!

ng-conf | June 14–15, 2023
Workshops | June 12–13, 2023
Location | Salt Lake City, UT

ng-conf 2023 is a two-day single track conference focused on building the Angular community. Come be a part of this amazing event, meet the Angular Team and the biggest names in the community. Learn the latest in Angular, build your network, and grow your skills.

Creating an Angular app in minutes with Cypress, StoryBook, Tailwind CSS and Nx was originally published in ngconf on Medium, where people are continuing the conversation by highlighting and responding to this story.

Leave a Comment

Your email address will not be published. Required fields are marked *