create-modern-react 1.0.0 → 1.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/bin/index.js CHANGED
@@ -1,28 +1,26 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { program } = require("commander");
4
- const chalk = require("chalk");
5
- const { createProject } = require("../lib/prompts");
3
+ const { program } = require('commander');
4
+ const chalk = require('chalk');
5
+ const { createProject } = require('../lib/prompts');
6
6
 
7
7
  program
8
- .name("create-modern-react")
9
- .description(
10
- "Create a modern React application with Vite, TypeScript, and your choice of modern libraries",
11
- )
12
- .version("1.0.0")
13
- .argument("[project-name]", "name of the project")
14
- .option("-t, --template <template>", "use a specific template")
15
- .option("--skip-install", "skip dependency installation")
16
- .option("--skip-git", "skip git initialization")
8
+ .name('create-modern-react')
9
+ .description('Create a modern React application with Vite, TypeScript, and your choice of modern libraries')
10
+ .version('1.0.0')
11
+ .argument('[project-name]', 'name of the project')
12
+ .option('-t, --template <template>', 'use a specific template')
13
+ .option('--skip-install', 'skip dependency installation')
14
+ .option('--skip-git', 'skip git initialization')
17
15
  .action(async (projectName, options) => {
18
- console.log(chalk.blue.bold("\nšŸš€ Welcome to create-modern-react!\n"));
16
+ console.log(chalk.blue.bold('\nšŸš€ Welcome to create-modern-react!\n'));
19
17
 
20
18
  try {
21
19
  await createProject(projectName, options);
22
20
  } catch (error) {
23
- console.error(chalk.red("āŒ Error creating project:"), error.message);
21
+ console.error(chalk.red('āŒ Error creating project:'), error.message);
24
22
  process.exit(1);
25
23
  }
26
24
  });
27
25
 
28
- program.parse();
26
+ program.parse();
package/lib/install.js CHANGED
@@ -1,15 +1,15 @@
1
- const { spawn } = require("child_process");
2
- const chalk = require("chalk");
1
+ const { spawn } = require('child_process');
2
+ const chalk = require('chalk');
3
3
 
4
4
  function runCommand(command, args, cwd) {
5
5
  return new Promise((resolve, reject) => {
6
6
  const child = spawn(command, args, {
7
7
  cwd,
8
- stdio: "inherit",
9
- shell: true,
8
+ stdio: 'inherit',
9
+ shell: true
10
10
  });
11
11
 
12
- child.on("close", (code) => {
12
+ child.on('close', (code) => {
13
13
  if (code === 0) {
14
14
  resolve();
15
15
  } else {
@@ -17,43 +17,114 @@ function runCommand(command, args, cwd) {
17
17
  }
18
18
  });
19
19
 
20
- child.on("error", (error) => {
20
+ child.on('error', (error) => {
21
21
  reject(error);
22
22
  });
23
23
  });
24
24
  }
25
25
 
26
+ // Check if a command is available
27
+ function isCommandAvailable(command) {
28
+ return new Promise((resolve) => {
29
+ const child = spawn(command, ['--version'], {
30
+ stdio: 'ignore',
31
+ shell: true
32
+ });
33
+
34
+ child.on('close', (code) => {
35
+ resolve(code === 0);
36
+ });
37
+
38
+ child.on('error', () => {
39
+ resolve(false);
40
+ });
41
+ });
42
+ }
43
+
44
+ // Get the best available package manager with fallback
45
+ async function getAvailablePackageManager(preferredManager) {
46
+ console.log(chalk.blue(`šŸ” Checking for ${preferredManager}...`));
47
+
48
+ // Check if preferred package manager is available
49
+ if (await isCommandAvailable(preferredManager)) {
50
+ console.log(chalk.green(`āœ… ${preferredManager} is available`));
51
+ return preferredManager;
52
+ }
53
+
54
+ // Fallback logic
55
+ console.log(chalk.yellow(`āš ļø ${preferredManager} is not installed`));
56
+
57
+ if (preferredManager !== 'npm') {
58
+ console.log(chalk.blue('šŸ”„ Falling back to npm...'));
59
+
60
+ if (await isCommandAvailable('npm')) {
61
+ console.log(chalk.green('āœ… npm is available, using npm instead'));
62
+ return 'npm';
63
+ } else {
64
+ throw new Error('Neither ' + preferredManager + ' nor npm is available');
65
+ }
66
+ } else {
67
+ throw new Error('npm is not available');
68
+ }
69
+ }
70
+
71
+ // Get install command and args for package manager
72
+ function getInstallCommand(packageManager) {
73
+ switch (packageManager) {
74
+ case 'yarn':
75
+ return { command: 'yarn', args: ['install'] };
76
+ case 'pnpm':
77
+ return { command: 'pnpm', args: ['install'] };
78
+ case 'npm':
79
+ default:
80
+ return { command: 'npm', args: ['install'] };
81
+ }
82
+ }
83
+
26
84
  async function installDependencies(config) {
27
- const { projectPath, packageManager } = config;
85
+ const { projectPath, packageManager: preferredManager, projectName } = config;
28
86
 
29
- console.log(chalk.blue("\nšŸ“¦ Installing dependencies..."));
87
+ console.log(chalk.blue('\nšŸ“¦ Installing dependencies...'));
30
88
 
31
89
  try {
32
- const installCommand =
33
- packageManager === "yarn"
34
- ? "yarn"
35
- : packageManager === "pnpm"
36
- ? "pnpm"
37
- : "npm";
38
- const installArgs =
39
- packageManager === "npm"
40
- ? ["install"]
41
- : packageManager === "pnpm"
42
- ? ["install"]
43
- : [];
44
-
45
- await runCommand(installCommand, installArgs, projectPath);
46
-
47
- console.log(chalk.green("āœ… Dependencies installed successfully!"));
90
+ // Get the best available package manager
91
+ const availableManager = await getAvailablePackageManager(preferredManager);
92
+ const { command, args } = getInstallCommand(availableManager);
93
+
94
+ // Update config with actual package manager used
95
+ config.actualPackageManager = availableManager;
96
+
97
+ console.log(chalk.blue(`šŸ“„ Running: ${command} ${args.join(' ')}`));
98
+ await runCommand(command, args, projectPath);
99
+
100
+ console.log(chalk.green('āœ… Dependencies installed successfully!'));
101
+
102
+ // Show different message if fallback was used
103
+ if (availableManager !== preferredManager) {
104
+ console.log(chalk.yellow(`ā„¹ļø Note: Used ${availableManager} instead of ${preferredManager}`));
105
+ }
106
+
48
107
  } catch (error) {
49
- console.error(
50
- chalk.red("āŒ Failed to install dependencies:"),
51
- error.message,
52
- );
53
- console.log(chalk.yellow("You can install them manually by running:"));
54
- console.log(chalk.gray(` cd ${config.projectName}`));
55
- console.log(chalk.gray(` ${packageManager} install`));
108
+ console.error(chalk.red('āŒ Failed to install dependencies:'), error.message);
109
+ console.log(chalk.yellow('\nšŸ”§ You can install them manually by running:'));
110
+ console.log(chalk.gray(` cd ${projectName}`));
111
+
112
+ // Show command for the originally preferred package manager
113
+ if (preferredManager === 'yarn') {
114
+ console.log(chalk.gray(` yarn install`));
115
+ } else if (preferredManager === 'pnpm') {
116
+ console.log(chalk.gray(` pnpm install`));
117
+ } else {
118
+ console.log(chalk.gray(` npm install`));
119
+ }
120
+
121
+ console.log(chalk.yellow('\nšŸ’” Make sure you have the package manager installed:'));
122
+ if (preferredManager === 'yarn') {
123
+ console.log(chalk.gray(` npm install -g yarn`));
124
+ } else if (preferredManager === 'pnpm') {
125
+ console.log(chalk.gray(` npm install -g pnpm`));
126
+ }
56
127
  }
57
128
  }
58
129
 
59
- module.exports = { installDependencies, runCommand };
130
+ module.exports = { installDependencies, runCommand };
package/lib/prompts.js CHANGED
@@ -1,25 +1,24 @@
1
- const inquirer = require("inquirer");
2
- const chalk = require("chalk");
3
- const path = require("path");
4
- const fs = require("fs-extra");
5
- const { installDependencies } = require("./install");
6
- const { setupProject } = require("./setup");
1
+ const inquirer = require('inquirer');
2
+ const chalk = require('chalk');
3
+ const path = require('path');
4
+ const fs = require('fs-extra');
5
+ const { installDependencies } = require('./install');
6
+ const { setupProject } = require('./setup');
7
7
 
8
8
  async function createProject(projectName, options) {
9
9
  // Get project name if not provided
10
10
  if (!projectName) {
11
11
  const nameAnswer = await inquirer.prompt([
12
12
  {
13
- type: "input",
14
- name: "projectName",
15
- message: "What is the name of your project?",
13
+ type: 'input',
14
+ name: 'projectName',
15
+ message: 'What is the name of your project?',
16
16
  validate: (input) => {
17
- if (!input.trim()) return "Project name is required";
18
- if (!/^[a-zA-Z0-9-_]+$/.test(input))
19
- return "Project name can only contain letters, numbers, hyphens, and underscores";
17
+ if (!input.trim()) return 'Project name is required';
18
+ if (!/^[a-zA-Z0-9-_]+$/.test(input)) return 'Project name can only contain letters, numbers, hyphens, and underscores';
20
19
  return true;
21
- },
22
- },
20
+ }
21
+ }
23
22
  ]);
24
23
  projectName = nameAnswer.projectName;
25
24
  }
@@ -30,15 +29,15 @@ async function createProject(projectName, options) {
30
29
  if (fs.existsSync(projectPath)) {
31
30
  const overwriteAnswer = await inquirer.prompt([
32
31
  {
33
- type: "confirm",
34
- name: "overwrite",
32
+ type: 'confirm',
33
+ name: 'overwrite',
35
34
  message: `Directory ${projectName} already exists. Do you want to overwrite it?`,
36
- default: false,
37
- },
35
+ default: false
36
+ }
38
37
  ]);
39
38
 
40
39
  if (!overwriteAnswer.overwrite) {
41
- console.log(chalk.yellow("Operation cancelled."));
40
+ console.log(chalk.yellow('Operation cancelled.'));
42
41
  return;
43
42
  }
44
43
 
@@ -48,147 +47,139 @@ async function createProject(projectName, options) {
48
47
  // Package Manager Selection
49
48
  const packageManagerAnswer = await inquirer.prompt([
50
49
  {
51
- type: "list",
52
- name: "packageManager",
53
- message: "Which package manager would you like to use?",
50
+ type: 'list',
51
+ name: 'packageManager',
52
+ message: 'Which package manager would you like to use?',
54
53
  choices: [
55
- { name: "npm", value: "npm" },
56
- { name: "yarn", value: "yarn" },
57
- { name: "pnpm", value: "pnpm" },
58
- ],
59
- },
54
+ { name: 'npm', value: 'npm' },
55
+ { name: 'yarn', value: 'yarn' },
56
+ { name: 'pnpm', value: 'pnpm' }
57
+ ]
58
+ }
60
59
  ]);
61
60
 
62
61
  // UI Library Selection
63
62
  const uiLibraryAnswer = await inquirer.prompt([
64
63
  {
65
- type: "list",
66
- name: "uiLibrary",
67
- message: "Do you want to include a UI component library?",
64
+ type: 'list',
65
+ name: 'uiLibrary',
66
+ message: 'Do you want to include a UI component library?',
68
67
  choices: [
69
- { name: "Ant Design v5 (with theme customization)", value: "antd" },
70
- { name: "Material-UI (MUI)", value: "mui" },
71
- { name: "Chakra UI", value: "chakra" },
72
- { name: "None (custom components only)", value: "none" },
73
- ],
74
- },
68
+ { name: 'Ant Design v5 (with theme customization)', value: 'antd' },
69
+ { name: 'Material-UI (MUI)', value: 'mui' },
70
+ { name: 'Chakra UI', value: 'chakra' },
71
+ { name: 'None (custom components only)', value: 'none' }
72
+ ]
73
+ }
75
74
  ]);
76
75
 
77
76
  // CSS Framework Selection
78
77
  const cssFrameworkAnswer = await inquirer.prompt([
79
78
  {
80
- type: "list",
81
- name: "cssFramework",
82
- message: "Which CSS framework would you like to use?",
79
+ type: 'list',
80
+ name: 'cssFramework',
81
+ message: 'Which CSS framework would you like to use?',
83
82
  choices: [
84
- { name: "Tailwind CSS (with custom config)", value: "tailwind" },
85
- { name: "CSS Modules", value: "css-modules" },
86
- { name: "Styled Components", value: "styled-components" },
87
- { name: "Plain CSS only", value: "plain" },
88
- ],
89
- },
83
+ { name: 'Tailwind CSS (with custom config)', value: 'tailwind' },
84
+ { name: 'CSS Modules', value: 'css-modules' },
85
+ { name: 'Styled Components', value: 'styled-components' },
86
+ { name: 'Plain CSS only', value: 'plain' }
87
+ ]
88
+ }
90
89
  ]);
91
90
 
92
91
  // State Management Selection
93
92
  const stateManagementAnswer = await inquirer.prompt([
94
93
  {
95
- type: "list",
96
- name: "stateManagement",
97
- message: "Do you need state management?",
94
+ type: 'list',
95
+ name: 'stateManagement',
96
+ message: 'Do you need state management?',
98
97
  choices: [
99
- { name: "Redux Toolkit (with Redux Persist)", value: "redux-toolkit" },
100
- { name: "Zustand", value: "zustand" },
101
- { name: "Jotai", value: "jotai" },
102
- { name: "React state only", value: "none" },
103
- ],
104
- },
98
+ { name: 'Redux Toolkit (with Redux Persist)', value: 'redux-toolkit' },
99
+ { name: 'Zustand', value: 'zustand' },
100
+ { name: 'Jotai', value: 'jotai' },
101
+ { name: 'React state only', value: 'none' }
102
+ ]
103
+ }
105
104
  ]);
106
105
 
107
106
  // Data Fetching Selection
108
107
  const dataFetchingAnswer = await inquirer.prompt([
109
108
  {
110
- type: "list",
111
- name: "dataFetching",
112
- message: "Do you want to include data fetching libraries?",
109
+ type: 'list',
110
+ name: 'dataFetching',
111
+ message: 'Do you want to include data fetching libraries?',
113
112
  choices: [
114
- { name: "React Query (TanStack Query)", value: "react-query" },
115
- { name: "SWR", value: "swr" },
116
- { name: "Apollo Client (for GraphQL)", value: "apollo" },
117
- { name: "Fetch API only", value: "none" },
118
- ],
119
- },
113
+ { name: 'React Query (TanStack Query)', value: 'react-query' },
114
+ { name: 'SWR', value: 'swr' },
115
+ { name: 'Apollo Client (for GraphQL)', value: 'apollo' },
116
+ { name: 'Fetch API only', value: 'none' }
117
+ ]
118
+ }
120
119
  ]);
121
120
 
122
121
  // Routing Selection
123
122
  const routingAnswer = await inquirer.prompt([
124
123
  {
125
- type: "list",
126
- name: "routing",
127
- message: "Do you need client-side routing?",
124
+ type: 'list',
125
+ name: 'routing',
126
+ message: 'Do you need client-side routing?',
128
127
  choices: [
129
- { name: "React Router v6", value: "react-router" },
130
- { name: "Wouter (lightweight)", value: "wouter" },
131
- { name: "No routing", value: "none" },
132
- ],
133
- },
128
+ { name: 'React Router v6', value: 'react-router' },
129
+ { name: 'Wouter (lightweight)', value: 'wouter' },
130
+ { name: 'No routing', value: 'none' }
131
+ ]
132
+ }
134
133
  ]);
135
134
 
136
135
  // Development Tools Selection
137
136
  const devToolsAnswer = await inquirer.prompt([
138
137
  {
139
- type: "checkbox",
140
- name: "devTools",
141
- message: "Which development tools would you like?",
138
+ type: 'checkbox',
139
+ name: 'devTools',
140
+ message: 'Which development tools would you like?',
142
141
  choices: [
143
- { name: "Storybook (component development)", value: "storybook" },
144
- {
145
- name: "ESLint + Prettier (code quality)",
146
- value: "eslint-prettier",
147
- checked: true,
148
- },
149
- {
150
- name: "Husky + lint-staged (git hooks)",
151
- value: "husky",
152
- checked: true,
153
- },
154
- { name: "Jest + Testing Library (testing)", value: "testing" },
155
- ],
156
- },
142
+ { name: 'Storybook (component development)', value: 'storybook' },
143
+ { name: 'ESLint + Prettier (code quality)', value: 'eslint-prettier', checked: true },
144
+ { name: 'Husky + lint-staged (git hooks)', value: 'husky', checked: true },
145
+ { name: 'Jest + Testing Library (testing)', value: 'testing' }
146
+ ]
147
+ }
157
148
  ]);
158
149
 
159
150
  // Icons Selection
160
151
  const iconsAnswer = await inquirer.prompt([
161
152
  {
162
- type: "list",
163
- name: "icons",
164
- message: "Do you want icon libraries?",
153
+ type: 'list',
154
+ name: 'icons',
155
+ message: 'Do you want icon libraries?',
165
156
  choices: [
166
- { name: "Lucide React", value: "lucide" },
167
- { name: "React Icons", value: "react-icons" },
168
- { name: "Heroicons", value: "heroicons" },
169
- { name: "No icon library", value: "none" },
170
- ],
171
- },
157
+ { name: 'Lucide React', value: 'lucide' },
158
+ { name: 'React Icons', value: 'react-icons' },
159
+ { name: 'Heroicons', value: 'heroicons' },
160
+ { name: 'No icon library', value: 'none' }
161
+ ]
162
+ }
172
163
  ]);
173
164
 
174
165
  // PWA Selection
175
166
  const pwaAnswer = await inquirer.prompt([
176
167
  {
177
- type: "confirm",
178
- name: "pwa",
179
- message: "Make it a PWA?",
180
- default: false,
181
- },
168
+ type: 'confirm',
169
+ name: 'pwa',
170
+ message: 'Make it a PWA?',
171
+ default: false
172
+ }
182
173
  ]);
183
174
 
184
175
  // Git Selection
185
176
  const gitAnswer = await inquirer.prompt([
186
177
  {
187
- type: "confirm",
188
- name: "git",
189
- message: "Initialize Git repository?",
190
- default: true,
191
- },
178
+ type: 'confirm',
179
+ name: 'git',
180
+ message: 'Initialize Git repository?',
181
+ default: true
182
+ }
192
183
  ]);
193
184
 
194
185
  const config = {
@@ -205,12 +196,10 @@ async function createProject(projectName, options) {
205
196
  pwa: pwaAnswer.pwa,
206
197
  git: gitAnswer.git,
207
198
  skipInstall: options.skipInstall,
208
- skipGit: options.skipGit,
199
+ skipGit: options.skipGit
209
200
  };
210
201
 
211
- console.log(
212
- chalk.blue("\nšŸ“¦ Creating project with the following configuration:"),
213
- );
202
+ console.log(chalk.blue('\nšŸ“¦ Creating project with the following configuration:'));
214
203
  console.log(chalk.gray(JSON.stringify(config, null, 2)));
215
204
 
216
205
  // Create project
@@ -221,15 +210,17 @@ async function createProject(projectName, options) {
221
210
  await installDependencies(config);
222
211
  }
223
212
 
224
- console.log(
225
- chalk.green.bold(`\nšŸŽ‰ Project ${projectName} created successfully!`),
226
- );
227
- console.log(chalk.blue("\nNext steps:"));
213
+ console.log(chalk.green.bold(`\nšŸŽ‰ Project ${projectName} created successfully!`));
214
+ console.log(chalk.blue('\nNext steps:'));
228
215
  console.log(chalk.gray(` cd ${projectName}`));
216
+
217
+ // Use the actual package manager that was used for installation
218
+ const actualPackageManager = config.actualPackageManager || config.packageManager;
219
+
229
220
  if (options.skipInstall) {
230
- console.log(chalk.gray(` ${config.packageManager} install`));
221
+ console.log(chalk.gray(` ${actualPackageManager} install`));
231
222
  }
232
- console.log(chalk.gray(` ${config.packageManager} dev`));
223
+ console.log(chalk.gray(` ${actualPackageManager === 'npm' ? 'npm run dev' : actualPackageManager + ' dev'}`));
233
224
  }
234
225
 
235
- module.exports = { createProject };
226
+ module.exports = { createProject };
package/lib/setup.js CHANGED
@@ -1,18 +1,18 @@
1
- const fs = require("fs-extra");
2
- const path = require("path");
3
- const chalk = require("chalk");
4
- const { runCommand } = require("./install");
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+ const { runCommand } = require('./install');
5
5
 
6
6
  async function setupProject(config) {
7
7
  const { projectPath, projectName } = config;
8
8
 
9
- console.log(chalk.blue("\nšŸ—ļø Setting up project structure..."));
9
+ console.log(chalk.blue('\nšŸ—ļø Setting up project structure...'));
10
10
 
11
11
  // Create project directory
12
12
  await fs.ensureDir(projectPath);
13
13
 
14
14
  // Copy base template
15
- const templatePath = path.join(__dirname, "../templates/base");
15
+ const templatePath = path.join(__dirname, '../templates/base');
16
16
  await fs.copy(templatePath, projectPath);
17
17
 
18
18
  // Update package.json with project name and selected dependencies
@@ -26,11 +26,11 @@ async function setupProject(config) {
26
26
  await initializeGit(config);
27
27
  }
28
28
 
29
- console.log(chalk.green("āœ… Project structure created successfully!"));
29
+ console.log(chalk.green('āœ… Project structure created successfully!'));
30
30
  }
31
31
 
32
32
  async function updatePackageJson(config) {
33
- const packageJsonPath = path.join(config.projectPath, "package.json");
33
+ const packageJsonPath = path.join(config.projectPath, 'package.json');
34
34
  const packageJson = await fs.readJson(packageJsonPath);
35
35
 
36
36
  // Update name
@@ -41,89 +41,89 @@ async function updatePackageJson(config) {
41
41
  const devDependencies = { ...packageJson.devDependencies };
42
42
 
43
43
  // UI Library dependencies
44
- if (config.uiLibrary === "antd") {
45
- dependencies["antd"] = "^5.0.0";
46
- } else if (config.uiLibrary === "mui") {
47
- dependencies["@mui/material"] = "^5.0.0";
48
- dependencies["@emotion/react"] = "^11.0.0";
49
- dependencies["@emotion/styled"] = "^11.0.0";
50
- } else if (config.uiLibrary === "chakra") {
51
- dependencies["@chakra-ui/react"] = "^2.0.0";
52
- dependencies["@emotion/react"] = "^11.0.0";
53
- dependencies["@emotion/styled"] = "^11.0.0";
54
- dependencies["framer-motion"] = "^6.0.0";
44
+ if (config.uiLibrary === 'antd') {
45
+ dependencies['antd'] = '^5.0.0';
46
+ } else if (config.uiLibrary === 'mui') {
47
+ dependencies['@mui/material'] = '^5.0.0';
48
+ dependencies['@emotion/react'] = '^11.0.0';
49
+ dependencies['@emotion/styled'] = '^11.0.0';
50
+ } else if (config.uiLibrary === 'chakra') {
51
+ dependencies['@chakra-ui/react'] = '^2.0.0';
52
+ dependencies['@emotion/react'] = '^11.0.0';
53
+ dependencies['@emotion/styled'] = '^11.0.0';
54
+ dependencies['framer-motion'] = '^6.0.0';
55
55
  }
56
56
 
57
57
  // CSS Framework dependencies
58
- if (config.cssFramework === "tailwind") {
59
- devDependencies["tailwindcss"] = "^3.0.0";
60
- devDependencies["postcss"] = "^8.0.0";
61
- devDependencies["autoprefixer"] = "^10.0.0";
62
- } else if (config.cssFramework === "styled-components") {
63
- dependencies["styled-components"] = "^6.0.0";
64
- devDependencies["@types/styled-components"] = "^5.1.0";
58
+ if (config.cssFramework === 'tailwind') {
59
+ devDependencies['tailwindcss'] = '^3.0.0';
60
+ devDependencies['postcss'] = '^8.0.0';
61
+ devDependencies['autoprefixer'] = '^10.0.0';
62
+ } else if (config.cssFramework === 'styled-components') {
63
+ dependencies['styled-components'] = '^6.0.0';
64
+ devDependencies['@types/styled-components'] = '^5.1.0';
65
65
  }
66
66
 
67
67
  // State Management dependencies
68
- if (config.stateManagement === "redux-toolkit") {
69
- dependencies["@reduxjs/toolkit"] = "^2.0.0";
70
- dependencies["react-redux"] = "^9.0.0";
71
- dependencies["redux-persist"] = "^6.0.0";
72
- } else if (config.stateManagement === "zustand") {
73
- dependencies["zustand"] = "^4.0.0";
74
- } else if (config.stateManagement === "jotai") {
75
- dependencies["jotai"] = "^2.0.0";
68
+ if (config.stateManagement === 'redux-toolkit') {
69
+ dependencies['@reduxjs/toolkit'] = '^2.0.0';
70
+ dependencies['react-redux'] = '^9.0.0';
71
+ dependencies['redux-persist'] = '^6.0.0';
72
+ } else if (config.stateManagement === 'zustand') {
73
+ dependencies['zustand'] = '^4.0.0';
74
+ } else if (config.stateManagement === 'jotai') {
75
+ dependencies['jotai'] = '^2.0.0';
76
76
  }
77
77
 
78
78
  // Data Fetching dependencies
79
- if (config.dataFetching === "react-query") {
80
- dependencies["@tanstack/react-query"] = "^5.0.0";
81
- dependencies["@tanstack/react-query-devtools"] = "^5.0.0";
82
- } else if (config.dataFetching === "swr") {
83
- dependencies["swr"] = "^2.0.0";
84
- } else if (config.dataFetching === "apollo") {
85
- dependencies["@apollo/client"] = "^3.0.0";
86
- dependencies["graphql"] = "^16.0.0";
79
+ if (config.dataFetching === 'react-query') {
80
+ dependencies['@tanstack/react-query'] = '^5.0.0';
81
+ dependencies['@tanstack/react-query-devtools'] = '^5.0.0';
82
+ } else if (config.dataFetching === 'swr') {
83
+ dependencies['swr'] = '^2.0.0';
84
+ } else if (config.dataFetching === 'apollo') {
85
+ dependencies['@apollo/client'] = '^3.0.0';
86
+ dependencies['graphql'] = '^16.0.0';
87
87
  }
88
88
 
89
89
  // Routing dependencies
90
- if (config.routing === "react-router") {
91
- dependencies["react-router-dom"] = "^6.0.0";
92
- } else if (config.routing === "wouter") {
93
- dependencies["wouter"] = "^3.0.0";
90
+ if (config.routing === 'react-router') {
91
+ dependencies['react-router-dom'] = '^6.0.0';
92
+ } else if (config.routing === 'wouter') {
93
+ dependencies['wouter'] = '^3.0.0';
94
94
  }
95
95
 
96
96
  // Icon dependencies
97
- if (config.icons === "lucide") {
98
- dependencies["lucide-react"] = "^0.400.0";
99
- } else if (config.icons === "react-icons") {
100
- dependencies["react-icons"] = "^5.0.0";
101
- } else if (config.icons === "heroicons") {
102
- dependencies["@heroicons/react"] = "^2.0.0";
97
+ if (config.icons === 'lucide') {
98
+ dependencies['lucide-react'] = '^0.400.0';
99
+ } else if (config.icons === 'react-icons') {
100
+ dependencies['react-icons'] = '^5.0.0';
101
+ } else if (config.icons === 'heroicons') {
102
+ dependencies['@heroicons/react'] = '^2.0.0';
103
103
  }
104
104
 
105
105
  // Development Tools dependencies
106
- if (config.devTools.includes("storybook")) {
107
- devDependencies["@storybook/react-vite"] = "^8.0.0";
108
- devDependencies["@storybook/addon-essentials"] = "^8.0.0";
109
- devDependencies["storybook"] = "^8.0.0";
106
+ if (config.devTools.includes('storybook')) {
107
+ devDependencies['@storybook/react-vite'] = '^8.0.0';
108
+ devDependencies['@storybook/addon-essentials'] = '^8.0.0';
109
+ devDependencies['storybook'] = '^8.0.0';
110
110
  }
111
111
 
112
- if (config.devTools.includes("testing")) {
113
- devDependencies["jest"] = "^29.0.0";
114
- devDependencies["@testing-library/react"] = "^14.0.0";
115
- devDependencies["@testing-library/jest-dom"] = "^6.0.0";
116
- devDependencies["@testing-library/user-event"] = "^14.0.0";
112
+ if (config.devTools.includes('testing')) {
113
+ devDependencies['jest'] = '^29.0.0';
114
+ devDependencies['@testing-library/react'] = '^14.0.0';
115
+ devDependencies['@testing-library/jest-dom'] = '^6.0.0';
116
+ devDependencies['@testing-library/user-event'] = '^14.0.0';
117
117
  }
118
118
 
119
- if (config.devTools.includes("husky")) {
120
- devDependencies["husky"] = "^9.0.0";
121
- devDependencies["lint-staged"] = "^15.0.0";
119
+ if (config.devTools.includes('husky')) {
120
+ devDependencies['husky'] = '^9.0.0';
121
+ devDependencies['lint-staged'] = '^15.0.0';
122
122
  }
123
123
 
124
124
  // PWA dependencies
125
125
  if (config.pwa) {
126
- devDependencies["vite-plugin-pwa"] = "^0.20.0";
126
+ devDependencies['vite-plugin-pwa'] = '^0.20.0';
127
127
  }
128
128
 
129
129
  packageJson.dependencies = dependencies;
@@ -136,7 +136,7 @@ async function configureLibraries(config) {
136
136
  const { projectPath } = config;
137
137
 
138
138
  // Configure Tailwind if selected
139
- if (config.cssFramework === "tailwind") {
139
+ if (config.cssFramework === 'tailwind') {
140
140
  await configureTailwind(projectPath);
141
141
  }
142
142
 
@@ -167,17 +167,11 @@ export default {
167
167
  },
168
168
  }`;
169
169
 
170
- await fs.writeFile(
171
- path.join(projectPath, "tailwind.config.js"),
172
- tailwindConfig,
173
- );
174
- await fs.writeFile(
175
- path.join(projectPath, "postcss.config.js"),
176
- postcssConfig,
177
- );
170
+ await fs.writeFile(path.join(projectPath, 'tailwind.config.js'), tailwindConfig);
171
+ await fs.writeFile(path.join(projectPath, 'postcss.config.js'), postcssConfig);
178
172
 
179
173
  // Add Tailwind directives to CSS
180
- const cssPath = path.join(projectPath, "src/index.css");
174
+ const cssPath = path.join(projectPath, 'src/index.css');
181
175
  const tailwindDirectives = `@tailwind base;
182
176
  @tailwind components;
183
177
  @tailwind utilities;
@@ -185,7 +179,7 @@ export default {
185
179
  `;
186
180
 
187
181
  if (await fs.pathExists(cssPath)) {
188
- const existingCss = await fs.readFile(cssPath, "utf8");
182
+ const existingCss = await fs.readFile(cssPath, 'utf8');
189
183
  await fs.writeFile(cssPath, tailwindDirectives + existingCss);
190
184
  } else {
191
185
  await fs.writeFile(cssPath, tailwindDirectives);
@@ -206,23 +200,16 @@ async function initializeGit(config) {
206
200
  const { projectPath } = config;
207
201
 
208
202
  try {
209
- console.log(chalk.blue("šŸ”§ Initializing Git repository..."));
203
+ console.log(chalk.blue('šŸ”§ Initializing Git repository...'));
210
204
 
211
- await runCommand("git", ["init"], projectPath);
212
- await runCommand("git", ["add", "."], projectPath);
213
- await runCommand(
214
- "git",
215
- ["commit", "-m", "Initial commit from create-modern-react"],
216
- projectPath,
217
- );
205
+ await runCommand('git', ['init'], projectPath);
206
+ await runCommand('git', ['add', '.'], projectPath);
207
+ await runCommand('git', ['commit', '-m', 'Initial commit from create-modern-react'], projectPath);
218
208
 
219
- console.log(chalk.green("āœ… Git repository initialized!"));
209
+ console.log(chalk.green('āœ… Git repository initialized!'));
220
210
  } catch (error) {
221
- console.warn(
222
- chalk.yellow("āš ļø Could not initialize Git repository:"),
223
- error.message,
224
- );
211
+ console.warn(chalk.yellow('āš ļø Could not initialize Git repository:'), error.message);
225
212
  }
226
213
  }
227
214
 
228
- module.exports = { setupProject };
215
+ module.exports = { setupProject };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-modern-react",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Create a modern React application with Vite, TypeScript, and your choice of modern libraries",
5
5
  "main": "bin/index.js",
6
6
  "bin": {
@@ -10,4 +10,4 @@
10
10
  <div id="root"></div>
11
11
  <script type="module" src="/src/main.tsx"></script>
12
12
  </body>
13
- </html>
13
+ </html>
@@ -25,4 +25,4 @@
25
25
  "typescript": "^5.2.2",
26
26
  "vite": "^5.2.0"
27
27
  }
28
- }
28
+ }
@@ -11,4 +11,4 @@
11
11
 
12
12
  .read-the-docs {
13
13
  color: #888;
14
- }
14
+ }
@@ -1,8 +1,8 @@
1
- import { useState } from "react";
2
- import "./App.css";
1
+ import { useState } from 'react'
2
+ import './App.css'
3
3
 
4
4
  function App() {
5
- const [count, setCount] = useState(0);
5
+ const [count, setCount] = useState(0)
6
6
 
7
7
  return (
8
8
  <div className="App">
@@ -16,10 +16,12 @@ function App() {
16
16
  Edit <code>src/App.tsx</code> and save to test HMR
17
17
  </p>
18
18
  </div>
19
- <p className="read-the-docs">Click on the React logo to learn more</p>
19
+ <p className="read-the-docs">
20
+ Click on the React logo to learn more
21
+ </p>
20
22
  </div>
21
23
  </div>
22
- );
24
+ )
23
25
  }
24
26
 
25
- export default App;
27
+ export default App
@@ -67,4 +67,4 @@ button:focus-visible {
67
67
  button {
68
68
  background-color: #f9f9f9;
69
69
  }
70
- }
70
+ }
@@ -1,10 +1,10 @@
1
- import React from "react";
2
- import ReactDOM from "react-dom/client";
3
- import App from "./App.tsx";
4
- import "./index.css";
1
+ import React from 'react'
2
+ import ReactDOM from 'react-dom/client'
3
+ import App from './App.tsx'
4
+ import './index.css'
5
5
 
6
- ReactDOM.createRoot(document.getElementById("root")!).render(
6
+ ReactDOM.createRoot(document.getElementById('root')!).render(
7
7
  <React.StrictMode>
8
8
  <App />
9
9
  </React.StrictMode>,
10
- );
10
+ )
@@ -28,4 +28,4 @@
28
28
  },
29
29
  "include": ["src"],
30
30
  "references": [{ "path": "./tsconfig.node.json" }]
31
- }
31
+ }
@@ -1,12 +1,12 @@
1
- import { defineConfig } from "vite";
2
- import react from "@vitejs/plugin-react";
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
3
 
4
4
  // https://vitejs.dev/config/
5
5
  export default defineConfig({
6
6
  plugins: [react()],
7
7
  resolve: {
8
8
  alias: {
9
- "~": "/src",
10
- },
11
- },
12
- });
9
+ '~': '/src'
10
+ }
11
+ }
12
+ })