otro generador de sitios estáticos? en serio?
This commit is contained in:
commit
827d1dfc04
7 changed files with 481 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
node_modules/
|
75
gen.js
Executable file
75
gen.js
Executable file
|
@ -0,0 +1,75 @@
|
|||
import { lstat, mkdir, readdir } from "fs/promises";
|
||||
import { dirname, join, relative, resolve } from "path";
|
||||
import { cwd } from "process";
|
||||
|
||||
import js from "./transformers/js.js";
|
||||
import copy from "./transformers/copy.js";
|
||||
|
||||
const sitegenConfigPath = join(cwd(), "sitegen.config.js");
|
||||
/** @type {any} */
|
||||
let config = {};
|
||||
try {
|
||||
await lstat(sitegenConfigPath);
|
||||
config = await import(sitegenConfigPath);
|
||||
} catch {}
|
||||
|
||||
const inputDirPath = "./src";
|
||||
const outputDirPath = join(cwd(), "_site");
|
||||
|
||||
const transformers = {
|
||||
".s.js": js,
|
||||
".s.jsx": js,
|
||||
".png": copy,
|
||||
".jpg": copy,
|
||||
".jpeg": copy,
|
||||
".avif": copy,
|
||||
".webp": copy,
|
||||
".woff": copy,
|
||||
".woff2": copy,
|
||||
...(config?.transformers || {}),
|
||||
};
|
||||
|
||||
let built = 0;
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
*/
|
||||
async function buildFile(path) {
|
||||
const transformerEnt = Object.entries(transformers).find(([ext]) =>
|
||||
path.endsWith(ext)
|
||||
);
|
||||
if (!transformerEnt) return;
|
||||
const outputPath = join(outputDirPath, relative(inputDirPath, path));
|
||||
await mkdir(dirname(outputPath), { recursive: true });
|
||||
const transformer = transformerEnt[1];
|
||||
try {
|
||||
await transformer.build(path, outputPath);
|
||||
} catch (error) {
|
||||
console.error(`While building ${path}`);
|
||||
throw error;
|
||||
}
|
||||
built++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} dir
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function buildDir(dir) {
|
||||
const children = await readdir(dir, { withFileTypes: true });
|
||||
await Promise.all(
|
||||
children.map((child) => {
|
||||
const path = join(dir, child.name);
|
||||
if (resolve(path) === resolve(outputDirPath)) return;
|
||||
if (resolve(path) === resolve("node_modules")) return;
|
||||
if (resolve(path) === resolve(".git")) return;
|
||||
if (child.isDirectory()) return buildDir(path);
|
||||
else if (child.isFile()) return buildFile(path);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
console.time("build");
|
||||
await buildDir(inputDirPath);
|
||||
console.timeEnd("build");
|
||||
console.info(`Built ${built} files into ${outputDirPath}.`);
|
26
package.json
Normal file
26
package.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "sitegen",
|
||||
"type": "module",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"bin": {
|
||||
"sitegen": "./gen.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.18.17",
|
||||
"nanoid": "^4.0.2",
|
||||
"vhtml": "^2.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tsconfig/node18": "^18.2.0",
|
||||
"@types/node": "^20.4.6",
|
||||
"typescript": "^5.1.6"
|
||||
}
|
||||
}
|
281
pnpm-lock.yaml
Normal file
281
pnpm-lock.yaml
Normal file
|
@ -0,0 +1,281 @@
|
|||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
esbuild:
|
||||
specifier: ^0.18.17
|
||||
version: 0.18.17
|
||||
nanoid:
|
||||
specifier: ^4.0.2
|
||||
version: 4.0.2
|
||||
vhtml:
|
||||
specifier: ^2.2.0
|
||||
version: 2.2.0
|
||||
|
||||
devDependencies:
|
||||
'@tsconfig/node18':
|
||||
specifier: ^18.2.0
|
||||
version: 18.2.0
|
||||
'@types/node':
|
||||
specifier: ^20.4.6
|
||||
version: 20.4.6
|
||||
typescript:
|
||||
specifier: ^5.1.6
|
||||
version: 5.1.6
|
||||
|
||||
packages:
|
||||
|
||||
/@esbuild/android-arm64@0.18.17:
|
||||
resolution: {integrity: sha512-9np+YYdNDed5+Jgr1TdWBsozZ85U1Oa3xW0c7TWqH0y2aGghXtZsuT8nYRbzOMcl0bXZXjOGbksoTtVOlWrRZg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/android-arm@0.18.17:
|
||||
resolution: {integrity: sha512-wHsmJG/dnL3OkpAcwbgoBTTMHVi4Uyou3F5mf58ZtmUyIKfcdA7TROav/6tCzET4A3QW2Q2FC+eFneMU+iyOxg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/android-x64@0.18.17:
|
||||
resolution: {integrity: sha512-O+FeWB/+xya0aLg23hHEM2E3hbfwZzjqumKMSIqcHbNvDa+dza2D0yLuymRBQQnC34CWrsJUXyH2MG5VnLd6uw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/darwin-arm64@0.18.17:
|
||||
resolution: {integrity: sha512-M9uJ9VSB1oli2BE/dJs3zVr9kcCBBsE883prage1NWz6pBS++1oNn/7soPNS3+1DGj0FrkSvnED4Bmlu1VAE9g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/darwin-x64@0.18.17:
|
||||
resolution: {integrity: sha512-XDre+J5YeIJDMfp3n0279DFNrGCXlxOuGsWIkRb1NThMZ0BsrWXoTg23Jer7fEXQ9Ye5QjrvXpxnhzl3bHtk0g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/freebsd-arm64@0.18.17:
|
||||
resolution: {integrity: sha512-cjTzGa3QlNfERa0+ptykyxs5A6FEUQQF0MuilYXYBGdBxD3vxJcKnzDlhDCa1VAJCmAxed6mYhA2KaJIbtiNuQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/freebsd-x64@0.18.17:
|
||||
resolution: {integrity: sha512-sOxEvR8d7V7Kw8QqzxWc7bFfnWnGdaFBut1dRUYtu+EIRXefBc/eIsiUiShnW0hM3FmQ5Zf27suDuHsKgZ5QrA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-arm64@0.18.17:
|
||||
resolution: {integrity: sha512-c9w3tE7qA3CYWjT+M3BMbwMt+0JYOp3vCMKgVBrCl1nwjAlOMYzEo+gG7QaZ9AtqZFj5MbUc885wuBBmu6aADQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-arm@0.18.17:
|
||||
resolution: {integrity: sha512-2d3Lw6wkwgSLC2fIvXKoMNGVaeY8qdN0IC3rfuVxJp89CRfA3e3VqWifGDfuakPmp90+ZirmTfye1n4ncjv2lg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-ia32@0.18.17:
|
||||
resolution: {integrity: sha512-1DS9F966pn5pPnqXYz16dQqWIB0dmDfAQZd6jSSpiT9eX1NzKh07J6VKR3AoXXXEk6CqZMojiVDSZi1SlmKVdg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-loong64@0.18.17:
|
||||
resolution: {integrity: sha512-EvLsxCk6ZF0fpCB6w6eOI2Fc8KW5N6sHlIovNe8uOFObL2O+Mr0bflPHyHwLT6rwMg9r77WOAWb2FqCQrVnwFg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-mips64el@0.18.17:
|
||||
resolution: {integrity: sha512-e0bIdHA5p6l+lwqTE36NAW5hHtw2tNRmHlGBygZC14QObsA3bD4C6sXLJjvnDIjSKhW1/0S3eDy+QmX/uZWEYQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-ppc64@0.18.17:
|
||||
resolution: {integrity: sha512-BAAilJ0M5O2uMxHYGjFKn4nJKF6fNCdP1E0o5t5fvMYYzeIqy2JdAP88Az5LHt9qBoUa4tDaRpfWt21ep5/WqQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-riscv64@0.18.17:
|
||||
resolution: {integrity: sha512-Wh/HW2MPnC3b8BqRSIme/9Zhab36PPH+3zam5pqGRH4pE+4xTrVLx2+XdGp6fVS3L2x+DrsIcsbMleex8fbE6g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-s390x@0.18.17:
|
||||
resolution: {integrity: sha512-j/34jAl3ul3PNcK3pfI0NSlBANduT2UO5kZ7FCaK33XFv3chDhICLY8wJJWIhiQ+YNdQ9dxqQctRg2bvrMlYgg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-x64@0.18.17:
|
||||
resolution: {integrity: sha512-QM50vJ/y+8I60qEmFxMoxIx4de03pGo2HwxdBeFd4nMh364X6TIBZ6VQ5UQmPbQWUVWHWws5MmJXlHAXvJEmpQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/netbsd-x64@0.18.17:
|
||||
resolution: {integrity: sha512-/jGlhWR7Sj9JPZHzXyyMZ1RFMkNPjC6QIAan0sDOtIo2TYk3tZn5UDrkE0XgsTQCxWTTOcMPf9p6Rh2hXtl5TQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/openbsd-x64@0.18.17:
|
||||
resolution: {integrity: sha512-rSEeYaGgyGGf4qZM2NonMhMOP/5EHp4u9ehFiBrg7stH6BYEEjlkVREuDEcQ0LfIl53OXLxNbfuIj7mr5m29TA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/sunos-x64@0.18.17:
|
||||
resolution: {integrity: sha512-Y7ZBbkLqlSgn4+zot4KUNYst0bFoO68tRgI6mY2FIM+b7ZbyNVtNbDP5y8qlu4/knZZ73fgJDlXID+ohY5zt5g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-arm64@0.18.17:
|
||||
resolution: {integrity: sha512-bwPmTJsEQcbZk26oYpc4c/8PvTY3J5/QK8jM19DVlEsAB41M39aWovWoHtNm78sd6ip6prilxeHosPADXtEJFw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-ia32@0.18.17:
|
||||
resolution: {integrity: sha512-H/XaPtPKli2MhW+3CQueo6Ni3Avggi6hP/YvgkEe1aSaxw+AeO8MFjq8DlgfTd9Iz4Yih3QCZI6YLMoyccnPRg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-x64@0.18.17:
|
||||
resolution: {integrity: sha512-fGEb8f2BSA3CW7riJVurug65ACLuQAzKq0SSqkY2b2yHHH0MzDfbLyKIGzHwOI/gkHcxM/leuSW6D5w/LMNitA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tsconfig/node18@18.2.0:
|
||||
resolution: {integrity: sha512-yhxwIlFVSVcMym3O31HoMnRXpoenmpIxcj4Yoes2DUpe+xCJnA7ECQP1Vw889V0jTt/2nzvpLQ/UuMYCd3JPIg==}
|
||||
dev: true
|
||||
|
||||
/@types/node@20.4.6:
|
||||
resolution: {integrity: sha512-q0RkvNgMweWWIvSMDiXhflGUKMdIxBo2M2tYM/0kEGDueQByFzK4KZAgu5YHGFNxziTlppNpTIBcqHQAxlfHdA==}
|
||||
dev: true
|
||||
|
||||
/esbuild@0.18.17:
|
||||
resolution: {integrity: sha512-1GJtYnUxsJreHYA0Y+iQz2UEykonY66HNWOb0yXYZi9/kNrORUEHVg87eQsCtqh59PEJ5YVZJO98JHznMJSWjg==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
'@esbuild/android-arm': 0.18.17
|
||||
'@esbuild/android-arm64': 0.18.17
|
||||
'@esbuild/android-x64': 0.18.17
|
||||
'@esbuild/darwin-arm64': 0.18.17
|
||||
'@esbuild/darwin-x64': 0.18.17
|
||||
'@esbuild/freebsd-arm64': 0.18.17
|
||||
'@esbuild/freebsd-x64': 0.18.17
|
||||
'@esbuild/linux-arm': 0.18.17
|
||||
'@esbuild/linux-arm64': 0.18.17
|
||||
'@esbuild/linux-ia32': 0.18.17
|
||||
'@esbuild/linux-loong64': 0.18.17
|
||||
'@esbuild/linux-mips64el': 0.18.17
|
||||
'@esbuild/linux-ppc64': 0.18.17
|
||||
'@esbuild/linux-riscv64': 0.18.17
|
||||
'@esbuild/linux-s390x': 0.18.17
|
||||
'@esbuild/linux-x64': 0.18.17
|
||||
'@esbuild/netbsd-x64': 0.18.17
|
||||
'@esbuild/openbsd-x64': 0.18.17
|
||||
'@esbuild/sunos-x64': 0.18.17
|
||||
'@esbuild/win32-arm64': 0.18.17
|
||||
'@esbuild/win32-ia32': 0.18.17
|
||||
'@esbuild/win32-x64': 0.18.17
|
||||
dev: false
|
||||
|
||||
/nanoid@4.0.2:
|
||||
resolution: {integrity: sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw==}
|
||||
engines: {node: ^14 || ^16 || >=18}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/typescript@5.1.6:
|
||||
resolution: {integrity: sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==}
|
||||
engines: {node: '>=14.17'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/vhtml@2.2.0:
|
||||
resolution: {integrity: sha512-TPXrXrxBOslRUVnlVkiAqhoXneiertIg86bdvzionrUYhEuiROvyPZNiiP6GIIJ2Q7oPNVyEtIx8gMAZZE9lCQ==}
|
||||
dev: false
|
7
transformers/copy.js
Normal file
7
transformers/copy.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { copyFile, constants } from "fs/promises";
|
||||
|
||||
export default class CopyTransformer {
|
||||
static async build(inputPath, outputPath) {
|
||||
await copyFile(inputPath, outputPath, constants.COPYFILE_FICLONE);
|
||||
}
|
||||
}
|
83
transformers/js.js
Normal file
83
transformers/js.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
import { nanoid } from "nanoid";
|
||||
import { build } from "esbuild";
|
||||
import { mkdir, readFile, rm, writeFile } from "fs/promises";
|
||||
import { cwd } from "process";
|
||||
import { basename, dirname, join } from "path";
|
||||
import h from "vhtml";
|
||||
|
||||
globalThis.vhtml = h;
|
||||
|
||||
export default class JsTransformer {
|
||||
/**
|
||||
* @param {string} inputPath
|
||||
* @param {string} outputPath
|
||||
*/
|
||||
static async build(inputPath, outputPath) {
|
||||
outputPath = join(
|
||||
dirname(outputPath),
|
||||
basename(outputPath, ".s.jsx") + ".html"
|
||||
);
|
||||
const outfile = join(cwd(), `${nanoid()}.mjs`);
|
||||
await mkdir(dirname(outfile), { recursive: true });
|
||||
try {
|
||||
await build({
|
||||
entryPoints: [join(cwd(), inputPath)],
|
||||
outfile,
|
||||
format: "esm",
|
||||
loader: {
|
||||
".json": "json",
|
||||
},
|
||||
|
||||
bundle: true,
|
||||
platform: "node",
|
||||
plugins: [
|
||||
{
|
||||
name: "svg-jsx",
|
||||
setup(build) {
|
||||
build.onLoad({ filter: /\.svg$/ }, async (args) => {
|
||||
const f = await readFile(args.path, "utf-8");
|
||||
const js = `
|
||||
export default (props) => {
|
||||
let s = \`${f}\`;
|
||||
if (props.class)
|
||||
s = s.replace("<svg", \`<svg class="\${props.class}"\`);
|
||||
return (
|
||||
<div
|
||||
class={props.containerClass}
|
||||
dangerouslySetInnerHTML={{ __html: s }}
|
||||
></div>
|
||||
);
|
||||
};
|
||||
`;
|
||||
return { contents: js, loader: "jsx" };
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "relative-import-path",
|
||||
setup(build) {
|
||||
build.onResolve({ filter: /./ }, (args) => {
|
||||
if (args.path.endsWith(".json") || args.path.endsWith(".svg"))
|
||||
return { path: join(args.resolveDir, args.path) };
|
||||
else if (args.path.startsWith("."))
|
||||
return {
|
||||
path: join(args.resolveDir, args.path),
|
||||
external: true,
|
||||
};
|
||||
else return { path: args.path, external: !!args.importer };
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
jsxFactory: "h",
|
||||
banner: { js: `const h = globalThis.vhtml;` },
|
||||
});
|
||||
const file = await import(outfile);
|
||||
const html = "<!doctype html>" + (await file.render());
|
||||
await writeFile(outputPath, html);
|
||||
} finally {
|
||||
}
|
||||
await rm(outfile);
|
||||
}
|
||||
}
|
8
tsconfig.json
Normal file
8
tsconfig.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "@tsconfig/node18/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue