Skip to content

Commit 69964b7

Browse files
feat: fix create-dojo
1 parent 6a5e8e9 commit 69964b7

File tree

10 files changed

+436
-256
lines changed

10 files changed

+436
-256
lines changed

packages/create-dojo/bin/index.d.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
#!/usr/bin/env node
1+
2+
export { }

packages/create-dojo/bin/index.js

100755100644
+65-105
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/create-dojo/bin/index.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/create-dojo/package.json

+12-5
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,28 @@
44
"description": "dojo: scaffolding dojo projects via npx",
55
"author": "dojo",
66
"module": "index.ts",
7-
"main": "./bin/index.js",
7+
"main": "./dist/index.js",
88
"type": "module",
99
"license": "MIT",
1010
"publishConfig": {
1111
"access": "public"
1212
},
13-
"bin": {
14-
"create-dojo": "./bin/index.js"
15-
},
13+
"exports": "./dist/index.js",
14+
"bin": "./dist/index.js",
15+
1616
"scripts": {
17+
"dev": "tsup --watch",
1718
"build": "tsup --dts-resolve"
1819
},
1920
"dependencies": {
2021
"@inquirer/prompts": "^3.3.0",
21-
"cross-spawn": "^7.0.3"
22+
"@types/fs-extra": "^11.0.4",
23+
"@types/prompts": "^2.4.9",
24+
"commander": "^12.1.0",
25+
"cross-spawn": "^7.0.3",
26+
"fs-extra": "^11.2.0",
27+
"prompts": "^2.4.2",
28+
"type-fest": "^4.26.1"
2229
},
2330
"devDependencies": {
2431
"@types/cross-spawn": "^6.0.6",
+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { Command } from "commander";
2+
import path from "path";
3+
import { promises as fs } from "fs";
4+
import spawn from "cross-spawn";
5+
import https from "https";
6+
import { input, select } from "@inquirer/prompts";
7+
8+
const templates = [
9+
{ value: "react-app", description: "React app using Dojo" },
10+
{ value: "react-phaser-example", description: "React/Phaser app using Dojo" },
11+
{ value: "react-pwa-app", description: "React Progressive Web Apps using Dojo" },
12+
{ value: "react-threejs", description: "React Threejs using Dojo" },
13+
];
14+
15+
async function init(projectName: string, cwd: string, template: string) {
16+
const projectPath = path.join(cwd, projectName);
17+
const clientPath = path.join(projectPath, 'client');
18+
const dojoStarterPath = path.join(projectPath, 'dojo-starter');
19+
20+
// Create project directories
21+
await fs.mkdir(projectPath, { recursive: true });
22+
await fs.mkdir(clientPath, { recursive: true });
23+
await fs.mkdir(dojoStarterPath, { recursive: true });
24+
25+
// Clone template into client directory
26+
console.log(`Downloading ${template} into client directory...`);
27+
const cloneResult = spawn.sync("npx", [
28+
"degit",
29+
`dojoengine/dojo.js/clients/react/${template}`,
30+
clientPath,
31+
], { stdio: "inherit" });
32+
33+
if (cloneResult.status !== 0) {
34+
throw new Error(`Failed to clone template: ${template}`);
35+
}
36+
37+
// Rewrite package.json in client directory
38+
await rewritePackageJson(projectName, clientPath);
39+
40+
// Clone dojo-starter
41+
console.log(`Downloading dojo-starter...`);
42+
spawn.sync("npx", ["degit", `dojoengine/dojo-starter`, dojoStarterPath], { stdio: "inherit" });
43+
44+
console.log(`Project initialized at ${projectPath}`);
45+
console.log("Congrats! Your new project has been set up successfully.\n");
46+
console.log(`Navigate into your project directory with:\n cd ${projectName}\n`);
47+
console.log("You can then build the starter and run the client.\n");
48+
console.log("For detailed instructions, follow the README here:\n");
49+
console.log('https://book.dojoengine.org/');
50+
}
51+
52+
async function rewritePackageJson(projectName: string, clientPath: string) {
53+
const packageJsonPath = path.join(clientPath, "package.json");
54+
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf-8"));
55+
const latestVersion = await getLatestVersion();
56+
57+
packageJson.name = projectName;
58+
59+
for (let dep of Object.keys(packageJson.dependencies)) {
60+
if (dep.startsWith("@dojoengine") && packageJson.dependencies[dep].startsWith("workspace:")) {
61+
packageJson.dependencies[dep] = latestVersion;
62+
}
63+
}
64+
65+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
66+
}
67+
68+
async function getLatestVersion(): Promise<string> {
69+
return new Promise((resolve, reject) => {
70+
https.get(
71+
"https://registry.npmjs.org/-/package/@dojoengine/core/dist-tags",
72+
(res) => {
73+
if (res.statusCode === 200) {
74+
let body = "";
75+
res.on("data", (data) => (body += data));
76+
res.on("end", () => {
77+
resolve(JSON.parse(body).latest);
78+
});
79+
} else {
80+
reject(new Error(`Failed to fetch latest version: ${res.statusCode}`));
81+
}
82+
}
83+
).on("error", (error) => {
84+
reject(error);
85+
});
86+
});
87+
}
88+
89+
export const start = new Command()
90+
.name("start")
91+
.description("initialize a new project with a selected template")
92+
.option("-c, --cwd <cwd>", "the working directory", process.cwd())
93+
.action(async (options) => {
94+
try {
95+
const cwd = path.resolve(options.cwd);
96+
97+
const template = await select({
98+
message: "Select a template",
99+
choices: templates,
100+
});
101+
102+
const projectName = await input({
103+
message: "Project name ",
104+
validate: (input: string) => {
105+
if (/^([A-Za-z\-\_\d])+$/.test(input)) return true;
106+
else return "Project name may only include letters, numbers, underscores and hashes.";
107+
},
108+
default: template,
109+
});
110+
111+
await init(projectName, cwd, template);
112+
} catch (error) {
113+
console.error("An error occurred:", error);
114+
process.exit(1);
115+
}
116+
});

0 commit comments

Comments
 (0)