create-fsd-architecture 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -0
- package/bin/index.mjs +180 -39
- package/package.json +8 -2
package/README.md
CHANGED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# create-fsd-architecture
|
|
2
|
+
|
|
3
|
+
Scaffold production-ready projects with [Feature-Sliced Design](https://feature-sliced.design/) architecture in seconds.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **FSD Architecture** — Pre-configured layers: app, pages, widgets, features, entities, shared
|
|
8
|
+
- **Interactive CLI** — Guided setup with project name, template selection, and dependency installation
|
|
9
|
+
- **Multiple Templates** — Choose from available project templates (more coming soon)
|
|
10
|
+
- **Zero Config** — Start coding immediately with sensible defaults
|
|
11
|
+
- **TypeScript** — Full TypeScript support out of the box
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx create-fsd-architecture my-app
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or with a specific package manager:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm create fsd-architecture my-app
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
### Interactive Mode
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx create-fsd-architecture
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The CLI will guide you through:
|
|
34
|
+
|
|
35
|
+
1. **Project name** — Name your project
|
|
36
|
+
2. **Template selection** — Choose your framework
|
|
37
|
+
3. **Install dependencies** — Optionally install packages
|
|
38
|
+
4. **Start dev server** — Optionally launch the development server
|
|
39
|
+
|
|
40
|
+
### With Arguments
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx create-fsd-architecture my-app
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Pass the project name directly to skip the name prompt.
|
|
47
|
+
|
|
48
|
+
## Available Templates
|
|
49
|
+
|
|
50
|
+
| Template | Status |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| React + Vite | Available |
|
|
53
|
+
| Next.js | Coming Soon |
|
|
54
|
+
|
|
55
|
+
## Project Structure
|
|
56
|
+
|
|
57
|
+
Projects are scaffolded with the FSD architecture:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
src/
|
|
61
|
+
├── app/ # App-level setup: providers, routing, styles
|
|
62
|
+
├── pages/ # Full pages composed from widgets and features
|
|
63
|
+
├── widgets/ # Large self-contained UI blocks
|
|
64
|
+
├── features/ # User interactions and actions
|
|
65
|
+
├── entities/ # Business entities and their representations
|
|
66
|
+
└── shared/ # Reusable utilities, UI kit, configs
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Roadmap
|
|
70
|
+
|
|
71
|
+
- [x] React + Vite template
|
|
72
|
+
- [ ] Next.js template
|
|
73
|
+
- [ ] Vue + Vite template
|
|
74
|
+
- [ ] Custom template support
|
|
75
|
+
- [ ] Git initialization option
|
|
76
|
+
- [ ] Package manager detection (npm, yarn, pnpm, bun)
|
|
77
|
+
|
|
78
|
+
## Requirements
|
|
79
|
+
|
|
80
|
+
- Node.js 18 or later
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
ISC
|
package/bin/index.mjs
CHANGED
|
@@ -3,58 +3,199 @@
|
|
|
3
3
|
import degit from "degit";
|
|
4
4
|
import prompts from "prompts";
|
|
5
5
|
import chalk from "chalk";
|
|
6
|
+
import ora from "ora";
|
|
6
7
|
import fs from "fs";
|
|
7
8
|
import path from "path";
|
|
8
|
-
import { execSync } from "child_process";
|
|
9
|
+
import { execSync, spawn } from "child_process";
|
|
9
10
|
|
|
10
|
-
const
|
|
11
|
+
const TEMPLATES = [
|
|
12
|
+
{
|
|
13
|
+
title: "React + Vite",
|
|
14
|
+
value: "react-vite",
|
|
15
|
+
description: "React with Vite and FSD architecture",
|
|
16
|
+
repo: "ashrafmo-1/FSD",
|
|
17
|
+
available: true,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
title: "Next.js",
|
|
21
|
+
value: "nextjs",
|
|
22
|
+
description: "Next.js — Full-stack React framework with SSR, SSG, and App Router.",
|
|
23
|
+
repo: "ashrafmo-1/FSD-NEXTJS",
|
|
24
|
+
available: true,
|
|
25
|
+
},
|
|
26
|
+
];
|
|
11
27
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
28
|
+
function showBanner() {
|
|
29
|
+
const line = chalk.cyan("─".repeat(39));
|
|
30
|
+
console.log();
|
|
31
|
+
console.log(` ${chalk.cyan("╭")}${line}${chalk.cyan("╮")}`);
|
|
32
|
+
console.log(` ${chalk.cyan("│")}${" ".repeat(39)}${chalk.cyan("│")}`);
|
|
33
|
+
console.log(` ${chalk.cyan("│")}${" ".repeat(7)}${chalk.bold.white("create-fsd-architecture")}${" ".repeat(9)}${chalk.cyan("│")}`);
|
|
34
|
+
console.log(` ${chalk.cyan("│")}${" ".repeat(3)}${chalk.dim("Feature-Sliced Design Scaffolding")}${" ".repeat(3)}${chalk.cyan("│")}`);
|
|
35
|
+
console.log(` ${chalk.cyan("│")}${" ".repeat(39)}${chalk.cyan("│")}`);
|
|
36
|
+
console.log(` ${chalk.cyan("╰")}${line}${chalk.cyan("╯")}`);
|
|
37
|
+
console.log();
|
|
38
|
+
}
|
|
22
39
|
|
|
23
|
-
|
|
40
|
+
function showNextSteps(projectName, depsInstalled) {
|
|
41
|
+
console.log();
|
|
42
|
+
console.log(chalk.bold.white(" Next steps:"));
|
|
43
|
+
console.log();
|
|
44
|
+
console.log(` ${chalk.cyan("$")} cd ${projectName}`);
|
|
45
|
+
if (!depsInstalled) {
|
|
46
|
+
console.log(` ${chalk.cyan("$")} npm install`);
|
|
47
|
+
}
|
|
48
|
+
console.log(` ${chalk.cyan("$")} npm run dev`);
|
|
49
|
+
console.log();
|
|
50
|
+
}
|
|
24
51
|
|
|
25
|
-
|
|
26
|
-
console.log(
|
|
27
|
-
|
|
52
|
+
function handleCancel() {
|
|
53
|
+
console.log();
|
|
54
|
+
console.log(chalk.yellow(" Cancelled."));
|
|
55
|
+
console.log();
|
|
56
|
+
process.exit(0);
|
|
28
57
|
}
|
|
29
58
|
|
|
30
|
-
const
|
|
59
|
+
const onCancel = { onCancel: handleCancel };
|
|
31
60
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
process.exit(1);
|
|
35
|
-
}
|
|
61
|
+
async function main() {
|
|
62
|
+
showBanner();
|
|
36
63
|
|
|
37
|
-
|
|
64
|
+
const argName = process.argv[2];
|
|
38
65
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
66
|
+
const { projectName } = argName
|
|
67
|
+
? { projectName: argName }
|
|
68
|
+
: await prompts(
|
|
69
|
+
{
|
|
70
|
+
type: "text",
|
|
71
|
+
name: "projectName",
|
|
72
|
+
message: "Project name",
|
|
73
|
+
initial: "my-fsd-app",
|
|
74
|
+
},
|
|
75
|
+
onCancel
|
|
76
|
+
);
|
|
44
77
|
|
|
45
|
-
|
|
78
|
+
if (!projectName) {
|
|
79
|
+
console.log(chalk.red(" Project name is required."));
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
46
82
|
|
|
47
|
-
|
|
83
|
+
const targetDir = path.resolve(process.cwd(), projectName);
|
|
48
84
|
|
|
49
|
-
|
|
85
|
+
if (fs.existsSync(targetDir)) {
|
|
86
|
+
console.log(chalk.red(` Folder "${projectName}" already exists.`));
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
50
89
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
90
|
+
const { template } = await prompts(
|
|
91
|
+
{
|
|
92
|
+
type: "select",
|
|
93
|
+
name: "template",
|
|
94
|
+
message: "Select project type",
|
|
95
|
+
choices: TEMPLATES.map((t) => ({
|
|
96
|
+
title: t.available
|
|
97
|
+
? t.title
|
|
98
|
+
: `${t.title} ${chalk.dim("(Coming Soon)")}`,
|
|
99
|
+
value: t.value,
|
|
100
|
+
})),
|
|
101
|
+
},
|
|
102
|
+
onCancel
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const selected = TEMPLATES.find((t) => t.value === template);
|
|
106
|
+
|
|
107
|
+
if (!selected || !selected.available) {
|
|
108
|
+
console.log();
|
|
109
|
+
console.log(
|
|
110
|
+
chalk.yellow(` ${selected ? selected.title : "Template"} support is coming soon!`)
|
|
111
|
+
);
|
|
112
|
+
console.log(chalk.dim(" Stay tuned for updates."));
|
|
113
|
+
console.log();
|
|
114
|
+
process.exit(0);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
console.log();
|
|
118
|
+
|
|
119
|
+
const spinner = ora({
|
|
120
|
+
text: "Downloading template...",
|
|
121
|
+
color: "cyan",
|
|
122
|
+
}).start();
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const emitter = degit(selected.repo, { cache: false, force: true });
|
|
126
|
+
await emitter.clone(targetDir);
|
|
127
|
+
spinner.succeed(chalk.green("Template downloaded."));
|
|
128
|
+
} catch (err) {
|
|
129
|
+
spinner.fail(chalk.red("Failed to download template."));
|
|
130
|
+
console.error(chalk.dim(` ${err.message}`));
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
55
133
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
134
|
+
const { installDeps } = await prompts(
|
|
135
|
+
{
|
|
136
|
+
type: "confirm",
|
|
137
|
+
name: "installDeps",
|
|
138
|
+
message: "Install dependencies now?",
|
|
139
|
+
initial: true,
|
|
140
|
+
},
|
|
141
|
+
onCancel
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
let depsInstalled = false;
|
|
145
|
+
|
|
146
|
+
if (installDeps) {
|
|
147
|
+
const installSpinner = ora({
|
|
148
|
+
text: "Installing dependencies...",
|
|
149
|
+
color: "cyan",
|
|
150
|
+
}).start();
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
execSync("npm install", { cwd: targetDir, stdio: "pipe" });
|
|
154
|
+
installSpinner.succeed(chalk.green("Dependencies installed."));
|
|
155
|
+
depsInstalled = true;
|
|
156
|
+
} catch (err) {
|
|
157
|
+
installSpinner.fail(chalk.red("Failed to install dependencies."));
|
|
158
|
+
console.log(chalk.dim(" You can install them manually later."));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (depsInstalled) {
|
|
163
|
+
const { startDev } = await prompts(
|
|
164
|
+
{
|
|
165
|
+
type: "confirm",
|
|
166
|
+
name: "startDev",
|
|
167
|
+
message: "Start development server now?",
|
|
168
|
+
initial: true,
|
|
169
|
+
},
|
|
170
|
+
onCancel
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
if (startDev) {
|
|
174
|
+
console.log();
|
|
175
|
+
console.log(chalk.cyan(" Starting development server..."));
|
|
176
|
+
console.log();
|
|
177
|
+
|
|
178
|
+
const child = spawn("npm", ["run", "dev"], {
|
|
179
|
+
cwd: targetDir,
|
|
180
|
+
stdio: "inherit",
|
|
181
|
+
shell: true,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
child.on("error", (err) => {
|
|
185
|
+
console.log(chalk.red(` Failed to start dev server: ${err.message}`));
|
|
186
|
+
showNextSteps(projectName, true);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
console.log();
|
|
194
|
+
console.log(chalk.green.bold(" Project created successfully!"));
|
|
195
|
+
showNextSteps(projectName, depsInstalled);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
main().catch((err) => {
|
|
199
|
+
console.error(chalk.red(` Error: ${err.message}`));
|
|
200
|
+
process.exit(1);
|
|
201
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-fsd-architecture",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
@@ -12,11 +12,17 @@
|
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"chalk": "^5.3.0",
|
|
15
|
+
"create-fsd-architecture": "^1.0.1",
|
|
15
16
|
"degit": "^2.8.4",
|
|
17
|
+
"ora": "^9.4.0",
|
|
16
18
|
"prompts": "^2.4.2"
|
|
17
19
|
},
|
|
20
|
+
"files": [
|
|
21
|
+
"bin",
|
|
22
|
+
"README.md"
|
|
23
|
+
],
|
|
18
24
|
"keywords": [],
|
|
19
25
|
"author": "",
|
|
20
26
|
"license": "ISC",
|
|
21
27
|
"type": "commonjs"
|
|
22
|
-
}
|
|
28
|
+
}
|