create-hsi-app 0.6.0 → 0.6.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/README.md +2 -2
- package/bin/create-hsi-app.mjs +88 -10
- package/package.json +1 -1
package/README.md
CHANGED
package/bin/create-hsi-app.mjs
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
} from './ui.mjs';
|
|
25
25
|
|
|
26
26
|
const templateRepo = 'https://github.com/Hsiii/frontend-template.git';
|
|
27
|
-
const templateTag = 'v0.6.
|
|
27
|
+
const templateTag = 'v0.6.1';
|
|
28
28
|
const defaultAppName = 'my-app';
|
|
29
29
|
const packageManagers = ['bun', 'npm', 'pnpm', 'yarn'];
|
|
30
30
|
const nextVersion = '16.2.7';
|
|
@@ -82,6 +82,7 @@ async function main() {
|
|
|
82
82
|
console.log(`- framework: ${frameworkLabel(selectedFramework)}`);
|
|
83
83
|
console.log(`- package.json: name, version, scripts, packageManager`);
|
|
84
84
|
logFrameworkFileChanges();
|
|
85
|
+
console.log(`- .gitignore: framework build artifacts`);
|
|
85
86
|
console.log(`- README.md: install/dev/check commands`);
|
|
86
87
|
console.log(`- package manager config: ${packageManagerConfigFile()}`);
|
|
87
88
|
if (selectedPackageManager === 'bun') {
|
|
@@ -89,6 +90,7 @@ async function main() {
|
|
|
89
90
|
}
|
|
90
91
|
updateFrameworkFiles();
|
|
91
92
|
updateAppText();
|
|
93
|
+
updateGitIgnore();
|
|
92
94
|
updatePackageManagerFiles();
|
|
93
95
|
writeAppReadme();
|
|
94
96
|
|
|
@@ -135,7 +137,7 @@ function updatePackageJson() {
|
|
|
135
137
|
if (selectedFramework === 'next') {
|
|
136
138
|
packageJson.scripts.dev = 'next dev';
|
|
137
139
|
packageJson.scripts.build = 'next build';
|
|
138
|
-
packageJson.scripts.preview
|
|
140
|
+
delete packageJson.scripts.preview;
|
|
139
141
|
packageJson.scripts.check =
|
|
140
142
|
'tsc -p tsconfig.json --noEmit && eslint . && prettier . --check && next build';
|
|
141
143
|
packageJson.dependencies.next = nextVersion;
|
|
@@ -191,6 +193,14 @@ function updateFrameworkFiles() {
|
|
|
191
193
|
}
|
|
192
194
|
}
|
|
193
195
|
|
|
196
|
+
function updateGitIgnore() {
|
|
197
|
+
if (selectedFramework !== 'next') {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
appendGitIgnoreEntries(['.next/', 'next-env.d.ts']);
|
|
202
|
+
}
|
|
203
|
+
|
|
194
204
|
function updatePackageManagerFiles() {
|
|
195
205
|
rmSync(join(targetPath, 'bunfig.toml'), { force: true });
|
|
196
206
|
rmSync(join(targetPath, '.npmrc'), { force: true });
|
|
@@ -250,7 +260,7 @@ function writeAppReadme() {
|
|
|
250
260
|
const securityNote = securityNoteForPackageManager();
|
|
251
261
|
const readme = `# ${appName}
|
|
252
262
|
|
|
253
|
-
Created from the ${
|
|
263
|
+
Created from the ${frameworkDescription(selectedFramework)} frontend template.
|
|
254
264
|
|
|
255
265
|
## Install
|
|
256
266
|
|
|
@@ -440,6 +450,30 @@ function replaceInFile(filePath, searchValue, replacement) {
|
|
|
440
450
|
writeFileSync(filePath, source.replace(searchValue, replacement.with));
|
|
441
451
|
}
|
|
442
452
|
|
|
453
|
+
function appendGitIgnoreEntries(entries) {
|
|
454
|
+
const gitIgnorePath = join(targetPath, '.gitignore');
|
|
455
|
+
|
|
456
|
+
if (!existsSync(gitIgnorePath)) {
|
|
457
|
+
writeFileSync(gitIgnorePath, `${entries.join('\n')}\n`);
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
const source = readFileSync(gitIgnorePath, 'utf8');
|
|
462
|
+
const lines = new Set(source.split('\n').filter(Boolean));
|
|
463
|
+
let nextSource = source;
|
|
464
|
+
|
|
465
|
+
for (const entry of entries) {
|
|
466
|
+
if (lines.has(entry)) {
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
nextSource += nextSource.endsWith('\n') ? `${entry}\n` : `\n${entry}\n`;
|
|
471
|
+
lines.add(entry);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
writeFileSync(gitIgnorePath, nextSource);
|
|
475
|
+
}
|
|
476
|
+
|
|
443
477
|
function toPackageName(value) {
|
|
444
478
|
const name = value
|
|
445
479
|
.trim()
|
|
@@ -539,9 +573,9 @@ function readNpmBooleanFlag(name) {
|
|
|
539
573
|
function logFrameworkFileChanges() {
|
|
540
574
|
if (selectedFramework === 'next') {
|
|
541
575
|
console.log(
|
|
542
|
-
`- Next app router files: src/app/layout.tsx, src/app/
|
|
576
|
+
`- Next app router files: src/app/layout.tsx, src/app/[[...slug]]/*`
|
|
543
577
|
);
|
|
544
|
-
console.log(`- src/app/global.css: app styles`);
|
|
578
|
+
console.log(`- src/app/global.css: app styles and client bootstrap`);
|
|
545
579
|
console.log(`- Next config: next.config.mjs, next-env.d.ts`);
|
|
546
580
|
console.log(
|
|
547
581
|
`- Vite files removed: index.html, vite.config.mjs, src/main.tsx`
|
|
@@ -561,15 +595,18 @@ function writeNextAppFiles() {
|
|
|
561
595
|
rmSync(join(targetPath, 'src/global.css'), { force: true });
|
|
562
596
|
|
|
563
597
|
const appPath = join(targetPath, 'src/app');
|
|
598
|
+
const catchAllPath = join(appPath, '[[...slug]]');
|
|
564
599
|
mkdirSync(appPath, { recursive: true });
|
|
600
|
+
mkdirSync(catchAllPath, { recursive: true });
|
|
565
601
|
|
|
566
602
|
writeFileSync(join(targetPath, 'next-env.d.ts'), nextEnvTypes());
|
|
567
603
|
writeFileSync(join(targetPath, 'next.config.mjs'), nextConfig());
|
|
568
604
|
writeFileSync(join(targetPath, 'eslint.config.mjs'), nextEslintConfig());
|
|
569
605
|
writeFileSync(join(targetPath, 'tsconfig.json'), nextTsconfig());
|
|
570
606
|
writeFileSync(join(appPath, 'layout.tsx'), nextLayout());
|
|
571
|
-
writeFileSync(join(appPath, 'page.tsx'), nextPage());
|
|
572
607
|
writeFileSync(join(appPath, 'global.css'), nextGlobalCss());
|
|
608
|
+
writeFileSync(join(catchAllPath, 'client.tsx'), nextClientPage());
|
|
609
|
+
writeFileSync(join(catchAllPath, 'page.tsx'), nextPage());
|
|
573
610
|
}
|
|
574
611
|
|
|
575
612
|
function frameworkLabel(framework) {
|
|
@@ -583,6 +620,17 @@ function frameworkLabel(framework) {
|
|
|
583
620
|
}
|
|
584
621
|
}
|
|
585
622
|
|
|
623
|
+
function frameworkDescription(framework) {
|
|
624
|
+
switch (framework) {
|
|
625
|
+
case 'vite':
|
|
626
|
+
return 'Vite';
|
|
627
|
+
case 'next':
|
|
628
|
+
return 'Next.js App Router SPA';
|
|
629
|
+
default:
|
|
630
|
+
fail(`Unsupported framework: ${framework}`);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
586
634
|
function frameworkTitle(framework) {
|
|
587
635
|
switch (framework) {
|
|
588
636
|
case 'vite':
|
|
@@ -624,7 +672,10 @@ function nextEnvTypes() {
|
|
|
624
672
|
|
|
625
673
|
function nextConfig() {
|
|
626
674
|
return `/** @type {import("next").NextConfig} */
|
|
627
|
-
const nextConfig = {
|
|
675
|
+
const nextConfig = {
|
|
676
|
+
output: 'export',
|
|
677
|
+
distDir: './dist',
|
|
678
|
+
};
|
|
628
679
|
|
|
629
680
|
export default nextConfig;
|
|
630
681
|
`;
|
|
@@ -638,7 +689,7 @@ export default [
|
|
|
638
689
|
...completeConfigBase,
|
|
639
690
|
|
|
640
691
|
{
|
|
641
|
-
ignores: ['.next/**', 'node_modules/**'],
|
|
692
|
+
ignores: ['.next/**', 'dist/**', 'node_modules/**'],
|
|
642
693
|
},
|
|
643
694
|
|
|
644
695
|
{
|
|
@@ -667,6 +718,9 @@ export default [
|
|
|
667
718
|
{
|
|
668
719
|
files: ['src/app/**/*.tsx'],
|
|
669
720
|
rules: {
|
|
721
|
+
'complete/no-mutable-return': 'off',
|
|
722
|
+
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
723
|
+
'n/file-extension-in-import': 'off',
|
|
670
724
|
'import-x/no-default-export': 'off',
|
|
671
725
|
},
|
|
672
726
|
},
|
|
@@ -739,13 +793,37 @@ export default function RootLayout({ children }: RootLayoutProps): JSX.Element {
|
|
|
739
793
|
`;
|
|
740
794
|
}
|
|
741
795
|
|
|
796
|
+
function nextClientPage() {
|
|
797
|
+
return `'use client';
|
|
798
|
+
|
|
799
|
+
import type { JSX } from 'react';
|
|
800
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
801
|
+
|
|
802
|
+
import { App } from '@/components/App';
|
|
803
|
+
|
|
804
|
+
const queryClient = new QueryClient();
|
|
805
|
+
|
|
806
|
+
export function ClientOnly(): JSX.Element {
|
|
807
|
+
return (
|
|
808
|
+
<QueryClientProvider client={queryClient}>
|
|
809
|
+
<App />
|
|
810
|
+
</QueryClientProvider>
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
`;
|
|
814
|
+
}
|
|
815
|
+
|
|
742
816
|
function nextPage() {
|
|
743
817
|
return `import type { JSX } from 'react';
|
|
744
818
|
|
|
745
|
-
import {
|
|
819
|
+
import { ClientOnly } from './client';
|
|
820
|
+
|
|
821
|
+
export function generateStaticParams() {
|
|
822
|
+
return [{ slug: [''] }];
|
|
823
|
+
}
|
|
746
824
|
|
|
747
825
|
export default function HomePage(): JSX.Element {
|
|
748
|
-
return <
|
|
826
|
+
return <ClientOnly />;
|
|
749
827
|
}
|
|
750
828
|
`;
|
|
751
829
|
}
|