chiwaa 0.1.11 → 0.1.12
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/chiwaa.js +55 -3
- package/package.json +1 -1
package/bin/chiwaa.js
CHANGED
|
@@ -236,6 +236,7 @@ function buildIfNeeded(dir, args) {
|
|
|
236
236
|
const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
237
237
|
const found = OUTPUTS.find(([n]) => deps[n]);
|
|
238
238
|
let outName = args.dir || (found ? found[1] : "dist");
|
|
239
|
+
if (found && found[0] === "next" && !args.dir) checkNext(dir);
|
|
239
240
|
if (args["no-build"]) {
|
|
240
241
|
console.log(c.dim("빌드는 건너뜁니다(--no-build)."));
|
|
241
242
|
} else {
|
|
@@ -249,10 +250,60 @@ function buildIfNeeded(dir, args) {
|
|
|
249
250
|
out = path.join(dir, alt);
|
|
250
251
|
}
|
|
251
252
|
if (found && found[0] === "next" && !fs.existsSync(path.join(out, "index.html")))
|
|
252
|
-
fail(
|
|
253
|
+
fail(NEXT_EXPORT_MSG);
|
|
253
254
|
return { out, built: true };
|
|
254
255
|
}
|
|
255
256
|
|
|
257
|
+
// Next.js: 서버에서 돌아가는 기능(API 주소·middleware·서버 액션·서버 렌더링)은 chiwaa 에서 돌지 않는다 — 빌드 전에 알린다
|
|
258
|
+
// (빌드 서버 chiwaa-deployd 의 next_server_features 와 같은 기준)
|
|
259
|
+
const AI_GUIDE = "안내: https://chiwaa.kr/llms.txt";
|
|
260
|
+
const NEXT_EXPORT_MSG =
|
|
261
|
+
"Next.js 는 next.config 에 output: 'export' 를 넣어야 올릴 수 있습니다(예: const nextConfig = { output: \"export\", images: { unoptimized: true } }).\n" +
|
|
262
|
+
`AI 에게 「이 Next.js 앱을 chiwaa 에 올릴 수 있게 output: 'export' 정적 사이트로 바꿔 줘. ${AI_GUIDE}」라고 말해 보세요.`;
|
|
263
|
+
function nextServerFeatures(dir) {
|
|
264
|
+
const found = [];
|
|
265
|
+
const pat = /['"]use server['"]|getServerSideProps|from\s+['"]next\/headers['"]/;
|
|
266
|
+
(function walk(d, rel) {
|
|
267
|
+
for (const e of fs.readdirSync(d, { withFileTypes: true })) {
|
|
268
|
+
if (e.isSymbolicLink() || e.name.startsWith(".")) continue;
|
|
269
|
+
const r = rel ? `${rel}/${e.name}` : e.name;
|
|
270
|
+
const full = path.join(d, e.name);
|
|
271
|
+
if (e.isDirectory()) {
|
|
272
|
+
if (!["node_modules", "out", "public"].includes(e.name)) walk(full, r);
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
const m = e.name.match(/^(.*)\.(js|jsx|ts|tsx|mjs)$/);
|
|
276
|
+
if (!m) continue;
|
|
277
|
+
if ((m[1] === "middleware" && ["", "src"].includes(rel)) ||
|
|
278
|
+
(m[1] === "route" && /(^|\/)app(\/|$)/.test(rel)) ||
|
|
279
|
+
/^(src\/)?pages\/api(\/|$)/.test(rel)) found.push(r);
|
|
280
|
+
else if (fs.statSync(full).size <= 300 * 1024 && pat.test(fs.readFileSync(full, "utf8"))) found.push(r);
|
|
281
|
+
}
|
|
282
|
+
})(dir, "");
|
|
283
|
+
return found;
|
|
284
|
+
}
|
|
285
|
+
function checkNext(dir) {
|
|
286
|
+
const server = nextServerFeatures(dir);
|
|
287
|
+
if (server.length) {
|
|
288
|
+
const shown = server.slice(0, 4).join(", ") + (server.length > 4 ? ` 등 ${server.length}곳` : "");
|
|
289
|
+
fail(`이 Next.js 앱은 서버에서 돌아가는 기능을 씁니다(${shown}). chiwaa 는 화면 파일(HTML·JS)을 올리는 곳이라 이대로는 열리지 않습니다.\n` +
|
|
290
|
+
`AI 에게 「이 Next.js 앱을 chiwaa 에 올릴 수 있게 output: 'export' 정적 사이트로 바꾸고, API·middleware 같은 서버 기능은 맨 위 api/ 폴더의 chiwaa 서버 함수로 옮겨 줘. ${AI_GUIDE}」라고 말해 보세요.`);
|
|
291
|
+
}
|
|
292
|
+
const conf = ["next.config.js", "next.config.mjs", "next.config.cjs", "next.config.ts"].find((n) => fs.existsSync(path.join(dir, n)));
|
|
293
|
+
if (!conf || !/output\s*:\s*['"]export['"]/.test(fs.readFileSync(path.join(dir, conf), "utf8"))) fail(NEXT_EXPORT_MSG);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 첫 화면(index.html)이 없는 폴더를 올리려 하면, 앱이나 HTML 이 들어 있는 하위 폴더를 알려 주고 멈춘다
|
|
297
|
+
function noIndexMessage(dir) {
|
|
298
|
+
const subs = fs.readdirSync(dir, { withFileTypes: true })
|
|
299
|
+
.filter((e) => e.isDirectory() && !e.name.startsWith(".") && !SKIP.has(e.name) &&
|
|
300
|
+
["package.json", "index.html"].some((f) => fs.existsSync(path.join(dir, e.name, f))))
|
|
301
|
+
.map((e) => e.name);
|
|
302
|
+
return "첫 화면 파일(index.html)이 없어 올리지 않았습니다(소스가 그대로 공개되지 않게).\n" +
|
|
303
|
+
(subs.length ? `앱이 하위 폴더에 있는 것 같습니다. 그 폴더에서 올려 보세요: ${subs.slice(0, 3).map((s) => `cd ${s} && npx chiwaa deploy`).join(" / ")}\n` : "") +
|
|
304
|
+
`AI 에게 「이 프로젝트를 chiwaa 에 올릴 수 있게 index.html 이 나오는 정적 사이트로 만들어 줘. ${AI_GUIDE}」라고 말해 보세요.`;
|
|
305
|
+
}
|
|
306
|
+
|
|
256
307
|
// ---------- 사이트 정하기 ----------
|
|
257
308
|
// 사용자가 직접 정한 이름은 바꾸지 않는다 — 규칙에 안 맞으면 거절한다(대문자만 소문자로)
|
|
258
309
|
const NAME_RULE = "사이트 이름은 영문 소문자·숫자·하이픈(-)으로 2~30자, 첫 글자는 영문이나 숫자여야 합니다(하이픈 두 개 연속은 안 됨). 예: my-shop, cafe2026";
|
|
@@ -382,8 +433,7 @@ async function deploy(args) {
|
|
|
382
433
|
}
|
|
383
434
|
const fnCount = files.filter((f) => !f.dir && /^api\/[^/_][^/]*\.(js|ts|mjs)$/.test(f.rel)).length;
|
|
384
435
|
if (fnCount) console.log(c.dim(`서버 함수 ${fnCount}개(api/) 함께 올림 → https://<사이트>/api/<이름>`));
|
|
385
|
-
if (!files.some((f) => !f.dir &&
|
|
386
|
-
console.log(c.dim("참고: 맨 위에 index.html 이 없습니다. 주소로 열면 첫 화면이 안 보일 수 있습니다."));
|
|
436
|
+
if (!files.some((f) => !f.dir && f.rel === "index.html")) fail(noIndexMessage(out));
|
|
387
437
|
const fileCount = files.filter((f) => !f.dir).length;
|
|
388
438
|
console.log(c.dim(`올리는 중: ${path.relative(process.cwd(), out) || "."} — 파일 ${fileCount}개, ${(total / 1048576).toFixed(1)}MB`));
|
|
389
439
|
const gz = makeTarGz(files);
|
|
@@ -395,6 +445,8 @@ async function deploy(args) {
|
|
|
395
445
|
});
|
|
396
446
|
if (r.status !== 200 || !r.data.ok) fail(r.data.message || r.data.error || `배포하지 못했습니다 (${r.status}).`);
|
|
397
447
|
console.log(c.green("✓"), `${preview ? "미리보기 " : ""}배포 완료 ${c.dim(`(${((Date.now() - t0) / 1000).toFixed(1)}초)`)}`);
|
|
448
|
+
const dropped = String(r.data.message || "").indexOf("뺀 파일:");
|
|
449
|
+
if (dropped >= 0) console.log(c.dim(r.data.message.slice(dropped).replace(/\)\s*$/, "")));
|
|
398
450
|
console.log(`\n ${c.bold(c.cyan(r.data.url))}\n`);
|
|
399
451
|
if (preview) console.log(c.dim("운영 주소는 그대로입니다. 괜찮으면 --preview 없이 다시 deploy 하세요. (미리보기는 검색엔진에 나오지 않음)\n"));
|
|
400
452
|
}
|