generator-bitloops 0.3.23 → 0.3.26
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 +1 -1
- package/package.json +1 -1
- package/setup/index.js +116 -92
- package/setup/templates/tsconfig.json +36 -0
package/README.md
CHANGED
|
@@ -6,4 +6,4 @@ Nonetheless, you can use it independently to setup your next Next.js project wit
|
|
|
6
6
|
|
|
7
7
|
## How to run it
|
|
8
8
|
|
|
9
|
-
`npx -y generator-bitloops setup --project="Your Project Name" --nextjs --typescript --tailwind --storybook --cypress`
|
|
9
|
+
`npx -y generator-bitloops setup --project="Your Project Name" --nextjs --i18n --typescript --tailwind --storybook --cypress`
|
package/package.json
CHANGED
package/setup/index.js
CHANGED
|
@@ -111,17 +111,24 @@ export default class extends Generator {
|
|
|
111
111
|
default: false,
|
|
112
112
|
});
|
|
113
113
|
|
|
114
|
+
this.option('i18n', {
|
|
115
|
+
type: Boolean,
|
|
116
|
+
description:
|
|
117
|
+
'Add i18n internationalization support (i18next, i18next-icu, react-i18next)',
|
|
118
|
+
default: false,
|
|
119
|
+
});
|
|
120
|
+
|
|
114
121
|
this.installNextJS = async function () {
|
|
115
122
|
// Clone Next.js template with Tailwind if specified, using the project name
|
|
116
|
-
const createNextAppCommand = ['-y', 'create-next-app@
|
|
123
|
+
const createNextAppCommand = ['-y', 'create-next-app@latest'];
|
|
117
124
|
createNextAppCommand.push(toKebabCase(this.options.project)); // Use the project name for the directory
|
|
125
|
+
createNextAppCommand.push('--yes');
|
|
118
126
|
createNextAppCommand.push('--app');
|
|
119
127
|
createNextAppCommand.push('--empty');
|
|
120
128
|
createNextAppCommand.push('--src-dir');
|
|
121
|
-
createNextAppCommand.push('--turbopack'); // when we go to Next.js 15
|
|
122
129
|
createNextAppCommand.push('--import-alias');
|
|
123
130
|
createNextAppCommand.push('@/*');
|
|
124
|
-
createNextAppCommand.push('--use-
|
|
131
|
+
createNextAppCommand.push('--use-pnpm');
|
|
125
132
|
createNextAppCommand.push('--eslint');
|
|
126
133
|
|
|
127
134
|
if (this.options.typescript) {
|
|
@@ -140,11 +147,11 @@ export default class extends Generator {
|
|
|
140
147
|
await new Promise((resolve, error) => {
|
|
141
148
|
exec(
|
|
142
149
|
`npx ${createNextAppCommand.join(' ')} && cd ${toKebabCase(
|
|
143
|
-
this.options.project
|
|
144
|
-
)} &&
|
|
150
|
+
this.options.project,
|
|
151
|
+
)} && pnpm add ${additionalPackages}`,
|
|
145
152
|
).on('exit', (code) => {
|
|
146
153
|
this.destinationRoot(
|
|
147
|
-
this.destinationPath(toKebabCase(this.options.project))
|
|
154
|
+
this.destinationPath(toKebabCase(this.options.project)),
|
|
148
155
|
);
|
|
149
156
|
resolve();
|
|
150
157
|
});
|
|
@@ -160,33 +167,50 @@ export default class extends Generator {
|
|
|
160
167
|
});
|
|
161
168
|
const versions = JSON.parse(versionsRaw);
|
|
162
169
|
|
|
163
|
-
// Filter for stable
|
|
170
|
+
// Filter for stable 10.x versions (exclude alpha/beta/rc)
|
|
164
171
|
const stableVersions = versions
|
|
165
|
-
.filter(version => version.startsWith('
|
|
166
|
-
.filter(version => !version.includes('-')); // Exclude pre-releases like -alpha or -beta
|
|
172
|
+
.filter((version) => version.startsWith('10.'))
|
|
173
|
+
.filter((version) => !version.includes('-')); // Exclude pre-releases like -alpha or -beta
|
|
167
174
|
|
|
168
175
|
// Sort descending and get the latest
|
|
169
|
-
const
|
|
170
|
-
.
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
throw new Error('No stable 9.0.x versions found.');
|
|
176
|
+
const latest10 = stableVersions.sort((a, b) => {
|
|
177
|
+
// Split version strings like '10.0.9' into [10, 0, 9]
|
|
178
|
+
const aParts = a.split(DOT).map(Number);
|
|
179
|
+
const bParts = b.split(DOT).map(Number);
|
|
180
|
+
// Compare major, then minor, then patch
|
|
181
|
+
if (aParts[0] !== bParts[0]) return bParts[0] - aParts[0];
|
|
182
|
+
if (aParts[1] !== bParts[1]) return bParts[1] - aParts[1];
|
|
183
|
+
return bParts[2] - aParts[2];
|
|
184
|
+
})[0];
|
|
185
|
+
|
|
186
|
+
if (!latest10) {
|
|
187
|
+
throw new Error('No stable 10.x versions found.');
|
|
182
188
|
}
|
|
183
189
|
|
|
184
|
-
this.log(`Latest stable
|
|
185
|
-
//Initializing
|
|
186
|
-
spawnSync(
|
|
190
|
+
this.log(`Latest stable 10.x version: ${latest10}`);
|
|
191
|
+
// Initializing storybook with nextjs+vite
|
|
192
|
+
spawnSync(
|
|
193
|
+
'npx',
|
|
194
|
+
[
|
|
195
|
+
'-y',
|
|
196
|
+
`storybook@${latest10}`,
|
|
197
|
+
'init',
|
|
198
|
+
'--no-dev',
|
|
199
|
+
'--yes',
|
|
200
|
+
'--type',
|
|
201
|
+
'nextjs',
|
|
202
|
+
'--builder',
|
|
203
|
+
'vite',
|
|
204
|
+
],
|
|
205
|
+
{ stdio: 'inherit', cwd: this.destinationRoot() },
|
|
206
|
+
);
|
|
187
207
|
this.log('Storybook installed!');
|
|
188
|
-
//Verifies the correct nextjs-vite framework is used
|
|
189
|
-
spawnSync(
|
|
208
|
+
// Verifies the correct nextjs-vite framework is used
|
|
209
|
+
spawnSync(
|
|
210
|
+
'pnpm',
|
|
211
|
+
['add', '-D', '@storybook/nextjs-vite@^10'],
|
|
212
|
+
{ stdio: 'inherit', cwd: this.destinationRoot() },
|
|
213
|
+
);
|
|
190
214
|
this.log('@storybook/nextjs-vite installed!');
|
|
191
215
|
}
|
|
192
216
|
};
|
|
@@ -195,44 +219,64 @@ export default class extends Generator {
|
|
|
195
219
|
// Conditionally add Cypress
|
|
196
220
|
if (this.options.cypress) {
|
|
197
221
|
this.log('Installing Cypress...');
|
|
198
|
-
spawnSync('
|
|
222
|
+
spawnSync('pnpm', ['add', '-D', 'cypress'], {
|
|
223
|
+
stdio: 'inherit',
|
|
224
|
+
cwd: this.destinationRoot(),
|
|
225
|
+
});
|
|
199
226
|
this.log('Cypress installed!');
|
|
200
227
|
if (this.options.bitloops) {
|
|
201
|
-
spawnSync(
|
|
202
|
-
'
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
228
|
+
spawnSync(
|
|
229
|
+
'pnpm',
|
|
230
|
+
[
|
|
231
|
+
'add',
|
|
232
|
+
'-D',
|
|
233
|
+
'mochawesome',
|
|
234
|
+
'mochawesome-merge',
|
|
235
|
+
'mochawesome-report-generator',
|
|
236
|
+
],
|
|
237
|
+
{ stdio: 'inherit', cwd: this.destinationRoot() },
|
|
238
|
+
);
|
|
208
239
|
}
|
|
209
240
|
}
|
|
210
241
|
};
|
|
211
242
|
|
|
243
|
+
this.installI18n = function () {
|
|
244
|
+
// Conditionally add i18n packages
|
|
245
|
+
if (this.options.i18n) {
|
|
246
|
+
this.log('Installing i18n packages...');
|
|
247
|
+
spawnSync(
|
|
248
|
+
'pnpm',
|
|
249
|
+
['add', 'i18next', 'i18next-icu', 'react-i18next'],
|
|
250
|
+
{ stdio: 'inherit', cwd: this.destinationRoot() },
|
|
251
|
+
);
|
|
252
|
+
this.log('i18n packages installed!');
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
|
|
212
256
|
this.installPrimitives = function () {
|
|
213
257
|
// Conditionally add Primitives
|
|
214
258
|
if (this.options.primitives) {
|
|
215
259
|
this.log('Installing Primitives...');
|
|
216
|
-
|
|
260
|
+
|
|
217
261
|
const platformNextIndexPath = `${PLATFORM_NEXT_SRC_FOLDER}/index.ts`;
|
|
218
262
|
deleteFileIfExists(this.destinationPath(platformNextIndexPath));
|
|
219
263
|
this.fs.copyTpl(
|
|
220
264
|
this.templatePath(platformNextIndexPath),
|
|
221
|
-
this.destinationPath(platformNextIndexPath)
|
|
265
|
+
this.destinationPath(platformNextIndexPath),
|
|
222
266
|
);
|
|
223
267
|
|
|
224
268
|
const platformNextImgPath = `${PLATFORM_NEXT_SRC_FOLDER}/Img.tsx`;
|
|
225
269
|
deleteFileIfExists(this.destinationPath(platformNextImgPath));
|
|
226
270
|
this.fs.copyTpl(
|
|
227
271
|
this.templatePath(platformNextImgPath),
|
|
228
|
-
this.destinationPath(platformNextImgPath)
|
|
272
|
+
this.destinationPath(platformNextImgPath),
|
|
229
273
|
);
|
|
230
274
|
|
|
231
275
|
const platformNextTypesPath = `${PLATFORM_NEXT_SRC_FOLDER}/types.ts`;
|
|
232
276
|
deleteFileIfExists(this.destinationPath(platformNextTypesPath));
|
|
233
277
|
this.fs.copyTpl(
|
|
234
278
|
this.templatePath(platformNextTypesPath),
|
|
235
|
-
this.destinationPath(platformNextTypesPath)
|
|
279
|
+
this.destinationPath(platformNextTypesPath),
|
|
236
280
|
);
|
|
237
281
|
|
|
238
282
|
this.log('Primitives installed!');
|
|
@@ -248,7 +292,7 @@ export default class extends Generator {
|
|
|
248
292
|
this.log('Setting up Tailwind CSS with Storybook...');
|
|
249
293
|
this.fs.copyTpl(
|
|
250
294
|
this.templatePath('storybook.preview.ts'),
|
|
251
|
-
this.destinationPath('.storybook/preview.ts')
|
|
295
|
+
this.destinationPath('.storybook/preview.ts'),
|
|
252
296
|
);
|
|
253
297
|
}
|
|
254
298
|
this.log('Removing default Storybook stories...');
|
|
@@ -267,58 +311,38 @@ export default class extends Generator {
|
|
|
267
311
|
this.log('Adding Cypress config...');
|
|
268
312
|
this.fs.copyTpl(
|
|
269
313
|
this.templatePath('cypress.config.ts'),
|
|
270
|
-
this.destinationPath('cypress.config.ts')
|
|
314
|
+
this.destinationPath('cypress.config.ts'),
|
|
271
315
|
);
|
|
272
316
|
}
|
|
273
317
|
|
|
274
318
|
deleteFileIfExists(this.destinationPath('src/app/page.tsx'));
|
|
275
319
|
this.fs.copyTpl(
|
|
276
320
|
this.templatePath('next.app.page.tsx'),
|
|
277
|
-
this.destinationPath('src/app/page.tsx')
|
|
321
|
+
this.destinationPath('src/app/page.tsx'),
|
|
278
322
|
);
|
|
279
323
|
|
|
280
324
|
deleteFileIfExists(this.destinationPath('src/app/layout.tsx'));
|
|
281
325
|
this.fs.copyTpl(
|
|
282
326
|
this.templatePath('next.app.layout.tsx'),
|
|
283
327
|
this.destinationPath('src/app/layout.tsx'),
|
|
284
|
-
{ projectName: this.options.project }
|
|
328
|
+
{ projectName: this.options.project },
|
|
285
329
|
);
|
|
286
330
|
|
|
287
331
|
this.log('Adding Meyer reset in global.css...');
|
|
288
332
|
deleteFileIfExists(this.destinationPath('src/app/globals.css'));
|
|
289
333
|
this.fs.copyTpl(
|
|
290
334
|
this.templatePath('globals.css'),
|
|
291
|
-
this.destinationPath('src/app/globals.css')
|
|
335
|
+
this.destinationPath('src/app/globals.css'),
|
|
292
336
|
);
|
|
293
337
|
|
|
294
338
|
if (this.options.typescript) {
|
|
295
|
-
this.log('
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if (!tsconfig.compilerOptions) {
|
|
303
|
-
tsconfig.compilerOptions = {};
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// Initialize paths if it doesn't exist
|
|
307
|
-
if (!tsconfig.compilerOptions.paths) {
|
|
308
|
-
tsconfig.compilerOptions.paths = {};
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Add or merge the path aliases
|
|
312
|
-
tsconfig.compilerOptions.paths = {
|
|
313
|
-
...tsconfig.compilerOptions.paths,
|
|
314
|
-
"@/primitives": ["./platform-next/src"],
|
|
315
|
-
"@/assets": ["./src/assets"]
|
|
316
|
-
};
|
|
317
|
-
|
|
318
|
-
deleteFileIfExists(tsconfigPath);
|
|
319
|
-
this.fs.write(tsconfigPath, JSON.stringify(tsconfig, null, 2) + '\n');
|
|
320
|
-
this.log('tsconfig.json paths updated!');
|
|
321
|
-
}
|
|
339
|
+
this.log('Replacing tsconfig.json with Bitloops template...');
|
|
340
|
+
deleteFileIfExists(this.destinationPath('tsconfig.json'));
|
|
341
|
+
this.fs.copyTpl(
|
|
342
|
+
this.templatePath('tsconfig.json'),
|
|
343
|
+
this.destinationPath('tsconfig.json'),
|
|
344
|
+
);
|
|
345
|
+
this.log('tsconfig.json updated!');
|
|
322
346
|
}
|
|
323
347
|
|
|
324
348
|
if (this.options.bitloops) {
|
|
@@ -327,36 +351,35 @@ export default class extends Generator {
|
|
|
327
351
|
'src/components/bitloops/unsupported/Unsupported.tsx';
|
|
328
352
|
this.fs.copyTpl(
|
|
329
353
|
this.templatePath(unsupportedPath),
|
|
330
|
-
this.destinationPath(unsupportedPath)
|
|
354
|
+
this.destinationPath(unsupportedPath),
|
|
331
355
|
);
|
|
332
356
|
const buttonPath = 'src/components/bitloops/button/Button.tsx';
|
|
333
357
|
this.fs.copyTpl(
|
|
334
358
|
this.templatePath(buttonPath),
|
|
335
|
-
this.destinationPath(buttonPath)
|
|
359
|
+
this.destinationPath(buttonPath),
|
|
336
360
|
);
|
|
337
361
|
if (this.options.storybook) {
|
|
338
362
|
const unsupportedPath =
|
|
339
363
|
'src/components/bitloops/unsupported/Unsupported.stories.tsx';
|
|
340
364
|
this.fs.copyTpl(
|
|
341
365
|
this.templatePath(unsupportedPath),
|
|
342
|
-
this.destinationPath(unsupportedPath)
|
|
366
|
+
this.destinationPath(unsupportedPath),
|
|
343
367
|
);
|
|
344
368
|
const buttonPath =
|
|
345
369
|
'src/components/bitloops/button/Button.stories.tsx';
|
|
346
370
|
this.fs.copyTpl(
|
|
347
371
|
this.templatePath(buttonPath),
|
|
348
|
-
this.destinationPath(buttonPath)
|
|
372
|
+
this.destinationPath(buttonPath),
|
|
349
373
|
);
|
|
350
374
|
}
|
|
351
375
|
if (this.options.cypress) {
|
|
352
376
|
const path = 'cypress/helpers/index.ts';
|
|
353
377
|
this.fs.copyTpl(this.templatePath(path), this.destinationPath(path));
|
|
354
378
|
}
|
|
355
|
-
spawnSync('
|
|
356
|
-
'
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
], { stdio: 'inherit', cwd: this.destinationRoot() });
|
|
379
|
+
spawnSync('pnpm', ['add', '-D', 'react-aria-components'], {
|
|
380
|
+
stdio: 'inherit',
|
|
381
|
+
cwd: this.destinationRoot(),
|
|
382
|
+
});
|
|
360
383
|
}
|
|
361
384
|
};
|
|
362
385
|
|
|
@@ -365,8 +388,8 @@ export default class extends Generator {
|
|
|
365
388
|
await new Promise((resolve) => {
|
|
366
389
|
exec(
|
|
367
390
|
`cd ${toKebabCase(
|
|
368
|
-
this.options.project
|
|
369
|
-
)} && git add . && git commit -m "Initial setup"
|
|
391
|
+
this.options.project,
|
|
392
|
+
)} && git add . && git commit -m "Initial setup"`,
|
|
370
393
|
).on('exit', (code) => {
|
|
371
394
|
if (code !== 0) {
|
|
372
395
|
this.log('Error committing changes to git! ', code);
|
|
@@ -383,30 +406,31 @@ export default class extends Generator {
|
|
|
383
406
|
// Check if the project name and --nextjs flag are provided
|
|
384
407
|
if (!this.options.project) {
|
|
385
408
|
this.log(
|
|
386
|
-
'Error: --project option is required to specify the project name.'
|
|
409
|
+
'Error: --project option is required to specify the project name.',
|
|
387
410
|
);
|
|
388
411
|
process.exit(1);
|
|
389
412
|
}
|
|
390
413
|
|
|
391
414
|
if (!this.options.nextjs) {
|
|
392
415
|
this.log(
|
|
393
|
-
'Error: --nextjs option is currently required to scaffold a project.'
|
|
416
|
+
'Error: --nextjs option is currently required to scaffold a project.',
|
|
394
417
|
);
|
|
395
418
|
process.exit(1);
|
|
396
419
|
}
|
|
397
420
|
|
|
398
421
|
this.log(
|
|
399
422
|
`Initializing project ${toKebabCase(
|
|
400
|
-
this.options.project
|
|
401
|
-
)} with the selected options
|
|
423
|
+
this.options.project,
|
|
424
|
+
)} with the selected options...`,
|
|
402
425
|
);
|
|
403
426
|
}
|
|
404
427
|
|
|
405
428
|
async main() {
|
|
406
429
|
await this.installNextJS();
|
|
407
|
-
this.installStorybook();
|
|
408
430
|
this.installCypress();
|
|
431
|
+
this.installI18n();
|
|
409
432
|
this.installPrimitives();
|
|
433
|
+
this.installStorybook();
|
|
410
434
|
await this.patchFiles();
|
|
411
435
|
if (this.options.git) {
|
|
412
436
|
await this.commitChanges();
|
|
@@ -416,19 +440,19 @@ export default class extends Generator {
|
|
|
416
440
|
end() {
|
|
417
441
|
this.log(
|
|
418
442
|
`Your Bitloops project '${toKebabCase(
|
|
419
|
-
this.options.project
|
|
420
|
-
)}' setup is complete!
|
|
443
|
+
this.options.project,
|
|
444
|
+
)}' setup is complete! 🎉🎉🎉`,
|
|
421
445
|
);
|
|
422
446
|
this.log('');
|
|
423
447
|
this.log('Use the following commands to start:');
|
|
424
|
-
this.log('- `
|
|
448
|
+
this.log('- `pnpm dev` to start the Next.js app.');
|
|
425
449
|
if (this.options.storybook)
|
|
426
|
-
this.log('- `
|
|
450
|
+
this.log('- `pnpm storybook` to start Storybook.');
|
|
427
451
|
if (this.options.cypress)
|
|
428
452
|
this.log('- `npx cypress open --e2e --browser chrome` to open Cypress.');
|
|
429
453
|
if (this.options.cypress)
|
|
430
454
|
this.log(
|
|
431
|
-
'- `npx cypress run --e2e --browser chrome` to run Cypress on the terminal.'
|
|
455
|
+
'- `npx cypress run --e2e --browser chrome` to run Cypress on the terminal.',
|
|
432
456
|
);
|
|
433
457
|
}
|
|
434
458
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"strict": true,
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"module": "esnext",
|
|
11
|
+
"moduleResolution": "bundler",
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"isolatedModules": true,
|
|
14
|
+
"jsx": "preserve",
|
|
15
|
+
"incremental": true,
|
|
16
|
+
"plugins": [
|
|
17
|
+
{
|
|
18
|
+
"name": "next"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"baseUrl": ".",
|
|
22
|
+
"paths": {
|
|
23
|
+
"@/*": ["src/*"],
|
|
24
|
+
"@/components/*": ["src/components/*"],
|
|
25
|
+
"@/assets/*": ["src/assets/*"],
|
|
26
|
+
"@/primitives": ["platform-next/src"],
|
|
27
|
+
"@/primitives/*": ["platform-next/src/*"],
|
|
28
|
+
"@/hooks/*": ["src/hooks/*"],
|
|
29
|
+
"@/lib/*": ["src/lib/*"],
|
|
30
|
+
"@/types/*": ["src/types/*"],
|
|
31
|
+
"@/utils/*": ["src/utils/*"]
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
35
|
+
"exclude": ["node_modules"]
|
|
36
|
+
}
|