How To Create a New Next.js Project in 2024?

Getting started with Next.js in 2024

Lakindu Hewawasam
Bits and Pieces

--

Let’s explore a modern approach on building Next.js apps in 2024!

This is important in building apps with excellent user experience (UX). And, stepping into 2024, that’s key.

UX not only includes building high-performing apps but also requires you to think about the overall consistency of your app. For instance, use buttons and text fields with the same look and feel across your app so that users don’t get lost.

Well, this is where you need to build Next.js apps driven by highly reusable components (AKA — Composable Software).

And that’s where Bit comes into the picture.

If you’re too excited on checking out the code, feel free to checkout my scope on Bit Cloud to get you started!

Building a Next.js Application with Bit

Figure: Bit

If you’re unfamiliar with Bit, it’s a build system that lets you design, develop, build, and version your components in isolated environments.

It lets you build apps as independent components where Bit keeps track of the usages of the components across your tree and leverages its CI Server — Ripple CI, to propagate changes to the component tree.

Figure: A component tree

Consider this tree:

  1. You have a Typography component which provides a consistent organization text formatting.
  2. You have an Icon Text Button that leverages your Typography component and creates an Icon Button.

We are making our components composable and pluggable in any nature. This is true in all front-end components. You’ll also want these dependencies to get automatically updated if a child updates, right?

For example, if I introduced a new variant in the Typography component, would you want your IconTextButton to know that a change was made automatically?

Bit leverages Ripple CI and understands the changes in the tree and will automatically update the changes and ensure the components run on the latest version!

Pretty cool, isn’t it?

Let’s get our hands dirty and deploy a Next.js app using Bit on Vercel!

Step 01 — Pre-requisites

First, you’ll need to install the Bit CLI using the command:

npx @teambit/bvm install

Next, you’ll need to verify that the CLI has been installed successfully by running the command:

bit --version

If you have installed Bit correctly, you should see the screenshot below.

Figure: Successfully installing Bit

Finally, you will need an account on Bit Cloud to host your composable app. Therefore, create an account with this link.

Step 02 — Initializing a Development Environment

Next, you’ll have to create a Bit workspace to help build composable components we can reuse across applications!

To do so, run the command:

bit init

Afterward, you will see a file being created — workspace.jsonc. Open that file and update the defaultScope parameter to your <<BIT_USER_NAME.SCOPE_NAME>>.

A scope is what your components will be stored on. So, you’ll have to first create a scope on Bit Cloud using the link. Next, update the parameter based on the guidelines above. In my case, my updated workspace.jsonc would be as follows:

"defaultScope": "lakinduhewa.nextjs"

A Bit Workspace is environment-independent.

This means that in a single Bit Workspace, you can work on your React, Angular, Vue.js, Node.js, HTML components. This is possible due to the concept of Bit Environments. An environment provides the “life” to a component we build.

Since, Next.js runs on top React, we’ll need a requirement environment to build the composable app. To create a React env, run the command:

bit create react-env envs/react --aspect teambit.react/react-env

If you explore the created environment, you’ll see an output similar to the one I’ve shown below:

Figure: The Environment

If you dig into this further, you’ll see that there’s a file — env.jsonc. This file defines all the dependencies you use in your React environment. For example, if your React component uses axios, you must update the env.jsonc to include axios. By doing so, all components you create using this environment will consist of axios.

Next, let’s quickly ensure that our workspace allows us to create Next.js apps. To do so, add the following entry to your workspace.jsonc:

"teambit.generator/generator": {
"envs": ["lakinduhewa.nextjs/envs/nextjs-env"]
}

This will let you use my Next.js environment to create Next.js apps!

Next, you can create components that use this environment.

Step 03 — Creating the composable components

Let’s create two components:

  1. Typography
  2. IconTextButton

To do so, run the commands:

bit create react elements/typography elements/icon-text-button  --env envs/react

By running this command, we create two React components (Typography and IconTextButton) that use the environment we created in Step 02. You’ll see the output below:

Figure: Creating the Components Successfully

With Bit, you can define the implementations and Unit tests for each component by writing your tests in the .spec.tsx files. This helps when Ripple CI builds and propagates the changes up the tree, as you can see isolated failures clearly.

To implement the components, open up your typography.tsx , icon-text-button.tsx and include the code below:

// typography.tsx
import React from 'react';

export type TypographyVariants = 'body1' | 'body2' | 'overline' | 'subtitle';
export type TypographyProps = {
variant: TypographyVariants;
children: React.ReactNode;
};
const styles: { [key: string]: React.CSSProperties } = {
body1: {
fontSize: '16px',
lineHeight: 1.5,
},
body2: {
fontSize: '14px',
lineHeight: 1.43,
},
overline: {
fontSize: '10px',
textTransform: 'uppercase',
lineHeight: 1.66,
},
subtitle: {
fontSize: '12px',
fontWeight: 'bold',
lineHeight: 1.75,
},
};

export function Typography({ children, variant }: TypographyProps) {
return (
<p style={styles[variant]}>{children}</p>
);
}
// icon-text-button.tsx
import React from 'react';
import { Typography } from '@lakinduhewa/nextjs.elements.typography';
export type IconTextButtonProps = {
text: string;
icon: React.ReactNode;
} & React.ButtonHTMLAttributes<HTMLButtonElement>
export function IconTextButton({ icon, text, ...rest }: IconTextButtonProps) {
return (
<button
style={{
display: 'flex',
alignItems: 'center',
gap: '10px',
...rest.style
}}
{...rest}
>
{icon}
<Typography variant={'overline'}>{text}</Typography>
</button>
);
}

Next, you’ll want to add some visualizations to your components. This is similar to compositions in Storybook.

You can do this by defining compositions in your .composition.tsx file. So go ahead and open up your icon-text-button.composition.tsx and typography.composition.tsx files and add the code below:

// icon-text-button.composition.tsx
import React from 'react';
import { IconTextButton } from './icon-text-button';

export const BasicIconTextButton = () => {
return (
<IconTextButton text={'Button Text'} icon={'Dummy Icon'}
onClick={() => alert('You Clicked Me!')}
/>
);
}

// typography.composition.tsx
import React from 'react';
import { Typography } from './typography';
export const Body1Typography = () => {
return (
<Typography
variant='body1'
>
Body 1
</Typography>
);
}
export const Body2Typography = () => {
return (
<Typography
variant='body2'
>
Body 2
</Typography>
);
}
export const OverlineTypography = () => {
return (
<Typography
variant='overline'
>
Overline
</Typography>
);
}
export const SubtitleTypography = () => {
return (
<Typography
variant='subtitle'
>
Subtitle
</Typography>
);
}

Next, run the command: bit start to launch the Bit Server locally to visualize your components:

Figure: Viewing the Compositions

As you can see, our components are now working as expected. Next, let’s go ahead and share this onto our Bit Cloud Scope using the command:

bit tag && bit export

This will automatically version the components and build them in the cloud using the CI Server — Ripple CI. The best part is that you don’t have to configure this!

Once you run the command, it’ll generate a Ripple URL:

Figure: The Ripple URL

Once you open the URL, it’ll show the component tree and its build:

Figure: The Bit Ripple CI

As you can see, Bit tracks all the dependencies of the components and automatically propagates the changes to the dependents. Once the build is done, you can see the output:

Figure: The Successful Build

Step 04 — Creating a Next.js App

Okay, now that we have created the composable components that are extendable by the consumers, let’s make an application that consumes all of this.

To do so, let’s create a Next.js app. This can be done using the command:

bit create nextjs apps/my-nextjs-app --aspect frontend.nextjs/nextjs-env

This will create an application component using Bit and Next.js.

It lets you launch your components independent of your Bit Server. Additionally, it provides a deployable unit you can make available via a DNS name.

If you’ve run the command successfully, you should see the output shown below:

Figure: The App Component

If you expand the app directory, you should see your familiar Next.js directory:

Figure: The App Directory

By default, it creates two pages:

  1. About
  2. Landing Page (page.tsx)

First, let’s launch the Next.js app. To do so, run the following command:

bit use apps/my-nextjs-app

Doing so will make your application loadable outside of a Bit runtime. Next, launch your app by running the command:

bit run my-nextjs-app

This will launch the Next.js app in a Next.js server, and you’ll see the output shown below:

Figure: Launching the Next.js app

Next, visit localhost:3000 to see the Next.js app:

Figure: Viewing the Next.js app

For now, let’s ship the App component to Bit Cloud by tagging and exporting it:

bit tag && bit export

You can visit the Ripple Build to see the App component building:

Figure: The Ripple Build for the Next.js App

Now, let’s update the app to use the components we’ve created:

  1. First, let’s delete the About page.
  2. Then, on the landing page, let’s use our composable components.

To do so, open up the page.tsx file in your app and add the code:

'use client';

import Image from 'next/image'
import { BitLogo } from '@bitdev/nextjs.examples.bit-logo';
import { Typography } from '@lakinduhewa/nextjs.elements.typography';
import { IconTextButton } from '@lakinduhewa/nextjs.elements.icon-text-button';
import styles from './page.module.css'
export default function Home() {
return (
<main className={styles.main}>
<div className={styles.description}>
<Typography
variant='overline'
>
Get started by editing&nbsp;
<code className={styles.code}>app/page.tsx</code>
</Typography>
<div>
<a
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
By{' '}
<IconTextButton
text='Click me!'
onClick={() => alert('Whee! I got clicked!')}
icon={<Image
src="/vercel.svg"
alt="Vercel Logo"
className={styles.vercelLogo}
width={100}
height={24}
priority
/>}
/>
</a>
</div>
</div>
<div className={styles.logosContainer}>
<div className={styles.bitLogo}>
<BitLogo width={100} height={100} />
</div>
<span role="img" aria-label="heart">
💜
</span>
<Image
className={styles.logo}
src="/next.svg"
alt="Next.js Logo"
width={180}
height={37}
priority
/>
</div>
</main>
)
}

Next, relaunch your app to see the changes:

Figure: Using the custom components

Next, let’s tag and export it to see Ripple in action:

You’ll see the app component being built again using our composable components.

The best part is that if you update any of the components you’re using, Bit will automatically track its parents and update as necessary. To do so, visit your Typography or IconTextButton, make any implementation changes, and retag and export it. You’ll see an output similar to this:

Figure: The Ripple build for the changed dependencies

As you can see, I’ve changed my “typography” component. By doing so, Bit understood this, and it automatically built my IconTextButton as well as my App!

That’s pretty cool, isn’t it?

Step 05 — Deploying the Next.js app on Vercel using Bit

Now that we’ve set up our application, let’s deploy it for the entire world to use!

No, we aren’t going to connect a GitHub account and integrate it to Vercel.

We’re not leaving any room for manual setup for 2024! Instead, we’re going to automate all of this using Bit’s Vercel Deployer Component:

https://bit.cloud/teambit/cloud-providers/deployers/vercel

The Deployer itself is a Bit component that’s sole responsibility is to deploy the app to Vercel whenever Bit + Ripple CI detects a change in the component tree.

So, in our example, as soon as any of our components or the app itself has a change, the deployer will be triggered, and the new version will be deployed to Vercel.

Let’s first install the deployer component onto your Bit workspace to deploy. This can be done using the command:

bit install @teambit/cloud-providers.deployers.vercel

Afterward, open your app component’s common JS file and include the code below:

/** @type {import("@teambit/react.apps.react-app-types").ReactAppOptions} */
/** @type {import("@teambit/cloud-providers.deployers.vercel").VercelOptions} */

const { Vercel } = require('@teambit/cloud-providers.deployers.vercel');
const vercelConfig = {
accessToken: process.env.VERCEL_AUTH_TOKEN,
teamId: '<<YOUR-TEAM-NAME>>',
projectName: 'nextjs-bit-demo',
// the deployer also supports vercel.json configuration, it can be an object or a path to a vercel.json file
vercelConfig: {
rewrites: [{ source: '/(.*)', destination: '/index.html' }],
},
};
module.exports.default = {
name: "my-nextjs-app",
deploy: Vercel.deploy(vercelConfig),
};

Replace <<YOUR-TEAM-NAME>> with your Vercel username. In my case, it'll be lakinduhewa, as shown below:

Figure: Vercel Console

Hint: Before proceeding any further, ensure that you’ve installed the Vercel CLI locally and logged in to the Vercel console through your terminal using vercel login.

Next, run the command bit tag && bit export. This will deploy your application onto Vercel automatically during the build with Ripple CI. Ensure you've added the Vercel token as an environment variable in Ripple CI. Afterward, your app should be available on the Vercel console.

And that’s it! Your app is now publicly accessible to users across the world!

The best part is that whenever you change any of your components, Ripple CI will automatically build the component tree and redeploy your app!

Wrapping Up

Well, that was simple. Building Next.js apps should be easy and easy to maintain in 2024. This lets you focus on working on what matters — delivering business value to your end users.

If you wish to explore the demo we built in this article, check out my scope on Bit Cloud.

I hope you found this article helpful.

Thank you for reading.

--

--