In an increasingly component-driven development world, a well-organized, efficient approach to managing these independent parts is key.
Bit provides a powerful, open-source solution for creating, sharing, and managing these components. Here, we'll explore how to leverage Bit's capabilities in a Next.js project, fostering better component isolation and modularity.
- See the demo NextJS project with the Bit components
- See the live demo app
- See the Bit scope for the demo components
Initialize Bit at the root of your NextJS project (replace learnbit-react.rocket-roster
with your own scope name):
Run the following to create an env (component) for your React components. The env will provide your independent React components with all the tooling and configurations they need to be developed, built and delivered, independent of your project's setup.
The output should confirm that the env was created successfully, and provide you with the component ID of the env you just created. It should look something like this:
Configure this env as the default env for future React components in your workspace:
/* @filename: workspace.jsonc */ { "teambit.generator/generator": { "envs": [ /* replace the following with your env's component id */ "learnbit-react.rocket-roster/envs/react-env" ] } }
Watch for changes in the node_modules
directory
Bit generates a corresponding Node package for each component you create.
A component's package, generated in the node_modules
of your project, is used to consume that component.
During the components' build a similar package is generated and persisted in the component snap (version). This package is then used to consume the component in other projects, as well. More on that in the following sections.
Set up NextJS to watch for changes (new compiled code) in the relevant directory, nested inside the node_modules
folder.
Add the following to your next.config.js
file (replace learnbit-react
with your own Bit account name):
/* @filename: next.config.js */ /** @type {import('next').NextConfig} */ const nextConfig = { webpack: (config) => { /** * add your Bit account name to the following regex. * replace the existing 'learnbit-react' account/org name * */ config.snapshot.managedPaths = [ /^(?!.*[\\/]node_modules[\\/](?:@learnbit-react)[\\/])(.+[\\/]node_modules[\\/])/, ]; return config; }, // ... other NextJS config }; module.exports = nextConfig;
Run the following to create a React component:
React component or a NextJS component?
In this tutorial, we create a generic React component, not a NextJS component. This is because we want to create a component that is not dependent on NextJS, and can be used in any React project.
Having said that, some cases might require you to set your component as a NextJS component, to enable NextJS-specific features, and to communicate to other developers that a component is meant to be used in a NextJS project.
More on that in future tutorials.
Run the following to compile your Bit components on every component change:
Bit React components will be compiled using the compiler configured by the React env you created in the previous step.
As you recall from an earlier section, Bit components are always consumed using their Node package, even when their source files are available in the workspace.
In the example below, the previously created card
component is consumed in the app's default page.tsx
file:
/* @filename: src/app/page.tsx */ import { client } from './utils/client'; import Link from 'next/link'; /** * this is the previously created Bit components. * it is consumed using its node package, which was generated by bit. */ import { Card } from '@learnbit-react/rocket-roster.ui.card'; export default async function Home() { const allLaunches = await client.getUpcomingLaunches({}); return ( <main> // ... <h2 > Space Rocket upcoming launches </h2> <div> {allLaunches.results.map((launch) => ( <Card key={launch.id} launch={launch} /> ))} </div> </section> <Link href="/past" > View Past Launches </Link> </div> </main> ); }
To learn how to install Bit component in your workspace, See Installing components.
To learn how to import Bit component, to change and update them, see Importing components.
Run the following ro run Bit's dev server/Workspace UI:
The component previews are loaded from the (component's) *.composition.tsx
files.
Make sure to set up your component compositions in a way that allows you to preview them in the Bit UI, without depending on NextJS. This will also make the component usable in other frameworks and projects.
For example, the card
component is rendered without NextJS's image optimization, when previewed in the Bit UI:
/* @filename: {COMPONENT_DIRECTORY}/card.tsx */ /** * This component utilizes the image optimization feature, provided by NextJS. */ import Image from 'next/image'; export function Card({ launch, isPreview }: CardProps) { return ( <article key={launch.id}> <header> <h5>{launch.name}</h5> <div> <Image src={launch.image} alt={launch.name} fill // disable NextJS image optimization in component previews unoptimized={isPreview} /> </div> <Countdown date={launch.window_start} /> </header> // ... </article> ); }
When the component is used in its .composition.tsx
file, for previewing, the image optimization is turned off:
/* @filename: {COMPONENT_DIRECTORY}/card.composition.tsx */ export const BasicCard = () => { const [launch, setLaunch] = useState<any | null>(null); useEffect(() => { // ... }, []); // disable NextJS image optimization in component previews using the 'isPreview' prop return <>{launch && <Card launch={launch} isPreview />}</>; };
Using NextJS features in component previews
Asx mentioned earlier, an alternative to disabling NextJS features in your component compositions, is to set your component as a NextJS component, using a dedicated NextJS component development environment. This will allow you to use NextJS features in your component compositions, and will also communicate to other developers that the component is meant to be used in a NextJS project.
Note that once your component is snapped and exported, the previews will be available in its component page, in the remote scope.
It is highly recommended to use Bit's dependency management feature to manage your components' dependencies. This is done by installing your project's (and Bit components') dependencies using Bit's install
command.
The installation process does a few critical things:
- It reads the dependencies from the fallowing sources, and installs them in your project's
node_modules
directory:- Your project's
package.json
file. - Dependencies listed in the workspace's
workspace.jsonc
file, and in the variousenv.jsonc
files, that are part of your component development environments. - Your components' specific dependencies, listed in their snaps
- Your project's
- It compiles your components and creates a symlinks to them in your project's
node_modules
directory.
To learn how to use your own package manager, see 'configuring bit.cloud in your NPM config'.
When your component is ready to be shared, snap and export and Export components it to its a remote scope.