create-react-adam 0.1.0
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 +182 -0
- package/bin/index.js +245 -0
- package/package.json +43 -0
- package/template/.e2e-deps.json +11 -0
- package/template/.github/renovate.json +24 -0
- package/template/.github/workflows/check.yml +36 -0
- package/template/.github/workflows/e2e.yml +48 -0
- package/template/.nvmrc +2 -0
- package/template/.prettierrc +3 -0
- package/template/README.md +83 -0
- package/template/e2e/README.md +94 -0
- package/template/e2e/example.spec.ts +14 -0
- package/template/eslint.config.js +54 -0
- package/template/index.html +12 -0
- package/template/package-lock.json +6571 -0
- package/template/package.json +47 -0
- package/template/playwright.config.ts +25 -0
- package/template/src/App.tsx +17 -0
- package/template/src/app.css +29 -0
- package/template/src/main.tsx +13 -0
- package/template/src/pages/About/index.no-utils.tsx +39 -0
- package/template/src/pages/About/index.tsx +97 -0
- package/template/src/pages/Home/index.no-utils.tsx +53 -0
- package/template/src/pages/Home/index.tsx +94 -0
- package/template/src/pages/NotFound/index.tsx +23 -0
- package/template/src/utils/Internet.ts +22 -0
- package/template/src/utils/Storage.ts +86 -0
- package/template/src/utils/classNames.ts +3 -0
- package/template/src/utils/useUrlState.ts +27 -0
- package/template/src/vite-env.d.ts +1 -0
- package/template/tsconfig.json +21 -0
- package/template/vite.config.ts +9 -0
package/README.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# create-react-adam
|
|
2
|
+
|
|
3
|
+
Create opinionated React apps with TypeScript, Vite, Wouter, and Tailwind CSS.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx create-react-adam@latest my-app
|
|
9
|
+
cd my-app
|
|
10
|
+
npm run dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## CLI Options
|
|
14
|
+
|
|
15
|
+
- `--dir <path>` - Create the project in a specific directory
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm create react-adam@latest my-app --dir ~/projects
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
- `--with-e2e` - Include E2E testing setup without prompting
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm create react-adam@latest my-app --with-e2e
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- `--no-e2e` - Skip E2E testing setup without prompting
|
|
28
|
+
```bash
|
|
29
|
+
npm create react-adam@latest my-app --no-e2e
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## What's Included
|
|
33
|
+
|
|
34
|
+
### Core Stack
|
|
35
|
+
|
|
36
|
+
- **React** - Latest version with TypeScript support
|
|
37
|
+
- **Vite** - Lightning-fast development server with HMR
|
|
38
|
+
- **Wouter** - Minimalist client-side routing (~1.3kB)
|
|
39
|
+
- **Tailwind CSS 4** - Utility-first CSS
|
|
40
|
+
- **React Icons** - Popular icon library
|
|
41
|
+
|
|
42
|
+
### Code Quality Tools
|
|
43
|
+
|
|
44
|
+
#### ESLint
|
|
45
|
+
|
|
46
|
+
Configured with a modern flat config (`eslint.config.js`) that includes:
|
|
47
|
+
|
|
48
|
+
- **TypeScript ESLint** - Recommended and strict presets for type-safe code
|
|
49
|
+
- **React Hooks** - Ensures correct hooks usage patterns
|
|
50
|
+
- **React Refresh** - Validates fast refresh compatibility
|
|
51
|
+
- **JSX Accessibility** - Enforces accessibility best practices (a11y)
|
|
52
|
+
- **Prettier integration** - Disables conflicting formatting rules
|
|
53
|
+
|
|
54
|
+
Why ESLint? It catches bugs early, enforces consistent code patterns, and integrates seamlessly with TypeScript. The strict preset helps maintain high code quality standards.
|
|
55
|
+
|
|
56
|
+
#### Prettier
|
|
57
|
+
|
|
58
|
+
Configured with two powerful plugins:
|
|
59
|
+
|
|
60
|
+
- **prettier-plugin-organize-imports** - Automatically sorts and removes unused imports
|
|
61
|
+
- **prettier-plugin-tailwindcss** - Sorts Tailwind class names consistently
|
|
62
|
+
|
|
63
|
+
Why Prettier? It eliminates debates about code style by automatically formatting code. The organize-imports plugin keeps imports clean, and the Tailwind plugin ensures class names follow the recommended ordering.
|
|
64
|
+
|
|
65
|
+
### Optional E2E Testing
|
|
66
|
+
|
|
67
|
+
When you include E2E testing (via prompt or `--with-e2e` flag), you get:
|
|
68
|
+
|
|
69
|
+
- **Playwright** - Modern, reliable E2E testing framework
|
|
70
|
+
- **Allure Reports** - Beautiful, detailed test reports
|
|
71
|
+
- Pre-configured test setup with example tests
|
|
72
|
+
- HTML reports and Allure integration
|
|
73
|
+
|
|
74
|
+
### Dependency Management
|
|
75
|
+
|
|
76
|
+
- **Exact version pinning** - All dependencies use exact versions (no `^` or `~`)
|
|
77
|
+
- **`.npmrc` configuration** - Ensures `save-exact=true` for all future installs
|
|
78
|
+
- **Renovate-friendly** - Compatible with automated dependency updates
|
|
79
|
+
|
|
80
|
+
### GitHub Actions Workflows
|
|
81
|
+
|
|
82
|
+
Two CI workflows are included in the generated projects:
|
|
83
|
+
|
|
84
|
+
1. **Code Checks** (`.github/workflows/check.yml`)
|
|
85
|
+
|
|
86
|
+
- TypeScript type checking
|
|
87
|
+
- Prettier formatting validation
|
|
88
|
+
- ESLint linting
|
|
89
|
+
- Production build verification
|
|
90
|
+
|
|
91
|
+
2. **E2E Tests** (`.github/workflows/e2e.yml`) - if E2E is included
|
|
92
|
+
- Runs Playwright tests in CI
|
|
93
|
+
- Uploads test reports as artifacts
|
|
94
|
+
- Configures Allure results
|
|
95
|
+
|
|
96
|
+
## Available Scripts
|
|
97
|
+
|
|
98
|
+
### Development
|
|
99
|
+
|
|
100
|
+
#### `npm run dev`
|
|
101
|
+
|
|
102
|
+
Starts the Vite development server with hot module replacement.
|
|
103
|
+
|
|
104
|
+
#### `npm run build`
|
|
105
|
+
|
|
106
|
+
Builds the app for production to the `dist` folder. Runs TypeScript compiler and Vite build.
|
|
107
|
+
|
|
108
|
+
#### `npm run preview`
|
|
109
|
+
|
|
110
|
+
Previews the production build locally.
|
|
111
|
+
|
|
112
|
+
### Code Quality
|
|
113
|
+
|
|
114
|
+
#### `npm run lint`
|
|
115
|
+
|
|
116
|
+
Runs ESLint and automatically fixes issues where possible.
|
|
117
|
+
|
|
118
|
+
#### `npm run lint:check`
|
|
119
|
+
|
|
120
|
+
Runs ESLint without fixing issues. Useful for CI environments.
|
|
121
|
+
|
|
122
|
+
#### `npm run format`
|
|
123
|
+
|
|
124
|
+
Formats all files with Prettier, organizing imports and sorting Tailwind classes.
|
|
125
|
+
|
|
126
|
+
#### `npm run format:check`
|
|
127
|
+
|
|
128
|
+
Checks if files are formatted correctly without modifying them. Useful for CI environments.
|
|
129
|
+
|
|
130
|
+
### E2E Testing (if included)
|
|
131
|
+
|
|
132
|
+
#### `npm run test:e2e`
|
|
133
|
+
|
|
134
|
+
Runs all Playwright E2E tests headlessly.
|
|
135
|
+
|
|
136
|
+
#### `npm run test:e2e:ui`
|
|
137
|
+
|
|
138
|
+
Opens Playwright's interactive UI mode for debugging tests.
|
|
139
|
+
|
|
140
|
+
#### `npm run test:e2e:report`
|
|
141
|
+
|
|
142
|
+
Generates and opens the Allure test report.
|
|
143
|
+
|
|
144
|
+
### Troubleshooting
|
|
145
|
+
|
|
146
|
+
#### `npm run itDoesNotWork`
|
|
147
|
+
|
|
148
|
+
Runs basic troubleshooting checks:
|
|
149
|
+
|
|
150
|
+
- Installs dependencies
|
|
151
|
+
- Checks if Vite dev server is running
|
|
152
|
+
- Provides helpful diagnostic information
|
|
153
|
+
|
|
154
|
+
## Project Structure
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
my-app/
|
|
158
|
+
├── src/
|
|
159
|
+
│ ├── pages/ # Page components
|
|
160
|
+
│ │ ├── Home/
|
|
161
|
+
│ │ └── About/
|
|
162
|
+
│ ├── App.tsx # Main app with routing
|
|
163
|
+
│ ├── main.tsx # Entry point
|
|
164
|
+
│ └── app.css # Tailwind directives
|
|
165
|
+
├── e2e/ # E2E tests (optional)
|
|
166
|
+
├── .github/ # GitHub Actions workflows
|
|
167
|
+
└── package.json
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Why This Stack?
|
|
171
|
+
|
|
172
|
+
- **Modern**: Latest versions of React, Vite, and Tailwind
|
|
173
|
+
- **Lightweight**: Minimal dependencies, under 1MB node_modules (before dev deps)
|
|
174
|
+
- **Type-safe**: Full TypeScript support with strict checking
|
|
175
|
+
- **Fast**: Vite's instant HMR and optimized builds
|
|
176
|
+
- **Accessible**: Built-in a11y linting ensures inclusive UIs
|
|
177
|
+
- **Maintainable**: Automated formatting and linting prevent technical debt
|
|
178
|
+
- **CI-ready**: Workflows for testing and validation out of the box
|
|
179
|
+
|
|
180
|
+
## License
|
|
181
|
+
|
|
182
|
+
MIT
|
package/bin/index.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { dirname, join } from 'path';
|
|
5
|
+
import { readdir, mkdir, readFile, writeFile, copyFile, stat, rm } from 'fs/promises';
|
|
6
|
+
import { existsSync } from 'fs';
|
|
7
|
+
import { spawn } from 'child_process';
|
|
8
|
+
import * as readline from 'readline';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = dirname(__filename);
|
|
12
|
+
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
|
|
15
|
+
function parseArgs(args) {
|
|
16
|
+
const parsed = {
|
|
17
|
+
projectName: null,
|
|
18
|
+
flags: {}
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
for (let i = 0; i < args.length; i++) {
|
|
22
|
+
const arg = args[i];
|
|
23
|
+
if (arg.startsWith('--')) {
|
|
24
|
+
const key = arg.slice(2);
|
|
25
|
+
const nextArg = args[i + 1];
|
|
26
|
+
if (nextArg && !nextArg.startsWith('--')) {
|
|
27
|
+
parsed.flags[key] = nextArg;
|
|
28
|
+
i++;
|
|
29
|
+
} else {
|
|
30
|
+
parsed.flags[key] = true;
|
|
31
|
+
}
|
|
32
|
+
} else if (!parsed.projectName) {
|
|
33
|
+
parsed.projectName = arg;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return parsed;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function validateProjectName(name) {
|
|
41
|
+
if (!name) {
|
|
42
|
+
return 'Project name is required';
|
|
43
|
+
}
|
|
44
|
+
if (!/^[a-z0-9-_]+$/i.test(name)) {
|
|
45
|
+
return 'Project name can only contain letters, numbers, hyphens, and underscores';
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function copyDirectory(src, dest, excludePaths = []) {
|
|
51
|
+
await mkdir(dest, { recursive: true });
|
|
52
|
+
const entries = await readdir(src, { withFileTypes: true });
|
|
53
|
+
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
const srcPath = join(src, entry.name);
|
|
56
|
+
const destPath = join(dest, entry.name);
|
|
57
|
+
|
|
58
|
+
const shouldExclude = excludePaths.some(excludePath => {
|
|
59
|
+
if (entry.isDirectory() && entry.name === excludePath) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return srcPath.endsWith(`/${excludePath}`) || srcPath.endsWith(`\\${excludePath}`);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (shouldExclude) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (entry.isDirectory()) {
|
|
70
|
+
await copyDirectory(srcPath, destPath, excludePaths);
|
|
71
|
+
} else {
|
|
72
|
+
await copyFile(srcPath, destPath);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function askQuestion(query) {
|
|
78
|
+
const rl = readline.createInterface({
|
|
79
|
+
input: process.stdin,
|
|
80
|
+
output: process.stdout
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
rl.question(query, (answer) => {
|
|
85
|
+
rl.close();
|
|
86
|
+
resolve(answer);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function replaceInFile(filePath, replacements) {
|
|
92
|
+
let content = await readFile(filePath, 'utf-8');
|
|
93
|
+
for (const [key, value] of Object.entries(replacements)) {
|
|
94
|
+
content = content.replace(new RegExp(key, 'g'), value);
|
|
95
|
+
}
|
|
96
|
+
await writeFile(filePath, content, 'utf-8');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function runCommand(command, args, cwd) {
|
|
100
|
+
return new Promise((resolve, reject) => {
|
|
101
|
+
const child = spawn(command, args, {
|
|
102
|
+
cwd,
|
|
103
|
+
stdio: 'inherit'
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
child.on('close', (code) => {
|
|
107
|
+
if (code !== 0) {
|
|
108
|
+
reject(new Error(`Command failed with exit code ${code}`));
|
|
109
|
+
} else {
|
|
110
|
+
resolve();
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function main() {
|
|
117
|
+
const { projectName, flags } = parseArgs(args);
|
|
118
|
+
|
|
119
|
+
const validationError = validateProjectName(projectName);
|
|
120
|
+
if (validationError) {
|
|
121
|
+
console.error(`Error: ${validationError}`);
|
|
122
|
+
console.log('\nUsage: npm create react-adam@latest <project-name> [options]');
|
|
123
|
+
console.log('\nOptions:');
|
|
124
|
+
console.log(' --dir <path> Create the project in a specific directory');
|
|
125
|
+
console.log(' --with-e2e Include E2E testing setup (Playwright + Allure)');
|
|
126
|
+
console.log(' --no-e2e Skip E2E testing setup');
|
|
127
|
+
console.log(' --with-utils Include utility functions (classNames, Storage, useUrlState)');
|
|
128
|
+
console.log(' --no-utils Skip utility functions');
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const baseDir = flags.dir || flags.directory || process.cwd();
|
|
133
|
+
const projectPath = join(baseDir, projectName);
|
|
134
|
+
|
|
135
|
+
if (existsSync(projectPath)) {
|
|
136
|
+
console.error(`Error: Directory "${projectName}" already exists`);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
let includeE2E = false;
|
|
141
|
+
if (flags['with-e2e']) {
|
|
142
|
+
includeE2E = true;
|
|
143
|
+
} else if (flags['no-e2e']) {
|
|
144
|
+
includeE2E = false;
|
|
145
|
+
} else {
|
|
146
|
+
const answer = await askQuestion('Include E2E testing setup (Playwright + Allure)? (y/N): ');
|
|
147
|
+
includeE2E = answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let includeUtils = false;
|
|
151
|
+
if (flags['with-utils']) {
|
|
152
|
+
includeUtils = true;
|
|
153
|
+
} else if (flags['no-utils']) {
|
|
154
|
+
includeUtils = false;
|
|
155
|
+
} else {
|
|
156
|
+
const answer = await askQuestion('Include utility functions (classNames, Storage, useUrlState)? (y/N): ');
|
|
157
|
+
includeUtils = answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes';
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
console.log(`Creating a new Adam React app in ${projectPath}...`);
|
|
161
|
+
|
|
162
|
+
const templatePath = join(__dirname, '..', 'template');
|
|
163
|
+
const excludePaths = [];
|
|
164
|
+
|
|
165
|
+
if (!includeE2E) {
|
|
166
|
+
excludePaths.push('e2e', 'playwright.config.ts', '.e2e-deps.json');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (!includeUtils) {
|
|
170
|
+
excludePaths.push('utils');
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
await copyDirectory(templatePath, projectPath, excludePaths);
|
|
174
|
+
|
|
175
|
+
if (!includeUtils) {
|
|
176
|
+
await copyFile(
|
|
177
|
+
join(projectPath, 'src', 'pages', 'Home', 'index.no-utils.tsx'),
|
|
178
|
+
join(projectPath, 'src', 'pages', 'Home', 'index.tsx')
|
|
179
|
+
);
|
|
180
|
+
await copyFile(
|
|
181
|
+
join(projectPath, 'src', 'pages', 'About', 'index.no-utils.tsx'),
|
|
182
|
+
join(projectPath, 'src', 'pages', 'About', 'index.tsx')
|
|
183
|
+
);
|
|
184
|
+
await rm(join(projectPath, 'src', 'pages', 'Home', 'index.no-utils.tsx'));
|
|
185
|
+
await rm(join(projectPath, 'src', 'pages', 'About', 'index.no-utils.tsx'));
|
|
186
|
+
} else {
|
|
187
|
+
await rm(join(projectPath, 'src', 'pages', 'Home', 'index.no-utils.tsx'));
|
|
188
|
+
await rm(join(projectPath, 'src', 'pages', 'About', 'index.no-utils.tsx'));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const replacements = {
|
|
192
|
+
'__PROJECT_NAME__': projectName
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
await replaceInFile(join(projectPath, 'package.json'), replacements);
|
|
196
|
+
await replaceInFile(join(projectPath, 'index.html'), replacements);
|
|
197
|
+
await replaceInFile(join(projectPath, 'README.md'), replacements);
|
|
198
|
+
|
|
199
|
+
if (includeE2E) {
|
|
200
|
+
const e2eDepsPath = join(projectPath, '.e2e-deps.json');
|
|
201
|
+
const packageJsonPath = join(projectPath, 'package.json');
|
|
202
|
+
|
|
203
|
+
const e2eDeps = JSON.parse(await readFile(e2eDepsPath, 'utf-8'));
|
|
204
|
+
const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8'));
|
|
205
|
+
|
|
206
|
+
packageJson.scripts = { ...packageJson.scripts, ...e2eDeps.scripts };
|
|
207
|
+
packageJson.devDependencies = { ...packageJson.devDependencies, ...e2eDeps.devDependencies };
|
|
208
|
+
|
|
209
|
+
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf-8');
|
|
210
|
+
await rm(e2eDepsPath);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
console.log('\nInstalling dependencies...');
|
|
214
|
+
await runCommand('npm', ['install'], projectPath);
|
|
215
|
+
|
|
216
|
+
console.log('\n✓ Success! Created', projectName, 'at', projectPath);
|
|
217
|
+
console.log('\nInside that directory, you can run several commands:\n');
|
|
218
|
+
console.log(' npm run dev');
|
|
219
|
+
console.log(' Starts the development server.\n');
|
|
220
|
+
console.log(' npm run build');
|
|
221
|
+
console.log(' Builds the app for production.\n');
|
|
222
|
+
console.log(' npm run preview');
|
|
223
|
+
console.log(' Previews the production build.\n');
|
|
224
|
+
console.log(' npm run lint');
|
|
225
|
+
console.log(' Runs the linter.\n');
|
|
226
|
+
|
|
227
|
+
if (includeE2E) {
|
|
228
|
+
console.log(' npm run test:e2e');
|
|
229
|
+
console.log(' Runs E2E tests with Playwright.\n');
|
|
230
|
+
console.log(' npm run test:e2e:ui');
|
|
231
|
+
console.log(' Opens Playwright UI mode.\n');
|
|
232
|
+
console.log(' npm run test:e2e:report');
|
|
233
|
+
console.log(' Generates and opens Allure report.\n');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
console.log('We suggest that you begin by typing:\n');
|
|
237
|
+
console.log(` cd ${projectName}`);
|
|
238
|
+
console.log(' npm run dev\n');
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
main().catch((error) => {
|
|
242
|
+
console.error('Error:', error.message);
|
|
243
|
+
process.exit(1);
|
|
244
|
+
});
|
|
245
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-react-adam",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Create opinionated React apps with TypeScript, Vite, Wouter, and Tailwind CSS",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-react-adam": "./bin/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"template"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"react",
|
|
15
|
+
"vite",
|
|
16
|
+
"typescript",
|
|
17
|
+
"wouter",
|
|
18
|
+
"tailwindcss",
|
|
19
|
+
"create-react-app",
|
|
20
|
+
"scaffolding"
|
|
21
|
+
],
|
|
22
|
+
"author": "Adam",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/adamjsturge/create-react-adam.git"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/adamjsturge/create-react-adam/issues"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/adamjsturge/create-react-adam#readme",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=18.0.0"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"quick-make": "npm link && cd ./tmp && npx create-react-adam test-app-$(date +%Y%m%d-%H%M%S) --with-e2e --with-utils",
|
|
37
|
+
"qm": "npm run quick-make",
|
|
38
|
+
"itDoesNotWork": "echo 'Wrong Directory'",
|
|
39
|
+
"cleanup": "rm -rf ./tmp/* && rm -rf ./template/node_modules && rm -rf ./template/dist && rm -rf ./template/package-lock.json && echo 'Template Dev Files Deleted, you must run npm install in the template directory for those features'",
|
|
40
|
+
"dev": "npm run cleanup && TIMESTAMP=$(date +%Y%m%d-%H%M%S) && npm link && cd ./tmp && npx create-react-adam test-app-$TIMESTAMP --with-e2e --with-utils && cd test-app-$TIMESTAMP && npm run dev"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"scripts": {
|
|
3
|
+
"test:e2e": "playwright test",
|
|
4
|
+
"test:e2e:ui": "playwright test --ui",
|
|
5
|
+
"test:e2e:report": "allure generate ./allure-results --clean && allure open"
|
|
6
|
+
},
|
|
7
|
+
"devDependencies": {
|
|
8
|
+
"@playwright/test": "1.48.0",
|
|
9
|
+
"allure-playwright": "3.0.3"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
|
3
|
+
"extends": ["config:recommended"],
|
|
4
|
+
"packageRules": [
|
|
5
|
+
{
|
|
6
|
+
"matchManagers": ["npm"],
|
|
7
|
+
"groupName": "JavaScript Dependencies",
|
|
8
|
+
"groupSlug": "javascript-dependencies",
|
|
9
|
+
"schedule": ["at any time"]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"matchManagers": ["github-actions"],
|
|
13
|
+
"groupName": "GitHub Actions Dependencies",
|
|
14
|
+
"groupSlug": "github-actions-dependencies",
|
|
15
|
+
"schedule": ["at any time"]
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"matchManagers": ["nvm"],
|
|
19
|
+
"groupName": "Node Version Manager Dependencies",
|
|
20
|
+
"groupSlug": "nvm-dependencies",
|
|
21
|
+
"schedule": ["at any time"]
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: Template Code Checks
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
check:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v5
|
|
16
|
+
|
|
17
|
+
- name: Setup Node.js
|
|
18
|
+
uses: actions/setup-node@v6
|
|
19
|
+
with:
|
|
20
|
+
node-version: "24.11.0"
|
|
21
|
+
cache: "npm"
|
|
22
|
+
|
|
23
|
+
- name: Install CLI dependencies
|
|
24
|
+
run: npm install
|
|
25
|
+
|
|
26
|
+
- name: Run TypeScript check
|
|
27
|
+
run: npx tsc --noEmit
|
|
28
|
+
|
|
29
|
+
- name: Check formatting
|
|
30
|
+
run: npm run format:check
|
|
31
|
+
|
|
32
|
+
- name: Run linting
|
|
33
|
+
run: npm run lint:check
|
|
34
|
+
|
|
35
|
+
- name: Run build
|
|
36
|
+
run: npm run build
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: E2E Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
e2e:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v5
|
|
16
|
+
|
|
17
|
+
- name: Setup Node.js
|
|
18
|
+
uses: actions/setup-node@v6
|
|
19
|
+
with:
|
|
20
|
+
node-version: "24.11.0"
|
|
21
|
+
cache: "npm"
|
|
22
|
+
|
|
23
|
+
- name: Install CLI dependencies
|
|
24
|
+
run: npm install
|
|
25
|
+
|
|
26
|
+
- name: Install Playwright browsers
|
|
27
|
+
working-directory: ./e2e/
|
|
28
|
+
run: npx playwright install --with-deps chromium
|
|
29
|
+
|
|
30
|
+
- name: Run E2E tests
|
|
31
|
+
working-directory: ./e2e/
|
|
32
|
+
run: npm run test:e2e
|
|
33
|
+
|
|
34
|
+
- name: Upload Playwright report
|
|
35
|
+
uses: actions/upload-artifact@v5
|
|
36
|
+
if: always()
|
|
37
|
+
with:
|
|
38
|
+
name: playwright-report
|
|
39
|
+
path: ./e2e/playwright-report/
|
|
40
|
+
retention-days: 30
|
|
41
|
+
|
|
42
|
+
- name: Upload Allure results
|
|
43
|
+
uses: actions/upload-artifact@v5
|
|
44
|
+
if: always()
|
|
45
|
+
with:
|
|
46
|
+
name: allure-results
|
|
47
|
+
path: ./e2e/allure-results/
|
|
48
|
+
retention-days: 30
|
package/template/.nvmrc
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# **PROJECT_NAME**
|
|
2
|
+
|
|
3
|
+
A React application created with create-react-adam.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run dev
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This will start the development server at `http://localhost:5173`.
|
|
12
|
+
|
|
13
|
+
## Available Scripts
|
|
14
|
+
|
|
15
|
+
### `npm run itDoesNotWork`
|
|
16
|
+
|
|
17
|
+
Runs basic troubleshooting checks:
|
|
18
|
+
|
|
19
|
+
- Installs dependencies
|
|
20
|
+
- Checks if Vite dev server is running
|
|
21
|
+
- Provides helpful diagnostic information
|
|
22
|
+
|
|
23
|
+
### `npm run dev`
|
|
24
|
+
|
|
25
|
+
Starts the development server with hot module replacement.
|
|
26
|
+
|
|
27
|
+
### `npm run build`
|
|
28
|
+
|
|
29
|
+
Builds the app for production. The build artifacts will be stored in the `dist/` directory.
|
|
30
|
+
|
|
31
|
+
### `npm run preview`
|
|
32
|
+
|
|
33
|
+
Previews the production build locally.
|
|
34
|
+
|
|
35
|
+
### `npm run lint`
|
|
36
|
+
|
|
37
|
+
Runs ESLint to check for code quality issues.
|
|
38
|
+
|
|
39
|
+
### `npm run format`
|
|
40
|
+
|
|
41
|
+
Formats all files with Prettier, organizing imports and sorting Tailwind classes.
|
|
42
|
+
|
|
43
|
+
## Tech Stack
|
|
44
|
+
|
|
45
|
+
- **React** - UI library
|
|
46
|
+
- **TypeScript** - Type safety
|
|
47
|
+
- **Vite** - Build tool and dev server
|
|
48
|
+
- **Wouter** - Lightweight routing
|
|
49
|
+
- **Tailwind CSS** - Utility-first CSS framework
|
|
50
|
+
- **ESLint & Prettier** - Code quality and formatting
|
|
51
|
+
|
|
52
|
+
## Project Structure
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
src/
|
|
56
|
+
├── pages/ # Page components
|
|
57
|
+
│ ├── Home/index.tsx
|
|
58
|
+
│ └── About/index.tsx
|
|
59
|
+
├── App.tsx # Main app with routes
|
|
60
|
+
├── main.tsx # Entry point
|
|
61
|
+
└── app.css # Global styles (Tailwind imports)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Adding New Pages
|
|
65
|
+
|
|
66
|
+
1. Create a new component in `src/pages/`
|
|
67
|
+
2. Import and add a route in `src/App.tsx`
|
|
68
|
+
|
|
69
|
+
Example:
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import NewPage from "./pages/NewPage";
|
|
73
|
+
|
|
74
|
+
// In the Switch component:
|
|
75
|
+
<Route path="/new" component={NewPage} />;
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Learn More
|
|
79
|
+
|
|
80
|
+
- [React Documentation](https://react.dev)
|
|
81
|
+
- [Vite Documentation](https://vitejs.dev)
|
|
82
|
+
- [Wouter Documentation](https://github.com/molefrog/wouter)
|
|
83
|
+
- [Tailwind CSS Documentation](https://tailwindcss.com)
|