react-client 1.0.27 ā 1.0.30
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 +0 -2
- package/dist/cli/commands/build.js +48 -42
- package/dist/cli/commands/dev.js +561 -457
- package/dist/cli/commands/init.js +75 -70
- package/dist/cli/commands/preview.js +130 -124
- package/dist/cli/index.js +32 -32
- package/dist/cli/types.js +1 -3
- package/dist/index.js +2 -20
- package/dist/server/broadcastManager.js +9 -16
- package/dist/utils/loadConfig.js +70 -98
- package/dist/utils/string.js +1 -4
- package/package.json +6 -6
|
@@ -1,48 +1,52 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return (
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
4
9
|
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import fs from 'fs-extra';
|
|
12
|
+
import prompts from 'prompts';
|
|
13
|
+
import chalk from 'chalk';
|
|
14
|
+
import { execSync } from 'child_process';
|
|
15
|
+
export default function initCmd(name, opts) {
|
|
16
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
17
|
+
const root = process.cwd();
|
|
18
|
+
const projectDir = path.resolve(root, name);
|
|
19
|
+
const template = opts.template || 'react-ts';
|
|
20
|
+
console.log(chalk.cyan(`\nš¦ Creating new React Client app: ${chalk.bold(name)}`));
|
|
21
|
+
// 1ļøā£ Check if directory exists
|
|
22
|
+
if (fs.existsSync(projectDir)) {
|
|
23
|
+
const res = yield prompts({
|
|
24
|
+
type: 'confirm',
|
|
25
|
+
name: 'overwrite',
|
|
26
|
+
message: chalk.yellow(`Directory "${name}" already exists. Overwrite?`),
|
|
27
|
+
initial: false,
|
|
28
|
+
});
|
|
29
|
+
if (!res.overwrite) {
|
|
30
|
+
console.log(chalk.red('ā Operation cancelled.'));
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
yield fs.remove(projectDir);
|
|
34
|
+
}
|
|
35
|
+
yield fs.ensureDir(projectDir);
|
|
36
|
+
// 2ļøā£ Locate template
|
|
37
|
+
const templateDir = path.resolve(__dirname, '../../../templates', template);
|
|
38
|
+
if (!fs.existsSync(templateDir)) {
|
|
39
|
+
console.error(chalk.red(`ā Template not found: ${template}`));
|
|
27
40
|
process.exit(1);
|
|
28
41
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
// 3ļøā£ Copy template
|
|
39
|
-
console.log(chalk_1.default.gray(`\nš Copying template: ${template}...`));
|
|
40
|
-
await fs_extra_1.default.copy(templateDir, projectDir);
|
|
41
|
-
// 4ļøā£ Optionally create react-client.config.js (not .ts)
|
|
42
|
-
if (opts.withConfig) {
|
|
43
|
-
const configPath = path_1.default.join(projectDir, 'react-client.config.js');
|
|
44
|
-
if (!fs_extra_1.default.existsSync(configPath)) {
|
|
45
|
-
const configContent = `// react-client.config.js
|
|
42
|
+
// 3ļøā£ Copy template
|
|
43
|
+
console.log(chalk.gray(`\nš Copying template: ${template}...`));
|
|
44
|
+
yield fs.copy(templateDir, projectDir);
|
|
45
|
+
// 4ļøā£ Optionally create react-client.config.js (not .ts)
|
|
46
|
+
if (opts.withConfig) {
|
|
47
|
+
const configPath = path.join(projectDir, 'react-client.config.js');
|
|
48
|
+
if (!fs.existsSync(configPath)) {
|
|
49
|
+
const configContent = `// react-client.config.js
|
|
46
50
|
import { defineConfig } from 'react-client/config';
|
|
47
51
|
|
|
48
52
|
export default defineConfig({
|
|
@@ -62,33 +66,34 @@ export default defineConfig({
|
|
|
62
66
|
// š” Add plugins, aliases, etc.
|
|
63
67
|
});
|
|
64
68
|
`;
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
yield fs.writeFile(configPath, configContent, 'utf8');
|
|
70
|
+
console.log(chalk.green('š Created react-client.config.js'));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// 5ļøā£ Initialize git repo
|
|
74
|
+
try {
|
|
75
|
+
execSync('git init', { cwd: projectDir, stdio: 'ignore' });
|
|
76
|
+
console.log(chalk.gray('š§ Initialized Git repository.'));
|
|
77
|
+
}
|
|
78
|
+
catch (_a) {
|
|
79
|
+
console.warn(chalk.yellow('ā ļø Git init failed (skipping).'));
|
|
80
|
+
}
|
|
81
|
+
// 6ļøā£ Install dependencies
|
|
82
|
+
const pkgManager = /yarn/.test(process.env.npm_execpath || '') ? 'yarn' : 'npm';
|
|
83
|
+
console.log(chalk.gray(`\nš¦ Installing dependencies using ${pkgManager}...`));
|
|
84
|
+
try {
|
|
85
|
+
execSync(`${pkgManager} install`, { cwd: projectDir, stdio: 'inherit' });
|
|
86
|
+
}
|
|
87
|
+
catch (_b) {
|
|
88
|
+
console.warn(chalk.yellow('ā ļø Dependency installation failed, please run manually.'));
|
|
67
89
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
(
|
|
72
|
-
console.log(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
console.
|
|
76
|
-
}
|
|
77
|
-
// 6ļøā£ Install dependencies
|
|
78
|
-
const pkgManager = /yarn/.test(process.env.npm_execpath || '') ? 'yarn' : 'npm';
|
|
79
|
-
console.log(chalk_1.default.gray(`\nš¦ Installing dependencies using ${pkgManager}...`));
|
|
80
|
-
try {
|
|
81
|
-
(0, child_process_1.execSync)(`${pkgManager} install`, { cwd: projectDir, stdio: 'inherit' });
|
|
82
|
-
}
|
|
83
|
-
catch {
|
|
84
|
-
console.warn(chalk_1.default.yellow('ā ļø Dependency installation failed, please run manually.'));
|
|
85
|
-
}
|
|
86
|
-
// 7ļøā£ Completion message
|
|
87
|
-
console.log();
|
|
88
|
-
console.log(chalk_1.default.green('ā
Project setup complete!'));
|
|
89
|
-
console.log(chalk_1.default.cyan(`\nNext steps:`));
|
|
90
|
-
console.log(chalk_1.default.gray(` cd ${name}`));
|
|
91
|
-
console.log(chalk_1.default.gray(` ${pkgManager === 'yarn' ? 'yarn dev' : 'npm run dev'}`));
|
|
92
|
-
console.log();
|
|
93
|
-
console.log(chalk_1.default.dim('Happy coding! ā”'));
|
|
90
|
+
// 7ļøā£ Completion message
|
|
91
|
+
console.log();
|
|
92
|
+
console.log(chalk.green('ā
Project setup complete!'));
|
|
93
|
+
console.log(chalk.cyan(`\nNext steps:`));
|
|
94
|
+
console.log(chalk.gray(` cd ${name}`));
|
|
95
|
+
console.log(chalk.gray(` ${pkgManager === 'yarn' ? 'yarn dev' : 'npm run dev'}`));
|
|
96
|
+
console.log();
|
|
97
|
+
console.log(chalk.dim('Happy coding! ā”'));
|
|
98
|
+
});
|
|
94
99
|
}
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
return (
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
4
9
|
};
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const open_1 = __importDefault(require("open"));
|
|
14
|
-
const loadConfig_1 = require("../../utils/loadConfig");
|
|
10
|
+
import http from 'http';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import fs from 'fs-extra';
|
|
13
|
+
import chalk from 'chalk';
|
|
14
|
+
import detectPort from 'detect-port';
|
|
15
|
+
import prompts from 'prompts';
|
|
16
|
+
import open from 'open';
|
|
17
|
+
import { loadReactClientConfig } from '../../utils/loadConfig';
|
|
15
18
|
const MIME = {
|
|
16
19
|
'.html': 'text/html; charset=utf-8',
|
|
17
20
|
'.js': 'application/javascript; charset=utf-8',
|
|
@@ -31,7 +34,7 @@ const MIME = {
|
|
|
31
34
|
'.txt': 'text/plain; charset=utf-8',
|
|
32
35
|
};
|
|
33
36
|
function contentType(file) {
|
|
34
|
-
return MIME[
|
|
37
|
+
return MIME[path.extname(file).toLowerCase()] || 'application/octet-stream';
|
|
35
38
|
}
|
|
36
39
|
function setCachingHeaders(res, stat) {
|
|
37
40
|
// Short cache for preview by default, but set ETag/Last-Modified so browsers behave nicely
|
|
@@ -40,126 +43,129 @@ function setCachingHeaders(res, stat) {
|
|
|
40
43
|
res.setHeader('Last-Modified', stat.mtime.toUTCString());
|
|
41
44
|
res.setHeader('Cache-Control', 'public, max-age=0, must-revalidate');
|
|
42
45
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
console.warn(chalk_1.default.yellow(`ā ļø index.html not found in ${outDir}. SPA fallback will be disabled.`));
|
|
55
|
-
}
|
|
56
|
-
const defaultPort = config.server?.port || 4173;
|
|
57
|
-
const port = await (0, detect_port_1.default)(defaultPort);
|
|
58
|
-
if (port !== defaultPort) {
|
|
59
|
-
const r = await (0, prompts_1.default)({
|
|
60
|
-
type: 'confirm',
|
|
61
|
-
name: 'useNewPort',
|
|
62
|
-
initial: true,
|
|
63
|
-
message: `Port ${defaultPort} is occupied. Use ${port} instead?`,
|
|
64
|
-
});
|
|
65
|
-
if (!r.useNewPort) {
|
|
66
|
-
console.log('š Preview cancelled.');
|
|
67
|
-
process.exit(0);
|
|
46
|
+
export default function preview() {
|
|
47
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
+
var _a, _b;
|
|
49
|
+
const cwd = process.cwd();
|
|
50
|
+
const config = yield loadReactClientConfig(cwd);
|
|
51
|
+
const appRoot = path.resolve(cwd, config.root || '.');
|
|
52
|
+
const outDir = path.join(appRoot, ((_a = config.build) === null || _a === void 0 ? void 0 : _a.outDir) || 'dist');
|
|
53
|
+
const indexHtml = path.join(outDir, 'index.html');
|
|
54
|
+
if (!(yield fs.pathExists(outDir))) {
|
|
55
|
+
console.error(chalk.red(`ā Preview directory not found: ${outDir}`));
|
|
56
|
+
process.exit(1);
|
|
68
57
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
58
|
+
if (!(yield fs.pathExists(indexHtml))) {
|
|
59
|
+
console.warn(chalk.yellow(`ā ļø index.html not found in ${outDir}. SPA fallback will be disabled.`));
|
|
60
|
+
}
|
|
61
|
+
const defaultPort = ((_b = config.server) === null || _b === void 0 ? void 0 : _b.port) || 4173;
|
|
62
|
+
const port = yield detectPort(defaultPort);
|
|
63
|
+
if (port !== defaultPort) {
|
|
64
|
+
const r = yield prompts({
|
|
65
|
+
type: 'confirm',
|
|
66
|
+
name: 'useNewPort',
|
|
67
|
+
initial: true,
|
|
68
|
+
message: `Port ${defaultPort} is occupied. Use ${port} instead?`,
|
|
69
|
+
});
|
|
70
|
+
if (!r.useNewPort) {
|
|
71
|
+
console.log('š Preview cancelled.');
|
|
72
|
+
process.exit(0);
|
|
78
73
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
else {
|
|
89
|
-
res.writeHead(404);
|
|
90
|
-
return res.end('Not found');
|
|
74
|
+
}
|
|
75
|
+
const server = http.createServer((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
76
|
+
try {
|
|
77
|
+
const url = req.url || '/';
|
|
78
|
+
// normalize and protect
|
|
79
|
+
const relPath = decodeURIComponent(url.split('?')[0]);
|
|
80
|
+
if (relPath.includes('..')) {
|
|
81
|
+
res.writeHead(400);
|
|
82
|
+
return res.end('Invalid request');
|
|
91
83
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
84
|
+
// handle root -> index.html
|
|
85
|
+
let filePath = path.join(outDir, relPath);
|
|
86
|
+
const tryIndexFallback = () => __awaiter(this, void 0, void 0, function* () {
|
|
87
|
+
if (yield fs.pathExists(indexHtml)) {
|
|
88
|
+
const stat = yield fs.stat(indexHtml);
|
|
89
|
+
setCachingHeaders(res, stat);
|
|
90
|
+
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
91
|
+
return fs.createReadStream(indexHtml).pipe(res);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
res.writeHead(404);
|
|
95
|
+
return res.end('Not found');
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
// If the request path is a directory, try index.html inside it
|
|
99
|
+
if (relPath.endsWith('/')) {
|
|
100
|
+
const candidate = path.join(filePath, 'index.html');
|
|
101
|
+
if (yield fs.pathExists(candidate)) {
|
|
102
|
+
filePath = candidate;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
return tryIndexFallback();
|
|
106
|
+
}
|
|
98
107
|
}
|
|
99
|
-
|
|
108
|
+
// If file doesn't exist, fallback to index.html for SPA routes
|
|
109
|
+
if (!(yield fs.pathExists(filePath))) {
|
|
110
|
+
// If request appears to be a static asset (has extension), return 404
|
|
111
|
+
if (path.extname(filePath)) {
|
|
112
|
+
res.writeHead(404);
|
|
113
|
+
return res.end('Not found');
|
|
114
|
+
}
|
|
100
115
|
return tryIndexFallback();
|
|
101
116
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
// If request appears to be a static asset (has extension), return 404
|
|
106
|
-
if (path_1.default.extname(filePath)) {
|
|
107
|
-
res.writeHead(404);
|
|
108
|
-
return res.end('Not found');
|
|
109
|
-
}
|
|
110
|
-
return tryIndexFallback();
|
|
111
|
-
}
|
|
112
|
-
const stat = await fs_extra_1.default.stat(filePath);
|
|
113
|
-
if (!stat.isFile()) {
|
|
114
|
-
return tryIndexFallback();
|
|
115
|
-
}
|
|
116
|
-
// Compression/Precompressed support: prefer brotli -> gzip -> raw
|
|
117
|
-
const accept = (req.headers['accept-encoding'] || '');
|
|
118
|
-
const tryPrecompressed = async () => {
|
|
119
|
-
if (accept.includes('br') && (await fs_extra_1.default.pathExists(filePath + '.br'))) {
|
|
120
|
-
res.setHeader('Content-Encoding', 'br');
|
|
121
|
-
res.setHeader('Content-Type', contentType(filePath));
|
|
122
|
-
setCachingHeaders(res, stat);
|
|
123
|
-
return fs_extra_1.default.createReadStream(filePath + '.br').pipe(res);
|
|
117
|
+
const stat = yield fs.stat(filePath);
|
|
118
|
+
if (!stat.isFile()) {
|
|
119
|
+
return tryIndexFallback();
|
|
124
120
|
}
|
|
125
|
-
|
|
126
|
-
|
|
121
|
+
// Compression/Precompressed support: prefer brotli -> gzip -> raw
|
|
122
|
+
const accept = (req.headers['accept-encoding'] || '');
|
|
123
|
+
const tryPrecompressed = () => __awaiter(this, void 0, void 0, function* () {
|
|
124
|
+
if (accept.includes('br') && (yield fs.pathExists(filePath + '.br'))) {
|
|
125
|
+
res.setHeader('Content-Encoding', 'br');
|
|
126
|
+
res.setHeader('Content-Type', contentType(filePath));
|
|
127
|
+
setCachingHeaders(res, stat);
|
|
128
|
+
return fs.createReadStream(filePath + '.br').pipe(res);
|
|
129
|
+
}
|
|
130
|
+
if (accept.includes('gzip') && (yield fs.pathExists(filePath + '.gz'))) {
|
|
131
|
+
res.setHeader('Content-Encoding', 'gzip');
|
|
132
|
+
res.setHeader('Content-Type', contentType(filePath));
|
|
133
|
+
setCachingHeaders(res, stat);
|
|
134
|
+
return fs.createReadStream(filePath + '.gz').pipe(res);
|
|
135
|
+
}
|
|
136
|
+
// default
|
|
127
137
|
res.setHeader('Content-Type', contentType(filePath));
|
|
128
138
|
setCachingHeaders(res, stat);
|
|
129
|
-
return
|
|
139
|
+
return fs.createReadStream(filePath).pipe(res);
|
|
140
|
+
});
|
|
141
|
+
// ETag / If-None-Match handling
|
|
142
|
+
const etag = `${stat.size}-${Date.parse(stat.mtime.toString())}`;
|
|
143
|
+
const inm = req.headers['if-none-match'];
|
|
144
|
+
if (inm && inm.toString() === etag) {
|
|
145
|
+
res.writeHead(304);
|
|
146
|
+
return res.end();
|
|
130
147
|
}
|
|
131
|
-
|
|
132
|
-
res.setHeader('Content-Type', contentType(filePath));
|
|
133
|
-
setCachingHeaders(res, stat);
|
|
134
|
-
return fs_extra_1.default.createReadStream(filePath).pipe(res);
|
|
135
|
-
};
|
|
136
|
-
// ETag / If-None-Match handling
|
|
137
|
-
const etag = `${stat.size}-${Date.parse(stat.mtime.toString())}`;
|
|
138
|
-
const inm = req.headers['if-none-match'];
|
|
139
|
-
if (inm && inm.toString() === etag) {
|
|
140
|
-
res.writeHead(304);
|
|
141
|
-
return res.end();
|
|
148
|
+
return tryPrecompressed();
|
|
142
149
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
process.exit(0);
|
|
150
|
+
catch (err) {
|
|
151
|
+
const e = err;
|
|
152
|
+
console.error('Preview server error:', e);
|
|
153
|
+
res.writeHead(500);
|
|
154
|
+
res.end('Internal Server Error');
|
|
155
|
+
}
|
|
156
|
+
}));
|
|
157
|
+
server.listen(port, () => __awaiter(this, void 0, void 0, function* () {
|
|
158
|
+
const url = `http://localhost:${port}`;
|
|
159
|
+
console.log(chalk.cyan.bold('\nš react-client preview'));
|
|
160
|
+
console.log(chalk.gray('āāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
161
|
+
console.log(chalk.green(`Serving: ${outDir}`));
|
|
162
|
+
console.log(chalk.green(`Open: ${url}`));
|
|
163
|
+
yield open(url, { newInstance: true });
|
|
164
|
+
}));
|
|
165
|
+
process.on('SIGINT', () => {
|
|
166
|
+
console.log(chalk.red('\nš Shutting down preview...'));
|
|
167
|
+
server.close();
|
|
168
|
+
process.exit(0);
|
|
169
|
+
});
|
|
164
170
|
});
|
|
165
171
|
}
|
package/dist/cli/index.js
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
};
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const preview_1 = __importDefault(require("./commands/preview"));
|
|
2
|
+
import { dirname, resolve } from 'path';
|
|
3
|
+
import fs from 'fs-extra';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
7
|
+
import initCmd from './commands/init';
|
|
8
|
+
import devCmd from './commands/dev';
|
|
9
|
+
import buildCmd from './commands/build';
|
|
10
|
+
import previewCmd from './commands/preview';
|
|
11
|
+
// Polyfill for __dirname in ESM
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
15
14
|
// Load package.json version dynamically
|
|
16
|
-
const pkgPath =
|
|
17
|
-
const
|
|
18
|
-
|
|
15
|
+
const pkgPath = resolve(__dirname, '../../package.json');
|
|
16
|
+
const isMainModule = process.argv[1] && pathToFileURL(process.argv[1]).href === import.meta.url;
|
|
17
|
+
const pkg = fs.existsSync(pkgPath)
|
|
18
|
+
? JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
|
|
19
19
|
: { version: '0.0.0' };
|
|
20
20
|
// š§ Fancy startup banner
|
|
21
21
|
function showBanner(cmd) {
|
|
22
|
-
const title =
|
|
23
|
-
const version =
|
|
24
|
-
const tagline =
|
|
25
|
-
const line =
|
|
22
|
+
const title = chalk.bold.cyan('ā” React Client');
|
|
23
|
+
const version = chalk.gray(`v${pkg.version}`);
|
|
24
|
+
const tagline = chalk.dim('Fast esbuild-based React CLI with HMR & Overlay');
|
|
25
|
+
const line = chalk.gray('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
26
26
|
console.log(`\n${title} ${version}`);
|
|
27
27
|
console.log(tagline);
|
|
28
28
|
console.log(line);
|
|
29
29
|
switch (cmd) {
|
|
30
30
|
case 'init':
|
|
31
|
-
console.log(
|
|
31
|
+
console.log(chalk.cyan('š¦ Initializing new React project...\n'));
|
|
32
32
|
break;
|
|
33
33
|
case 'dev':
|
|
34
|
-
console.log(
|
|
34
|
+
console.log(chalk.green('š Starting development server...\n'));
|
|
35
35
|
break;
|
|
36
36
|
case 'build':
|
|
37
|
-
console.log(
|
|
37
|
+
console.log(chalk.yellow('šļø Building for production...\n'));
|
|
38
38
|
break;
|
|
39
39
|
case 'preview':
|
|
40
|
-
console.log(
|
|
40
|
+
console.log(chalk.blue('š Starting production preview server...\n'));
|
|
41
41
|
break;
|
|
42
42
|
default:
|
|
43
43
|
console.log();
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
// š§© Commander setup
|
|
47
|
-
const program = new
|
|
47
|
+
const program = new Command();
|
|
48
48
|
program
|
|
49
49
|
.name('react-client')
|
|
50
50
|
.description('react-client CLI ā A lightweight React toolkit for fast builds & dev server')
|
|
@@ -59,34 +59,34 @@ program
|
|
|
59
59
|
.description('initialize a new React project')
|
|
60
60
|
.action((name, opts) => {
|
|
61
61
|
showBanner('init');
|
|
62
|
-
(
|
|
62
|
+
initCmd(name, opts);
|
|
63
63
|
});
|
|
64
64
|
program
|
|
65
65
|
.command('dev')
|
|
66
66
|
.description('start dev server (with React Fast Refresh)')
|
|
67
67
|
.action(() => {
|
|
68
68
|
showBanner('dev');
|
|
69
|
-
(
|
|
69
|
+
devCmd();
|
|
70
70
|
});
|
|
71
71
|
program
|
|
72
72
|
.command('build')
|
|
73
73
|
.description('build production assets')
|
|
74
74
|
.action(() => {
|
|
75
75
|
showBanner('build');
|
|
76
|
-
(
|
|
76
|
+
buildCmd();
|
|
77
77
|
});
|
|
78
78
|
program
|
|
79
79
|
.command('preview')
|
|
80
80
|
.description('preview production build')
|
|
81
81
|
.action(() => {
|
|
82
82
|
showBanner('preview');
|
|
83
|
-
(
|
|
83
|
+
previewCmd();
|
|
84
84
|
});
|
|
85
85
|
// ------------------------------------------------------
|
|
86
86
|
// Default / Unknown command handling
|
|
87
87
|
// ------------------------------------------------------
|
|
88
88
|
program.on('command:*', () => {
|
|
89
|
-
console.error(
|
|
89
|
+
console.error(chalk.red('ā Invalid command:'), program.args.join(' '));
|
|
90
90
|
console.log();
|
|
91
91
|
program.outputHelp();
|
|
92
92
|
process.exit(1);
|
|
@@ -94,7 +94,7 @@ program.on('command:*', () => {
|
|
|
94
94
|
// ------------------------------------------------------
|
|
95
95
|
// Entry point
|
|
96
96
|
// ------------------------------------------------------
|
|
97
|
-
if (
|
|
97
|
+
if (isMainModule) {
|
|
98
98
|
if (process.argv.length <= 2) {
|
|
99
99
|
console.clear();
|
|
100
100
|
showBanner();
|
|
@@ -104,4 +104,4 @@ if (require.main === module) {
|
|
|
104
104
|
program.parse(process.argv);
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
-
|
|
107
|
+
export default program;
|
package/dist/cli/types.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,20 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.defineConfig = void 0;
|
|
18
|
-
const defineConfig = (c) => c;
|
|
19
|
-
exports.defineConfig = defineConfig;
|
|
20
|
-
__exportStar(require("./cli/index"), exports);
|
|
1
|
+
export const defineConfig = (c) => c;
|
|
2
|
+
export * from './cli/index';
|