NAS 정식 스택과 배포 파이프라인 도구를 고정
This commit is contained in:
parent
f1b80676c1
commit
d6d9dc5f61
8 changed files with 812 additions and 1 deletions
90
scripts/preserve-assets.mjs
Normal file
90
scripts/preserve-assets.mjs
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* 이전 Pages 배포 세대의 자산 보존 — immutable preview URL(들)의 HTML/JS/CSS 의존
|
||||
* 그래프를 따라 내려받아, 새 빌드 dist 에 없는 파일만 추가한다(기존 파일은 덮어쓰지 않는다).
|
||||
* 사용: node preserve-assets.mjs
|
||||
*/
|
||||
import { mkdir, writeFile, readFile } from "node:fs/promises";
|
||||
import { createHash } from "node:crypto";
|
||||
import path from "node:path";
|
||||
|
||||
const ORIGINS = [
|
||||
"https://vignette.chanpaca.net",
|
||||
"https://5a525329.vignette-b1q.pages.dev",
|
||||
"https://e1c73735.vignette-b1q.pages.dev",
|
||||
"https://bbebb2d3.vignette-b1q.pages.dev",
|
||||
"https://44edecc8.vignette-b1q.pages.dev",
|
||||
"https://0ffdc694.vignette-b1q.pages.dev",
|
||||
"https://7bd59055.vignette-b1q.pages.dev",
|
||||
];
|
||||
|
||||
const DIST = "dist";
|
||||
|
||||
async function exists(p) {
|
||||
try {
|
||||
await readFile(p);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function collect(origin) {
|
||||
const seen = new Map(); // path -> sha256 hex
|
||||
const html = await (await fetch(origin + "/")).text();
|
||||
// index.html 이 참조하는 엔트리 자산
|
||||
const refs = new Set();
|
||||
for (const m of html.matchAll(/(?:src|href)="(\/[^"]+\.(?:js|css))"/g)) refs.add(m[1]);
|
||||
for (const m of html.matchAll(/(?:src|href)="(\/[^"]+\.(?:png|svg|ico|webmanifest|json|woff2?))"/g))
|
||||
refs.add(m[1]);
|
||||
// JS 청크 의존 그래프 폐쇄
|
||||
const queue = [...refs];
|
||||
while (queue.length) {
|
||||
const ref = queue.pop();
|
||||
if (seen.has(ref)) continue;
|
||||
const res = await fetch(origin + ref);
|
||||
if (!res.ok) {
|
||||
seen.set(ref, "FETCH_FAILED_" + res.status);
|
||||
continue;
|
||||
}
|
||||
const buf = Buffer.from(await res.arrayBuffer());
|
||||
seen.set(ref, createHash("sha256").update(buf).digest("hex"));
|
||||
if (ref.endsWith(".js")) {
|
||||
const text = buf.toString("utf8");
|
||||
for (const m of text.matchAll(/["'`](\.\/[A-Za-z0-9_.-]+\.(?:js|css))["'`]/g)) {
|
||||
const p = path.posix.normalize(path.posix.join(path.posix.dirname(ref), m[1]));
|
||||
if (!seen.has(p)) queue.push(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
return seen;
|
||||
}
|
||||
|
||||
const perOrigin = [];
|
||||
let added = 0;
|
||||
const addedList = [];
|
||||
for (const origin of ORIGINS) {
|
||||
const map = await collect(origin);
|
||||
let ok = 0;
|
||||
for (const [p, sha] of map) {
|
||||
if (sha.startsWith("FETCH_FAILED")) continue;
|
||||
const rel = p.replace(/^\//, "");
|
||||
const target = path.join(DIST, rel);
|
||||
if (await exists(target)) {
|
||||
ok += 1;
|
||||
continue;
|
||||
}
|
||||
await mkdir(path.dirname(target), { recursive: true });
|
||||
const res = await fetch(origin + p);
|
||||
await writeFile(target, Buffer.from(await res.arrayBuffer()));
|
||||
added += 1;
|
||||
addedList.push(rel);
|
||||
}
|
||||
perOrigin.push({ origin, assets: map.size, reused_in_new_build: ok });
|
||||
console.log(`origin ${origin}: ${map.size} assets, ${ok} already in new build`);
|
||||
}
|
||||
console.log(`assets_added: ${added}`);
|
||||
await writeFile(
|
||||
"preserve-report.json",
|
||||
JSON.stringify({ origins: perOrigin, assets_added: added, added: addedList }, null, 1),
|
||||
"utf8",
|
||||
);
|
||||
Loading…
Add table
Add a link
Reference in a new issue