@t1ep1l0t/create-fsd 1.0.2 ā 2.0.1
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/LICENSE +21 -0
- package/README.md +104 -6
- package/bin/cli.js +145 -1
- package/package.json +5 -2
- package/templates/react/src/app/styles/global.css +15 -0
- package/templates/react/src/app/styles/index.css +0 -19
- package/templates/react/src/main.jsx +14 -11
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 t1ep1l0t
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# š @t1ep1l0t/create-fsd
|
|
4
4
|
|
|
5
|
-
**Scaffold modern frontend applications with Feature-Sliced Design architecture**
|
|
5
|
+
**Scaffold modern frontend applications with Feature-Sliced Design architecture and generate FSD structures on-the-fly**
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@t1ep1l0t/create-fsd)
|
|
8
8
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
## š About
|
|
16
16
|
|
|
17
|
-
**@t1ep1l0t/create-fsd** is a powerful CLI tool that helps you quickly bootstrap production-ready React applications following the [Feature-Sliced Design (FSD)](https://feature-sliced.design/) architectural methodology.
|
|
17
|
+
**@t1ep1l0t/create-fsd** is a powerful CLI tool that helps you quickly bootstrap production-ready React applications following the [Feature-Sliced Design (FSD)](https://feature-sliced.design/) architectural methodology. Not only can you create fully configured projects in seconds, but you can also generate FSD-compliant structures for features, entities, widgets, and pages on-demand!
|
|
18
18
|
|
|
19
19
|
> šÆ Currently supports **React** template. More frameworks (Vue, Next, Nuxt, Svelte) coming soon!
|
|
20
20
|
|
|
@@ -24,8 +24,9 @@
|
|
|
24
24
|
|
|
25
25
|
### šļø **Architecture**
|
|
26
26
|
- **Feature-Sliced Design (FSD)** - Scalable and maintainable project structure
|
|
27
|
+
- **FSD Structure Generator** - Quickly generate features, entities, widgets, and pages
|
|
27
28
|
- Clear separation of concerns across layers
|
|
28
|
-
- Ready-to-use folder structure
|
|
29
|
+
- Ready-to-use folder structure with automated scaffolding
|
|
29
30
|
|
|
30
31
|
### ā” **Modern Stack**
|
|
31
32
|
- **React 18** - Latest React with concurrent features
|
|
@@ -73,6 +74,68 @@ npx @t1ep1l0t/create-fsd my-app --template react
|
|
|
73
74
|
|
|
74
75
|
---
|
|
75
76
|
|
|
77
|
+
## šļø FSD Structure Generator
|
|
78
|
+
|
|
79
|
+
After creating your project, you can use the `fsd` command to quickly generate FSD-compliant directory structures for features, entities, widgets, and pages.
|
|
80
|
+
|
|
81
|
+
### Usage
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
create-fsd fsd [options]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Options
|
|
88
|
+
|
|
89
|
+
| Option | Alias | Description |
|
|
90
|
+
|--------|-------|-------------|
|
|
91
|
+
| `--feature <name>` | `-f` | Create feature in `features/` |
|
|
92
|
+
| `--entity <name>` | `-e` | Create entity in `entities/` |
|
|
93
|
+
| `--widget <name>` | `-w` | Create widget in `widgets/` |
|
|
94
|
+
| `--page <name>` | `-p` | Create page in `pages/` |
|
|
95
|
+
| `--segments <segments...>` | `-s` | Segments to create (e.g., model ui api lib) |
|
|
96
|
+
| `--index` | `-i` | Create index files in root and all segments |
|
|
97
|
+
|
|
98
|
+
### Examples
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
# Create a feature with UI and model segments
|
|
102
|
+
create-fsd fsd -f user -s ui model -i
|
|
103
|
+
|
|
104
|
+
# Result:
|
|
105
|
+
# src/features/user/
|
|
106
|
+
# āāā ui/
|
|
107
|
+
# ā āāā index.js
|
|
108
|
+
# āāā model/
|
|
109
|
+
# ā āāā index.js
|
|
110
|
+
# āāā index.js (exports all segments)
|
|
111
|
+
|
|
112
|
+
# Create an entity with API and lib segments
|
|
113
|
+
create-fsd fsd -e product -s api lib -i
|
|
114
|
+
|
|
115
|
+
# Create a widget without index files (uses .gitkeep)
|
|
116
|
+
create-fsd fsd -w header -s ui model
|
|
117
|
+
|
|
118
|
+
# Create a page
|
|
119
|
+
create-fsd fsd -p home -s ui api -i
|
|
120
|
+
|
|
121
|
+
# Add more segments to existing structure
|
|
122
|
+
create-fsd fsd -f user -s api config -i
|
|
123
|
+
# This will add api/ and config/ folders and update the root index.js
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Common Segment Names
|
|
127
|
+
|
|
128
|
+
| Segment | Purpose |
|
|
129
|
+
|---------|---------|
|
|
130
|
+
| `ui` | UI components |
|
|
131
|
+
| `model` | Business logic, state, hooks |
|
|
132
|
+
| `api` | API requests and endpoints |
|
|
133
|
+
| `lib` | Helper functions and utilities |
|
|
134
|
+
| `config` | Configuration and constants |
|
|
135
|
+
| `types` | TypeScript types/interfaces |
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
76
139
|
## š Project Structure
|
|
77
140
|
|
|
78
141
|
The generated project follows the FSD architecture with clear layer separation:
|
|
@@ -145,19 +208,21 @@ The generated project includes working examples for all included libraries:
|
|
|
145
208
|
|
|
146
209
|
---
|
|
147
210
|
|
|
148
|
-
## š CLI
|
|
211
|
+
## š CLI Commands
|
|
212
|
+
|
|
213
|
+
### Create Project
|
|
149
214
|
|
|
150
215
|
```bash
|
|
151
216
|
create-fsd <project-name> [options]
|
|
152
217
|
```
|
|
153
218
|
|
|
154
|
-
|
|
219
|
+
#### Options
|
|
155
220
|
|
|
156
221
|
| Option | Alias | Description | Default |
|
|
157
222
|
|--------|-------|-------------|---------|
|
|
158
223
|
| `--template <name>` | `-t` | Template to use | `react` |
|
|
159
224
|
|
|
160
|
-
|
|
225
|
+
#### Examples
|
|
161
226
|
|
|
162
227
|
```bash
|
|
163
228
|
# Create project with React template (default)
|
|
@@ -170,6 +235,39 @@ npx @t1ep1l0t/create-fsd my-app --template react
|
|
|
170
235
|
npx @t1ep1l0t/create-fsd my-app -t react
|
|
171
236
|
```
|
|
172
237
|
|
|
238
|
+
### Generate FSD Structure
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
create-fsd fsd [options]
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
#### Options
|
|
245
|
+
|
|
246
|
+
| Option | Alias | Description | Required |
|
|
247
|
+
|--------|-------|-------------|----------|
|
|
248
|
+
| `--feature <name>` | `-f` | Create feature in `features/` | One layer required |
|
|
249
|
+
| `--entity <name>` | `-e` | Create entity in `entities/` | One layer required |
|
|
250
|
+
| `--widget <name>` | `-w` | Create widget in `widgets/` | One layer required |
|
|
251
|
+
| `--page <name>` | `-p` | Create page in `pages/` | One layer required |
|
|
252
|
+
| `--segments <segments...>` | `-s` | Segments to create | Yes |
|
|
253
|
+
| `--index` | `-i` | Create index files | No |
|
|
254
|
+
|
|
255
|
+
#### Examples
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
# Create feature with index files
|
|
259
|
+
create-fsd fsd -f authentication -s ui model api -i
|
|
260
|
+
|
|
261
|
+
# Create entity without index files
|
|
262
|
+
create-fsd fsd -e user -s model api
|
|
263
|
+
|
|
264
|
+
# Create widget
|
|
265
|
+
create-fsd fsd -w sidebar -s ui lib -i
|
|
266
|
+
|
|
267
|
+
# Create page
|
|
268
|
+
create-fsd fsd -p dashboard -s ui model -i
|
|
269
|
+
```
|
|
270
|
+
|
|
173
271
|
---
|
|
174
272
|
|
|
175
273
|
## š Learn More
|
package/bin/cli.js
CHANGED
|
@@ -16,7 +16,7 @@ const program = new Command();
|
|
|
16
16
|
program
|
|
17
17
|
.name('create-fsd')
|
|
18
18
|
.description('CLI to create React projects with FSD architecture')
|
|
19
|
-
.version('
|
|
19
|
+
.version('2.0.0')
|
|
20
20
|
.argument('<project-name>', 'name of the project')
|
|
21
21
|
.option('-t, --template <template>', 'template to use', 'react')
|
|
22
22
|
.action(async (projectName, options) => {
|
|
@@ -81,4 +81,148 @@ program
|
|
|
81
81
|
console.log();
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
+
// FSD structure generation command
|
|
85
|
+
program
|
|
86
|
+
.command('fsd')
|
|
87
|
+
.description('Generate FSD (Feature-Sliced Design) structure')
|
|
88
|
+
.option('-f, --feature <name>', 'create feature in features/')
|
|
89
|
+
.option('-e, --entity <name>', 'create entity in entities/')
|
|
90
|
+
.option('-w, --widget <name>', 'create widget in widgets/')
|
|
91
|
+
.option('-p, --page <name>', 'create page in pages/')
|
|
92
|
+
.option('-s, --segments <segments...>', 'segments to create (e.g., model ui api lib)')
|
|
93
|
+
.option('-i, --index', 'create index files in root and all segments', false)
|
|
94
|
+
.action(async (options) => {
|
|
95
|
+
const { feature, entity, widget, page, segments, index } = options;
|
|
96
|
+
|
|
97
|
+
// Determine layer and name based on which flag was used
|
|
98
|
+
let layer, name, layerType;
|
|
99
|
+
|
|
100
|
+
if (feature) {
|
|
101
|
+
layer = 'features';
|
|
102
|
+
name = feature;
|
|
103
|
+
layerType = 'Feature';
|
|
104
|
+
} else if (entity) {
|
|
105
|
+
layer = 'entities';
|
|
106
|
+
name = entity;
|
|
107
|
+
layerType = 'Entity';
|
|
108
|
+
} else if (widget) {
|
|
109
|
+
layer = 'widgets';
|
|
110
|
+
name = widget;
|
|
111
|
+
layerType = 'Widget';
|
|
112
|
+
} else if (page) {
|
|
113
|
+
layer = 'pages';
|
|
114
|
+
name = page;
|
|
115
|
+
layerType = 'Page';
|
|
116
|
+
} else {
|
|
117
|
+
console.log(chalk.red('ā Layer flag is required! Use -f (feature), -e (entity), -w (widget), or -p (page)'));
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Validation
|
|
122
|
+
if (!segments || segments.length === 0) {
|
|
123
|
+
console.log(chalk.red('ā At least one segment is required! Use -s or --segments'));
|
|
124
|
+
process.exit(1);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
console.log(chalk.blue.bold(`\nšļø Generating FSD structure...\n`));
|
|
128
|
+
console.log(chalk.cyan(`Layer: ${layer}`));
|
|
129
|
+
console.log(chalk.cyan(`${layerType}: ${name}`));
|
|
130
|
+
console.log(chalk.cyan(`Segments: ${segments.join(', ')}`));
|
|
131
|
+
console.log(chalk.cyan(`Index files: ${index ? 'Yes' : 'No'}\n`));
|
|
132
|
+
|
|
133
|
+
const baseDir = path.join(process.cwd(), 'src', layer, name);
|
|
134
|
+
|
|
135
|
+
// Check if directory already exists
|
|
136
|
+
if (fs.existsSync(baseDir)) {
|
|
137
|
+
console.log(chalk.yellow(`ā ļø Directory ${layer}/${name} already exists!`));
|
|
138
|
+
console.log(chalk.yellow('Adding segments to existing structure...\n'));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Create directory
|
|
142
|
+
fs.mkdirSync(baseDir, { recursive: true });
|
|
143
|
+
|
|
144
|
+
// Create segments
|
|
145
|
+
const spinner = ora('Creating segments...').start();
|
|
146
|
+
try {
|
|
147
|
+
for (const segment of segments) {
|
|
148
|
+
const segmentDir = path.join(baseDir, segment);
|
|
149
|
+
fs.mkdirSync(segmentDir, { recursive: true });
|
|
150
|
+
|
|
151
|
+
// Create index file in segment if requested
|
|
152
|
+
if (index) {
|
|
153
|
+
const segmentIndexPath = path.join(segmentDir, 'index.js');
|
|
154
|
+
fs.writeFileSync(segmentIndexPath, '');
|
|
155
|
+
} else {
|
|
156
|
+
// Create a .gitkeep file to ensure empty directories are tracked
|
|
157
|
+
const gitkeepPath = path.join(segmentDir, '.gitkeep');
|
|
158
|
+
fs.writeFileSync(gitkeepPath, '');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
spinner.succeed('Segments created!');
|
|
162
|
+
} catch (error) {
|
|
163
|
+
spinner.fail('Failed to create segments');
|
|
164
|
+
console.error(error);
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Create index file if requested
|
|
169
|
+
if (index) {
|
|
170
|
+
const indexSpinner = ora('Creating root index file...').start();
|
|
171
|
+
try {
|
|
172
|
+
const indexPath = path.join(baseDir, 'index.js');
|
|
173
|
+
|
|
174
|
+
// If index file exists, read existing exports and merge with new ones
|
|
175
|
+
let existingExports = new Set();
|
|
176
|
+
if (fs.existsSync(indexPath)) {
|
|
177
|
+
const existingContent = fs.readFileSync(indexPath, 'utf-8');
|
|
178
|
+
const exportMatches = existingContent.matchAll(/export \* from ['"]\.\/(.+?)['"]/g);
|
|
179
|
+
for (const match of exportMatches) {
|
|
180
|
+
existingExports.add(match[1]);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Add new segments to existing exports
|
|
185
|
+
segments.forEach(segment => existingExports.add(segment));
|
|
186
|
+
|
|
187
|
+
// Generate exports for all segments
|
|
188
|
+
let indexContent = `// ${name} exports\n\n`;
|
|
189
|
+
|
|
190
|
+
// Sort segments for consistency
|
|
191
|
+
const allSegments = Array.from(existingExports).sort();
|
|
192
|
+
for (const segment of allSegments) {
|
|
193
|
+
indexContent += `export * from './${segment}';\n`;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
fs.writeFileSync(indexPath, indexContent);
|
|
197
|
+
|
|
198
|
+
if (existingExports.size > segments.length) {
|
|
199
|
+
indexSpinner.succeed('Root index file updated with new exports!');
|
|
200
|
+
} else {
|
|
201
|
+
indexSpinner.succeed('Root index file created!');
|
|
202
|
+
}
|
|
203
|
+
} catch (error) {
|
|
204
|
+
indexSpinner.fail('Failed to create root index file');
|
|
205
|
+
console.error(error);
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Success message
|
|
211
|
+
console.log(chalk.green.bold('\nā
FSD structure generated successfully!\n'));
|
|
212
|
+
console.log(chalk.cyan('Generated structure:'));
|
|
213
|
+
console.log(chalk.white(` src/${layer}/${name}/`));
|
|
214
|
+
segments.forEach((segment, idx) => {
|
|
215
|
+
const isLast = idx === segments.length - 1;
|
|
216
|
+
const prefix = index ? 'āāā' : (isLast ? 'āāā' : 'āāā');
|
|
217
|
+
console.log(chalk.white(` ${prefix} ${segment}/`));
|
|
218
|
+
if (index) {
|
|
219
|
+
console.log(chalk.white(` ā āāā index.js`));
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
if (index) {
|
|
223
|
+
console.log(chalk.white(` āāā index.js`));
|
|
224
|
+
}
|
|
225
|
+
console.log();
|
|
226
|
+
});
|
|
227
|
+
|
|
84
228
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@t1ep1l0t/create-fsd",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "CLI tool to create React projects with FSD architecture",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -24,7 +24,10 @@
|
|
|
24
24
|
],
|
|
25
25
|
"author": "t1ep1l0t",
|
|
26
26
|
"license": "MIT",
|
|
27
|
-
|
|
27
|
+
"repository": {
|
|
28
|
+
"url": "https://github.com/t1ep1l0t/create-fsd"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
28
31
|
"node": ">=16.0.0"
|
|
29
32
|
},
|
|
30
33
|
"dependencies": {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
* {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
html {
|
|
6
|
+
font-size: 14px;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
body {
|
|
10
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
11
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
12
|
+
sans-serif;
|
|
13
|
+
-webkit-font-smoothing: antialiased;
|
|
14
|
+
-moz-osx-font-smoothing: grayscale;
|
|
15
|
+
}
|
|
@@ -7,22 +7,3 @@
|
|
|
7
7
|
--color-danger: #ef4444;
|
|
8
8
|
--color-warning: #f59e0b;
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
* {
|
|
12
|
-
margin: 0;
|
|
13
|
-
padding: 0;
|
|
14
|
-
box-sizing: border-box;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
body {
|
|
18
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
19
|
-
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
20
|
-
sans-serif;
|
|
21
|
-
-webkit-font-smoothing: antialiased;
|
|
22
|
-
-moz-osx-font-smoothing: grayscale;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
code {
|
|
26
|
-
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
|
27
|
-
monospace;
|
|
28
|
-
}
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import '@app/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import ReactDOM from 'react-dom/client'
|
|
4
|
+
|
|
5
|
+
import { App } from '@app/App'
|
|
6
|
+
import '@app/styles/index.css'
|
|
7
|
+
import '@app/styles/global.css'
|
|
8
|
+
import '@app/providers/i18n'
|
|
9
|
+
|
|
10
|
+
ReactDOM.createRoot(document.getElementById('root')).render(
|
|
11
|
+
<React.StrictMode>
|
|
12
|
+
<App />
|
|
13
|
+
</React.StrictMode>
|
|
14
|
+
)
|