@anaemia/cli 0.3.0 ā 0.3.2
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/dist/commands/create.js +6 -21
- package/dist/commands/typecheck.js +0 -1
- package/dist/utils/fetch-template.js +30 -0
- package/package.json +4 -3
- package/src/commands/create.ts +175 -186
- package/src/commands/dev.ts +9 -13
- package/src/commands/typecheck.ts +1 -1
- package/src/types/rspack-dev-server.d.ts +1 -1
- package/src/utils/fetch-template.ts +37 -0
package/dist/commands/create.js
CHANGED
|
@@ -3,9 +3,12 @@ import path from "path";
|
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import pc from "picocolors";
|
|
5
5
|
import { generateSharedComponent, scaffoldFeature, scaffoldHook, scaffoldPage } from "../scaffold.js";
|
|
6
|
-
import { execSync } from "node:child_process";
|
|
7
6
|
import prompts from "prompts";
|
|
8
7
|
import { transform } from "sucrase";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { fetchTemplate } from "../utils/fetch-template.js";
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = path.dirname(__filename);
|
|
9
12
|
export function register(cli) {
|
|
10
13
|
cli
|
|
11
14
|
.command("create [target]", "initialize an application or generate domain features (e.g., feature:name)")
|
|
@@ -100,25 +103,8 @@ export function register(cli) {
|
|
|
100
103
|
});
|
|
101
104
|
}
|
|
102
105
|
else {
|
|
103
|
-
logger.
|
|
104
|
-
|
|
105
|
-
let packageManager = "npm";
|
|
106
|
-
if (userAgent.includes("pnpm"))
|
|
107
|
-
packageManager = "pnpm";
|
|
108
|
-
else if (userAgent.includes("yarn"))
|
|
109
|
-
packageManager = "yarn";
|
|
110
|
-
try {
|
|
111
|
-
if (packageManager === "pnpm") {
|
|
112
|
-
execSync(`pnpm dlx degit colourlabs/anaemia/templates/base-app "${targetPath}"`, { stdio: "ignore" });
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
execSync(`npx degit colourlabs/anaemia/templates/base-app "${targetPath}"`, { stdio: "ignore" });
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
catch (err) {
|
|
119
|
-
logger.error("could not source template workspace assets locally or from network registry nodes. " + err);
|
|
120
|
-
process.exit(1);
|
|
121
|
-
}
|
|
106
|
+
logger.info("fetching template from remote registry...");
|
|
107
|
+
await fetchTemplate(targetPath);
|
|
122
108
|
}
|
|
123
109
|
const removeGitKeepFiles = (dir) => {
|
|
124
110
|
const files = fs.readdirSync(dir);
|
|
@@ -200,4 +186,3 @@ export function register(cli) {
|
|
|
200
186
|
console.log(` ${pc.cyan("pnpm dev")} ${pc.dim("# launches hot reload server")}\n`);
|
|
201
187
|
});
|
|
202
188
|
}
|
|
203
|
-
;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as tar from "tar";
|
|
2
|
+
import logger from "./logger.js";
|
|
3
|
+
const TAR_URL = "https://codeload.github.com/colourlabs/anaemia/tar.gz/main";
|
|
4
|
+
export async function fetchTemplate(targetPath) {
|
|
5
|
+
logger.info("downloading template...");
|
|
6
|
+
const res = await fetch(TAR_URL);
|
|
7
|
+
if (!res.ok)
|
|
8
|
+
throw new Error(`failed to download template: ${res.statusText}`);
|
|
9
|
+
await new Promise((resolve, reject) => {
|
|
10
|
+
const extract = tar.extract({
|
|
11
|
+
cwd: targetPath,
|
|
12
|
+
strip: 2,
|
|
13
|
+
filter: (p) => p.startsWith("anaemia-main/templates/base-app"),
|
|
14
|
+
});
|
|
15
|
+
extract.on("finish", resolve);
|
|
16
|
+
extract.on("error", reject);
|
|
17
|
+
const reader = res.body.getReader();
|
|
18
|
+
const pump = async () => {
|
|
19
|
+
while (true) {
|
|
20
|
+
const { done, value } = await reader.read();
|
|
21
|
+
if (done) {
|
|
22
|
+
extract.end();
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
extract.write(value);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
pump().catch(reject);
|
|
29
|
+
});
|
|
30
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anaemia/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"anaemia": "./dist/index.js"
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@anaemia/bundler": "^0.3.
|
|
10
|
-
"@anaemia/core": "^0.3.
|
|
9
|
+
"@anaemia/bundler": "^0.3.2",
|
|
10
|
+
"@anaemia/core": "^0.3.2",
|
|
11
11
|
"@rspack/core": "^2.0.5",
|
|
12
12
|
"@rspack/dev-server": "2.0.1",
|
|
13
13
|
"cac": "^7.0.0",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"picocolors": "^1.1.1",
|
|
17
17
|
"prompts": "^2.4.2",
|
|
18
18
|
"sucrase": "^3.35.1",
|
|
19
|
+
"tar": "^7.5.15",
|
|
19
20
|
"ws": "^8.21.0"
|
|
20
21
|
},
|
|
21
22
|
"devDependencies": {
|
package/src/commands/create.ts
CHANGED
|
@@ -4,226 +4,215 @@ import path from "path";
|
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import pc from "picocolors";
|
|
6
6
|
import { generateSharedComponent, scaffoldFeature, scaffoldHook, scaffoldPage } from "../scaffold.js";
|
|
7
|
-
import { execSync } from "node:child_process";
|
|
8
7
|
import prompts from "prompts";
|
|
9
8
|
import { transform } from "sucrase";
|
|
9
|
+
import { fileURLToPath } from "node:url";
|
|
10
|
+
import { fetchTemplate } from "../utils/fetch-template.js";
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = path.dirname(__filename);
|
|
10
14
|
|
|
11
15
|
export function register(cli: CAC) {
|
|
12
16
|
cli
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
.command("create [target]", "initialize an application or generate domain features (e.g., feature:name)")
|
|
18
|
+
.alias("init")
|
|
19
|
+
.action(async (target) => {
|
|
20
|
+
const appRoot = process.cwd();
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
22
|
+
if (target && target.includes(":")) {
|
|
23
|
+
const [type, name] = target.split(":");
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
if (!name) {
|
|
26
|
+
logger.error(`missing name modifier. Use layout template like: ${pc.cyan(`create ${type}:your-name`)}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
+
if (!fs.existsSync(path.join(appRoot, "package.json"))) {
|
|
31
|
+
logger.error("no package.json detected. code generation commands must run inside an Anaemia project root.");
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
const normalizedName = name.trim();
|
|
32
36
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
if (type === "feature") {
|
|
38
|
+
scaffoldFeature(normalizedName, appRoot);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
37
41
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
if (type === "component") {
|
|
43
|
+
generateSharedComponent(appRoot, normalizedName, { logger, pc });
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (type === "page") {
|
|
48
|
+
scaffoldPage(normalizedName, appRoot);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (type === "hook") {
|
|
53
|
+
scaffoldHook(normalizedName, appRoot);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
42
56
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return;
|
|
57
|
+
logger.error(`unknown layout generator type "${type}". Supported variants: "feature:", "component:", "page:", "hook:"`);
|
|
58
|
+
process.exit(1);
|
|
46
59
|
}
|
|
47
60
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
logger.compiler("launching Anaemia project initialization wizard...");
|
|
62
|
+
|
|
63
|
+
const response = await prompts([
|
|
64
|
+
{
|
|
65
|
+
type: target ? null : "text",
|
|
66
|
+
name: "projectName",
|
|
67
|
+
message: "Project name:",
|
|
68
|
+
initial: "anaemia-app",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
type: "select",
|
|
72
|
+
name: "variant",
|
|
73
|
+
message: "Select a variant:",
|
|
74
|
+
choices: [
|
|
75
|
+
{ title: pc.blue("TypeScript (Recommended)"), value: "ts" },
|
|
76
|
+
{ title: pc.yellow("JavaScript"), value: "js" },
|
|
77
|
+
],
|
|
78
|
+
initial: 0,
|
|
79
|
+
},
|
|
80
|
+
]);
|
|
81
|
+
|
|
82
|
+
if (!response.variant && response.variant !== 0) {
|
|
83
|
+
logger.warn("project creation aborted.");
|
|
84
|
+
process.exit(0);
|
|
51
85
|
}
|
|
52
86
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
choices: [
|
|
71
|
-
{ title: pc.blue("TypeScript (Recommended)"), value: "ts" },
|
|
72
|
-
{ title: pc.yellow("JavaScript"), value: "js" },
|
|
73
|
-
],
|
|
74
|
-
initial: 0,
|
|
75
|
-
},
|
|
76
|
-
]);
|
|
77
|
-
|
|
78
|
-
if (!response.variant && response.variant !== 0) {
|
|
79
|
-
logger.warn("project creation aborted.");
|
|
80
|
-
process.exit(0);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const targetDir = target || response.projectName;
|
|
84
|
-
const targetPath = path.resolve(appRoot, targetDir);
|
|
85
|
-
|
|
86
|
-
if (fs.existsSync(targetPath)) {
|
|
87
|
-
const files = fs.readdirSync(targetPath);
|
|
88
|
-
if (files.length > 0) {
|
|
89
|
-
const { overwrite } = await prompts({
|
|
90
|
-
type: "confirm",
|
|
91
|
-
name: "overwrite",
|
|
92
|
-
message: `target directory "${targetDir}" is not empty. remove existing files and continue?`,
|
|
93
|
-
initial: false,
|
|
94
|
-
});
|
|
87
|
+
const targetDir = target || response.projectName;
|
|
88
|
+
const targetPath = path.resolve(appRoot, targetDir);
|
|
89
|
+
|
|
90
|
+
if (fs.existsSync(targetPath)) {
|
|
91
|
+
const files = fs.readdirSync(targetPath);
|
|
92
|
+
if (files.length > 0) {
|
|
93
|
+
const { overwrite } = await prompts({
|
|
94
|
+
type: "confirm",
|
|
95
|
+
name: "overwrite",
|
|
96
|
+
message: `target directory "${targetDir}" is not empty. remove existing files and continue?`,
|
|
97
|
+
initial: false,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (!overwrite) {
|
|
101
|
+
logger.error("aborted to protect existing project directory.");
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
95
104
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
105
|
+
logger.warn(`purging existing files inside ${targetDir}...`);
|
|
106
|
+
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
107
|
+
fs.mkdirSync(targetPath, { recursive: true });
|
|
99
108
|
}
|
|
100
|
-
|
|
101
|
-
logger.warn(`purging existing files inside ${targetDir}...`);
|
|
102
|
-
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
109
|
+
} else {
|
|
103
110
|
fs.mkdirSync(targetPath, { recursive: true });
|
|
104
111
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
let templatePath = path.resolve(__dirname, "../templates/template-base");
|
|
110
|
-
if (!fs.existsSync(templatePath)) {
|
|
111
|
-
templatePath = path.resolve(__dirname, "../templates/base-app");
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (fs.existsSync(templatePath)) {
|
|
115
|
-
logger.info("unpacking localized scaffolding architecture layout structures...");
|
|
116
|
-
fs.cpSync(templatePath, targetPath, {
|
|
117
|
-
recursive: true,
|
|
118
|
-
filter: (src) => !["node_modules", "dist", ".anaemia", ".rspack"].includes(path.basename(src)),
|
|
119
|
-
});
|
|
120
|
-
} else {
|
|
121
|
-
logger.warn("local templates missing. fetching remote registry packages over the network...");
|
|
122
|
-
const userAgent = process.env.npm_config_user_agent || "";
|
|
123
|
-
let packageManager = "npm";
|
|
124
|
-
if (userAgent.includes("pnpm")) packageManager = "pnpm";
|
|
125
|
-
else if (userAgent.includes("yarn")) packageManager = "yarn";
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
if (packageManager === "pnpm") {
|
|
129
|
-
execSync(`pnpm dlx degit colourlabs/anaemia/templates/base-app "${targetPath}"`, { stdio: "ignore" });
|
|
130
|
-
} else {
|
|
131
|
-
execSync(`npx degit colourlabs/anaemia/templates/base-app "${targetPath}"`, { stdio: "ignore" });
|
|
132
|
-
}
|
|
133
|
-
} catch (err) {
|
|
134
|
-
logger.error("could not source template workspace assets locally or from network registry nodes. " + err);
|
|
135
|
-
process.exit(1);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const removeGitKeepFiles = (dir: string) => {
|
|
140
|
-
const files = fs.readdirSync(dir);
|
|
141
|
-
for (const file of files) {
|
|
142
|
-
const fullPath = path.join(dir, file);
|
|
143
|
-
if (fs.statSync(fullPath).isDirectory()) {
|
|
144
|
-
removeGitKeepFiles(fullPath);
|
|
145
|
-
} else if (file === ".gitkeep") {
|
|
146
|
-
fs.unlinkSync(fullPath);
|
|
147
|
-
}
|
|
112
|
+
|
|
113
|
+
let templatePath = path.resolve(__dirname, "../templates/template-base");
|
|
114
|
+
if (!fs.existsSync(templatePath)) {
|
|
115
|
+
templatePath = path.resolve(__dirname, "../templates/base-app");
|
|
148
116
|
}
|
|
149
|
-
};
|
|
150
|
-
removeGitKeepFiles(targetPath);
|
|
151
117
|
|
|
152
|
-
|
|
153
|
-
|
|
118
|
+
if (fs.existsSync(templatePath)) {
|
|
119
|
+
logger.info("unpacking localized scaffolding architecture layout structures...");
|
|
120
|
+
fs.cpSync(templatePath, targetPath, {
|
|
121
|
+
recursive: true,
|
|
122
|
+
filter: (src) => !["node_modules", "dist", ".anaemia", ".rspack"].includes(path.basename(src)),
|
|
123
|
+
});
|
|
124
|
+
} else {
|
|
125
|
+
logger.info("fetching template from remote registry...");
|
|
126
|
+
await fetchTemplate(targetPath);
|
|
127
|
+
}
|
|
154
128
|
|
|
155
|
-
const
|
|
129
|
+
const removeGitKeepFiles = (dir: string) => {
|
|
156
130
|
const files = fs.readdirSync(dir);
|
|
157
|
-
|
|
158
131
|
for (const file of files) {
|
|
159
132
|
const fullPath = path.join(dir, file);
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (
|
|
163
|
-
|
|
164
|
-
} else if (file.endsWith(".ts") || file.endsWith(".tsx")) {
|
|
165
|
-
const isTsx = file.endsWith(".tsx");
|
|
166
|
-
const code = fs.readFileSync(fullPath, "utf8");
|
|
167
|
-
|
|
168
|
-
try {
|
|
169
|
-
const compiled = transform(code, {
|
|
170
|
-
transforms: isTsx ? ["typescript", "jsx"] : ["typescript"],
|
|
171
|
-
jsxRuntime: "preserve",
|
|
172
|
-
production: true,
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
const newExt = isTsx ? ".jsx" : ".js";
|
|
176
|
-
const newPath = fullPath.replace(/\.tsx?$/, newExt);
|
|
177
|
-
|
|
178
|
-
fs.writeFileSync(newPath, compiled.code, "utf8");
|
|
179
|
-
fs.unlinkSync(fullPath);
|
|
180
|
-
} catch {
|
|
181
|
-
logger.warn(`failed to strip types from ${file}, skipping...`);
|
|
182
|
-
}
|
|
133
|
+
if (fs.statSync(fullPath).isDirectory()) {
|
|
134
|
+
removeGitKeepFiles(fullPath);
|
|
135
|
+
} else if (file === ".gitkeep") {
|
|
136
|
+
fs.unlinkSync(fullPath);
|
|
183
137
|
}
|
|
184
138
|
}
|
|
185
139
|
};
|
|
140
|
+
removeGitKeepFiles(targetPath);
|
|
141
|
+
|
|
142
|
+
if (response.variant === "js") {
|
|
143
|
+
logger.info("converting workspace assets to vanilla JavaScript...");
|
|
144
|
+
|
|
145
|
+
const convertTypeScriptToJs = (dir: string) => {
|
|
146
|
+
const files = fs.readdirSync(dir);
|
|
147
|
+
|
|
148
|
+
for (const file of files) {
|
|
149
|
+
const fullPath = path.join(dir, file);
|
|
150
|
+
const stat = fs.statSync(fullPath);
|
|
151
|
+
|
|
152
|
+
if (stat.isDirectory()) {
|
|
153
|
+
convertTypeScriptToJs(fullPath);
|
|
154
|
+
} else if (file.endsWith(".ts") || file.endsWith(".tsx")) {
|
|
155
|
+
const isTsx = file.endsWith(".tsx");
|
|
156
|
+
const code = fs.readFileSync(fullPath, "utf8");
|
|
157
|
+
|
|
158
|
+
try {
|
|
159
|
+
const compiled = transform(code, {
|
|
160
|
+
transforms: isTsx ? ["typescript", "jsx"] : ["typescript"],
|
|
161
|
+
jsxRuntime: "preserve",
|
|
162
|
+
production: true,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
const newExt = isTsx ? ".jsx" : ".js";
|
|
166
|
+
const newPath = fullPath.replace(/\.tsx?$/, newExt);
|
|
167
|
+
|
|
168
|
+
fs.writeFileSync(newPath, compiled.code, "utf8");
|
|
169
|
+
fs.unlinkSync(fullPath);
|
|
170
|
+
} catch {
|
|
171
|
+
logger.warn(`failed to strip types from ${file}, skipping...`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
186
176
|
|
|
187
|
-
|
|
177
|
+
convertTypeScriptToJs(targetPath);
|
|
188
178
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
179
|
+
const tsconfigPath = path.join(targetPath, "tsconfig.json");
|
|
180
|
+
if (fs.existsSync(tsconfigPath)) {
|
|
181
|
+
fs.unlinkSync(tsconfigPath);
|
|
182
|
+
}
|
|
192
183
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
184
|
+
|
|
185
|
+
const pkgJsonPath = path.join(targetPath, "package.json");
|
|
186
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
187
|
+
try {
|
|
188
|
+
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
|
|
189
|
+
pkg.name = path.basename(targetPath);
|
|
190
|
+
|
|
191
|
+
if (response.variant === "js") {
|
|
192
|
+
if (pkg.devDependencies) {
|
|
193
|
+
delete pkg.devDependencies["typescript"];
|
|
194
|
+
delete pkg.devDependencies["@types/node"];
|
|
195
|
+
delete pkg.devDependencies["@typescript-eslint/eslint-plugin"];
|
|
196
|
+
delete pkg.devDependencies["@typescript-eslint/parser"];
|
|
197
|
+
}
|
|
198
|
+
if (pkg.scripts && pkg.scripts.typecheck) {
|
|
199
|
+
delete pkg.scripts.typecheck;
|
|
200
|
+
}
|
|
210
201
|
}
|
|
211
|
-
}
|
|
212
202
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
203
|
+
fs.writeFileSync(pkgJsonPath, JSON.stringify(pkg, null, 2), "utf8");
|
|
204
|
+
} catch (err) {
|
|
205
|
+
logger.error("failed rewriting package.json manifest structures:", err);
|
|
206
|
+
}
|
|
216
207
|
}
|
|
217
|
-
}
|
|
218
208
|
|
|
219
|
-
|
|
220
|
-
|
|
209
|
+
logger.success(`\nš project successfully scaffolded into ${pc.magenta(targetDir)}!`);
|
|
210
|
+
console.log(pc.dim("\nfollow these steps to begin execution:\n"));
|
|
221
211
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
};
|
|
212
|
+
if (targetDir !== ".") {
|
|
213
|
+
console.log(` cd ${pc.cyan(targetDir)}`);
|
|
214
|
+
}
|
|
215
|
+
console.log(` ${pc.cyan("pnpm install")} ${pc.dim("# or npm i / yarn install")}`);
|
|
216
|
+
console.log(` ${pc.cyan("pnpm dev")} ${pc.dim("# launches hot reload server")}\n`);
|
|
217
|
+
});
|
|
218
|
+
}
|
package/src/commands/dev.ts
CHANGED
|
@@ -58,19 +58,15 @@ export function register(cli: CAC) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
setTimeout(() => {
|
|
61
|
-
serverProcess = spawn(
|
|
62
|
-
"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
RSPACK_DEV_PORT: String(targetPort + 1),
|
|
71
|
-
},
|
|
72
|
-
}
|
|
73
|
-
);
|
|
61
|
+
serverProcess = spawn("node", ["--enable-source-maps", path.resolve(appRoot, "./dist/server/index.js")], {
|
|
62
|
+
stdio: "inherit",
|
|
63
|
+
env: {
|
|
64
|
+
...process.env,
|
|
65
|
+
NODE_ENV: "development",
|
|
66
|
+
PORT: String(targetPort),
|
|
67
|
+
RSPACK_DEV_PORT: String(targetPort + 1),
|
|
68
|
+
},
|
|
69
|
+
});
|
|
74
70
|
}, 200);
|
|
75
71
|
};
|
|
76
72
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as tar from "tar";
|
|
2
|
+
import logger from "./logger.js";
|
|
3
|
+
|
|
4
|
+
const TAR_URL = "https://codeload.github.com/colourlabs/anaemia/tar.gz/main";
|
|
5
|
+
|
|
6
|
+
export async function fetchTemplate(targetPath: string): Promise<void> {
|
|
7
|
+
logger.info("downloading template...");
|
|
8
|
+
|
|
9
|
+
const res = await fetch(TAR_URL);
|
|
10
|
+
if (!res.ok) throw new Error(`failed to download template: ${res.statusText}`);
|
|
11
|
+
|
|
12
|
+
await new Promise<void>((resolve, reject) => {
|
|
13
|
+
const extract = tar.extract({
|
|
14
|
+
cwd: targetPath,
|
|
15
|
+
strip: 2,
|
|
16
|
+
filter: (p: string) => p.startsWith("anaemia-main/templates/base-app"),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
extract.on("finish", resolve);
|
|
20
|
+
extract.on("error", reject);
|
|
21
|
+
|
|
22
|
+
const reader = res.body!.getReader();
|
|
23
|
+
|
|
24
|
+
const pump = async () => {
|
|
25
|
+
while (true) {
|
|
26
|
+
const { done, value } = await reader.read();
|
|
27
|
+
if (done) {
|
|
28
|
+
extract.end();
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
extract.write(value);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
pump().catch(reject);
|
|
36
|
+
});
|
|
37
|
+
}
|