Skip to content

Commit

Permalink
feat(shadcn): monorepo support (#6104)
Browse files Browse the repository at this point in the history
  • Loading branch information
shadcn authored Dec 20, 2024
1 parent ea677cc commit 811bb59
Show file tree
Hide file tree
Showing 65 changed files with 6,665 additions and 88 deletions.
8 changes: 8 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
node_modules/
target/
.next/
build/
dist/

/templates/
/fixtures/
2 changes: 1 addition & 1 deletion .github/workflows/prerelease-comment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
A new prerelease is available for testing:
```sh
npx shadcn@${{ env.BETA_PACKAGE_VERSION }}
pnpm dlx shadcn@${{ env.BETA_PACKAGE_VERSION }}
```
- name: "Remove the autorelease label once published"
Expand Down
4 changes: 2 additions & 2 deletions apps/www/components/announcement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import { ArrowRight } from "lucide-react"
export function Announcement() {
return (
<Link
href="/docs/components/sidebar"
href="/docs/monorepo"
className="group mb-2 inline-flex items-center px-0.5 text-sm font-medium"
>
<span className="underline-offset-4 group-hover:underline">
New sidebar component
Monorepo support
</span>
<ArrowRight className="ml-1 h-4 w-4" />
</Link>
Expand Down
17 changes: 11 additions & 6 deletions apps/www/config/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ export const docsConfig: DocsConfig = {
href: "/docs/cli",
items: [],
},
{
title: "Monorepo",
href: "/docs/monorepo",
items: [],
label: "New",
},
{
title: "Next.js 15 + React 19",
href: "/docs/react-19",
Expand Down Expand Up @@ -141,12 +147,6 @@ export const docsConfig: DocsConfig = {
{
title: "Components",
items: [
{
title: "Sidebar",
href: "/docs/components/sidebar",
items: [],
label: "New",
},
{
title: "Accordion",
href: "/docs/components/accordion",
Expand Down Expand Up @@ -337,6 +337,11 @@ export const docsConfig: DocsConfig = {
href: "/docs/components/sheet",
items: [],
},
{
title: "Sidebar",
href: "/docs/components/sidebar",
items: [],
},
{
title: "Skeleton",
href: "/docs/components/skeleton",
Expand Down
175 changes: 175 additions & 0 deletions apps/www/content/docs/monorepo.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
---
title: Monorepo
description: Using shadcn/ui components and CLI in a monorepo.
---

<Callout>
**Note:** We're releasing monorepo support in the CLI as __experimental__.
Help us improve it by testing it out and sending feedback. If you have any
questions, please [reach out to
us](https://github.com/shadcn-ui/ui/discussions).
</Callout>

Until now, using shadcn/ui in a monorepo was a bit of a pain. You could add
components using the CLI, but you had to manage where the components
were installed and manually fix import paths.

With the new monorepo support in the CLI, we've made it a lot easier to use
shadcn/ui in a monorepo.

The CLI now understands the monorepo structure and will install the components,
dependencies and registry dependencies to the correct paths and handle imports
for you.

## Getting started

<Steps>

### Create a new monorepo project

To create a new monorepo project, run the `init` command. You will be prompted
to select the type of project you are creating.

```bash
npx shadcn@canary init
```

Select the `Next.js (Monorepo)` option.

```bash
? Would you like to start a new project?
Next.js
❯ Next.js (Monorepo)
```

This will create a new monorepo project with two workspaces: `web` and `ui`,
and [Turborepo](https://turbo.build/repo/docs) as the build system.

Everything is set up for you, so you can start adding components to your project.

### Add components to your project

To add components to your project, run the `add` command **in the path of your app**.

```bash
cd apps/web
```

```bash
npx shadcn@canary add [COMPONENT]
```

The CLI will figure out what type of component you are adding and install the
correct files to the correct path.

For example, if you run `npx shadcn@canary add button`, the CLI will install the button component under `packages/ui` and update the import path for components in `apps/web`.

If you run `npx shadcn@canary add login-01`, the CLI will install the `button`, `label`, `input` and `card` components under `packages/ui` and the `login-form` component under `apps/web/components`.

### Importing components

You can import components from the `@workspace/ui` package as follows:

```tsx
import { Button } from "@workspace/ui/components/button"
```

You can also import hooks and utilities from the `@workspace/ui` package.

```tsx
import { useTheme } from "@workspace/ui/hooks/use-theme"
import { cn } from "@workspace/ui/lib/utils"
```

</Steps>

## File Structure

When you create a new monorepo project, the CLI will create the following file structure:

```txt
apps
└── web # Your app goes here.
├── app
│ └── page.tsx
├── components
│ └── login-form.tsx
├── components.json
└── package.json
packages
└── ui # Your components and dependencies are installed here.
├── src
│ ├── components
│ │ └── button.tsx
│ ├── hooks
│ ├── lib
│ │ └── utils.ts
│ └── styles
│ └── globals.css
├── components.json
└── package.json
package.json
turbo.json
```

## Requirements

1. Every workspace must have a `components.json` file. A `package.json` file tells npm how to install the dependencies. A `components.json` file tells the CLI how and where to install components.

2. The `components.json` file must properly define aliases for the workspace. This tells the CLI how to import components, hooks, utilities, etc.

```json title="apps/web/components.json"
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "../../packages/ui/tailwind.config.ts",
"css": "../../packages/ui/src/styles/globals.css",
"baseColor": "zinc",
"cssVariables": true
},
"iconLibrary": "lucide",
"aliases": {
"components": "@/components",
"hooks": "@/hooks",
"lib": "@/lib",
"utils": "@workspace/ui/lib/utils",
"ui": "@workspace/ui/components"
}
}
```

```json title="packages/ui/components.json"
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/styles/globals.css",
"baseColor": "zinc",
"cssVariables": true
},
"iconLibrary": "lucide",
"aliases": {
"components": "@workspace/ui/components",
"utils": "@workspace/ui/lib/utils",
"hooks": "@workspace/ui/hooks",
"lib": "@workspace/ui/lib",
"ui": "@workspace/ui/components"
}
}
```

3. Ensure you have the same `style`, `iconLibrary` and `baseColor` in both `components.json` files.

By following these requirements, the CLI will be able to install ui components, blocks, libs and hooks to the correct paths and handle imports for you.

## Help us improve monorepo support

We're releasing monorepo support in the CLI as **experimental**. Help us improve it by testing it out and sending feedback.

If you have any questions, please reach out to us on [GitHub Discussions](https://github.com/shadcn-ui/ui/discussions).
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@
},
"workspaces": [
"apps/*",
"packages/*",
"templates/*"
"packages/*"
],
"scripts": {
"build": "turbo run build",
Expand Down
36 changes: 21 additions & 15 deletions packages/shadcn/src/commands/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { preFlightAdd } from "@/src/preflights/preflight-add"
import { addComponents } from "@/src/utils/add-components"
import { createProject } from "@/src/utils/create-project"
import * as ERRORS from "@/src/utils/errors"
import { getConfig } from "@/src/utils/get-config"
import { handleError } from "@/src/utils/handle-error"
import { highlighter } from "@/src/utils/highlighter"
import { logger } from "@/src/utils/logger"
Expand Down Expand Up @@ -112,7 +113,7 @@ export const add = new Command()

let shouldUpdateAppIndex = false
if (errors[ERRORS.MISSING_DIR_OR_EMPTY_PROJECT]) {
const { projectPath } = await createProject({
const { projectPath, projectType } = await createProject({
cwd: options.cwd,
force: options.overwrite,
srcDir: options.srcDir,
Expand All @@ -124,20 +125,25 @@ export const add = new Command()
}
options.cwd = projectPath

config = await runInit({
cwd: options.cwd,
yes: true,
force: true,
defaults: false,
skipPreflight: true,
silent: true,
isNewProject: true,
srcDir: options.srcDir,
})

shouldUpdateAppIndex =
options.components?.length === 1 &&
!!options.components[0].match(/\/chat\/b\//)
if (projectType === "monorepo") {
options.cwd = path.resolve(options.cwd, "apps/web")
config = await getConfig(options.cwd)
} else {
config = await runInit({
cwd: options.cwd,
yes: true,
force: true,
defaults: false,
skipPreflight: true,
silent: true,
isNewProject: true,
srcDir: options.srcDir,
})

shouldUpdateAppIndex =
options.components?.length === 1 &&
!!options.components[0].match(/\/chat\/b\//)
}
}

if (!config) {
Expand Down
9 changes: 8 additions & 1 deletion packages/shadcn/src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,28 @@ export async function runInit(
}
) {
let projectInfo
let newProjectType
if (!options.skipPreflight) {
const preflight = await preFlightInit(options)
if (preflight.errors[ERRORS.MISSING_DIR_OR_EMPTY_PROJECT]) {
const { projectPath } = await createProject(options)
const { projectPath, projectType } = await createProject(options)
if (!projectPath) {
process.exit(1)
}
options.cwd = projectPath
options.isNewProject = true
newProjectType = projectType
}
projectInfo = preflight.projectInfo
} else {
projectInfo = await getProjectInfo(options.cwd)
}

if (newProjectType === "monorepo") {
options.cwd = path.resolve(options.cwd, "apps/web")
return await getConfig(options.cwd)
}

const projectConfig = await getProjectConfig(options.cwd, projectInfo)
const config = projectConfig
? await promptForMinimalConfig(projectConfig, options)
Expand Down
Loading

0 comments on commit 811bb59

Please sign in to comment.