Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
turbo/**/*.hbs
82 changes: 68 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,85 @@
# shadcn/ui monorepo template
## packages 워크스페이스 내 pacakge 추가

This template is for creating a monorepo with shadcn/ui.
### 기능

## Usage
- 패키지 이름의 kebab-case 형식 검증
- 이미 존재하는 패키지 이름 중복 확인
- 일반 패키지 또는 React 패키지 생성 선택 가능
- 패키지 생성 후 자동 `pnpm install` 실행
- 패키지 사용법 안내

### 사용 방법

```bash
pnpm dlx shadcn@latest init
turbo gen package
```

## Adding components
명령어 실행 후 다음 과정을 따라주세요:

1. 패키지 이름 입력 (kebab-case 형식)
2. 패키지 유형 선택
- 일반 패키지: 기본 TypeScript 패키지
- React 패키지: React 라이브러리 패키지

To add components to your app, run the following command at the root of your `web` app:
#### 일반 패키지 생성 예제

```bash
pnpm dlx shadcn@latest add button -c apps/web
$ turbo gen package
? 패키지 이름 입력 > utils
? 패키지 유형을 선택해주세요 > 일반 패키지
```

This will place the ui components in the `packages/ui/src/components` directory.
#### React 패키지 생성 예제

## Tailwind
```bash
$ turbo gen package
? 패키지 이름 입력 > ui-components
? 패키지 유형을 선택해주세요 > React 패키지
```

Your `tailwind.config.ts` and `globals.css` are already set up to use the components from the `ui` package.
#### 생성 파일 구조

## Using components
```
//일반 패키지

packages/your-package/
├── package.json
├── tsconfig.json
├── eslint.config.js
├── build.js
└── src/
└── index.ts
```

To use the components in your app, import them from the `ui` package.
```
//React 패키지

```tsx
import { Button } from "@workspace/ui/components/ui/button"
packages/your-react-package/
├── package.json (React 의존성 포함)
├── tsconfig.json
├── eslint.config.js
├── build.js
└── src/
├── index.ts
└── components/
```

### 템플릿 파일

패키지 생성 도구는 다음 위치의 템플릿 파일을 사용합니다.

#### 일반 패키지 템플릿

- `./templates/package.json.hbs`: 패키지 기본 구성
- `./templates/tsconfig.json.hbs`: TypeScript 설정
- `./templates/eslint.config.js.hbs`: ESLint 설정
- `./templates/build.js.hbs`: 빌드 스크립트(공통)
- `./templates/src/index.ts.hbs`: 소스 코드 진입점 (공통)

#### React 패키지 템플릿

- `./templates/react/package.json.hbs`: React 의존성을 포함한 패키지 구성
- `./templates/react/tsconfig.json.hbs`: React 프로젝트에 맞는 TypeScript 설정
- `./templates/react/eslint.config.js.hbs`: React 프로젝트에 맞는 ESLint 설정
- `./templates/build.js.hbs`: 빌드 스크립트(공통)
- `./templates/src/index.ts.hbs`: 소스 코드 진입점 (공통)
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"lint-staged": "lint-staged"
},
"devDependencies": {
"@turbo/gen": "^2.2.3",
"@workspace/eslint-config": "workspace:*",
"@workspace/typescript-config": "workspace:*",
"husky": "^9.0.11",
Expand Down
68 changes: 68 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

109 changes: 109 additions & 0 deletions turbo/generators/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/* eslint-disable import/no-default-export */
import type { PlopTypes } from '@turbo/gen';
import { execSync } from 'child_process';
import fs from 'fs';
import path from 'path';

export default function generator(plop: PlopTypes.NodePlopAPI) {
plop.setActionType('postInstall', () => {
try {
execSync('pnpm install', { stdio: 'inherit' });

return '✅ pnpm install 완료';
} catch (error) {
console.error('❌ pnpm install 실행 중 오류 발생:', error);
return '❌ pnpm install 실행 실패';
}
});

plop.setGenerator('package', {
description: 'packages 폴더 내부에 package를 생성합니다.',
prompts: [
{
type: 'input',
name: 'packageName',
message: '패키지 이름 입력 >',
validate: (input) => {
const kebabCaseRegex = /^[a-z]+(-[a-z]+)*$/;
if (!kebabCaseRegex.test(input)) {
return '패키지명은 kebab-case로 작성해주세요.';
}

const packagePath = path.join(process.cwd(), 'packages', input);
if (fs.existsSync(packagePath)) {
return '이미 존재하는 패키지 이름입니다. 다른 이름을 입력해주세요.';
}

return true;
},
},
{
type: 'list',
name: 'packageType',
message: '패키지 유형을 선택해주세요 >',
choices: [
{ name: '일반 패키지', value: 'regular' },
{ name: 'React 패키지', value: 'react' },
],
default: 'regular',
},
],
actions: (data) => {
const actions = [];
const { packageType } = data as { packageType: 'regular' | 'react' };

const pathPrefix =
packageType === 'react' ? './templates/react' : './templates';

// 1. package.json 생성
actions.push({
type: 'add',
path: 'packages/{{packageName}}/package.json',
templateFile: `${pathPrefix}/package.json.hbs`,
});

// 2. tsconfig.json 생성
actions.push({
type: 'add',
path: 'packages/{{packageName}}/tsconfig.json',
templateFile: `${pathPrefix}/tsconfig.json.hbs`,
});

// 3. esliont.config.js 생성
actions.push({
type: 'add',
path: 'packages/{{packageName}}/eslint.config.js',
templateFile: `${pathPrefix}/eslint.config.js.hbs`,
});

// 4. build.js 생성
actions.push({
type: 'add',
path: 'packages/{{packageName}}/build.js',
templateFile: './templates/build.js.hbs',
});

// 5. src 디렉토리 및 기본 파일 생성
actions.push({
type: 'add',
path: 'packages/{{packageName}}/src/index.ts',
templateFile: './templates/src/index.ts.hbs',
});

// 6. package.json 이름 업데이트
actions.push({
type: 'modify',
path: 'packages/{{packageName}}/package.json',
pattern: /"name": ".*"/,
template: '"name": "@workspace/{{packageName}}"',
});

// 7. pnpm install 실행
actions.push({
type: 'postInstall',
});

return actions;
},
});
}
3 changes: 3 additions & 0 deletions turbo/generators/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "commonjs"
}
5 changes: 5 additions & 0 deletions turbo/generators/templates/build.js.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {run} from '@workspace/build-config';

import pkg from './package.json' assert { type: 'json' };

run({ pkg });
4 changes: 4 additions & 0 deletions turbo/generators/templates/eslint.config.js.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { config } from '@nettee-sample/eslint-config/base';

/** @type {import("eslint").Linter.Config} */
export default config;
24 changes: 24 additions & 0 deletions turbo/generators/templates/package.json.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "@workspace/{{name}}",
"version": "0.0.1",
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "node build.js",
"dev": "node build.js --watch"
},
"devDependencies": {
"@workspace/build-config": "workspace:*",
"@workspace/eslint-config": "workspace:*",
"@workspace/typescript-config": "workspace:*",
"typescript": "^5.6.3"
}
}
4 changes: 4 additions & 0 deletions turbo/generators/templates/react/eslint.config.js.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { config } from '@nettee-sample/eslint-config/react-internal';

/** @type {import("eslint").Linter.Config} */
export default config;
32 changes: 32 additions & 0 deletions turbo/generators/templates/react/package.json.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "@workspace/{{name}}",
"version": "0.0.1",
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
},
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "node build.js",
"dev": "node build.js --watch"
},
"devDependencies": {
"@workspace/build-config": "workspace:*",
"@workspace/eslint-config": "workspace:*",
"@workspace/typescript-config": "workspace:*",
"@types/react": "18.3.0",
"@types/react-dom": "18.3.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"typescript": "^5.6.3"
},
"peerDependencies": {
"react": ">=19.0.0",
"react-dom": ">=19.0.0"
}
}
Loading