@randajan/simple-lib
Version:
Supersimple start for developing custom js library
382 lines (364 loc) • 11.7 kB
JavaScript
import {
logger
} from "./chunk-KF2SC7L5.js";
// src/index.js
import { Worker } from "worker_threads";
import { watch } from "chokidar";
import fs3 from "fs-extra";
import server from "live-server";
// src/tools/argv.js
var argv = {};
var _trues = ["y", "t", "true"];
var _falses = ["n", "f", "false"];
var parseValue = (raw) => {
const low = raw.toLowerCase();
if (_trues.includes(low)) {
return true;
}
if (_falses.includes(low)) {
return false;
}
const num = Number(raw);
if (!isNaN(num)) {
return num;
}
return raw;
};
for (const arg of process.argv) {
const pair = String(arg).split("=");
if (pair.length <= 1) {
continue;
}
const key = pair.shift();
if (!key) {
continue;
}
Object.defineProperty(argv, key, { value: parseValue(pair.join("")), enumerable: true });
}
var argv_default = argv;
// src/tools/config.js
import approot from "app-root-path";
import fse from "fs-extra";
// src/tools/inject.js
import fs from "fs-extra";
var injectString = (string, vars = {}) => {
string = string == null ? "" : String(string);
for (let key of new Set(string.match(/(?<=\{\{)[^\{\}]+(?=\}\})/g))) {
string = string.replaceAll("{{" + key + "}}", vars[key] == null ? "" : vars[key]);
}
return string;
};
var injectFile = async (file, vars = {}) => await fs.writeFile(file, injectString(await fs.readFile(file), vars));
// src/tools/config.js
import path3 from "path";
// src/tools/buildFactory.js
import esbuild from "esbuild";
import path2 from "path";
// src/tools/renamer.js
import fs2 from "fs";
import path from "path";
var renameEntries = (dir, files, ext) => {
for (const file of files) {
const oldPath = path.resolve(path.join(dir, file));
const mapPath = path.resolve(path.join(dir, file + ".map"));
if (fs2.existsSync(oldPath)) {
fs2.renameSync(oldPath, oldPath.replace(/\.js$/, ext));
}
if (fs2.existsSync(mapPath)) {
fs2.renameSync(mapPath, mapPath.replace(/\.js\.map$/, ext + ".map"));
}
}
};
// src/tools/buildFactory.js
import { builtinModules } from "module";
import { nodeExternalsPlugin } from "esbuild-node-externals";
var _allowList = ["info", "lib", "node", "web"].map((v) => "@randajan/simple-lib/" + v);
var extPlug = (plugins, bundle) => {
if (!bundle) {
return plugins;
}
return [...plugins, nodeExternalsPlugin({ allowList: [...bundle, ..._allowList] })];
};
var _buildFactory = (opt = {}) => {
const { isLib, globalName, entries, entryPoints, filename, distdir, minify, splitting, plugins, bundle, loader, format, jsx, info } = opt;
let context;
return async (_) => {
if (!context) {
context = await esbuild.context({
globalName,
format,
minify,
color: true,
bundle: true,
sourcemap: true,
logLevel: "error",
entryPoints,
outfile: filename ? path2.join(distdir, filename + (filename.endsWith(".js") ? "" : ".js")) : void 0,
outdir: filename ? void 0 : distdir,
define: { __slib_info: JSON.stringify(info) },
splitting,
external: builtinModules,
plugins: extPlug(plugins, bundle),
loader,
jsx: jsx.transform,
jsxDev: jsx.dev,
jsxFactory: jsx.factory,
jsxFragment: jsx.fragment || jsx.factory,
jsxImportSource: jsx.importSource
});
}
await context.rebuild();
if (!isLib) {
return;
} else if (format === "esm") {
renameEntries(distdir, entries, ".mjs");
} else if (format === "cjs") {
renameEntries(distdir, entries, ".cjs");
}
return context;
};
};
var buildFactory = (config) => {
if (!config.isLib) {
return _buildFactory(config);
}
const { distdir } = config;
const esm = _buildFactory({
...config,
distdir: path2.join(distdir, "esm")
});
const cjs = _buildFactory({
...config,
distdir: path2.join(distdir, "cjs"),
format: "cjs",
splitting: false
});
return (_) => Promise.all([esm(), cjs()]);
};
// src/tools/config.js
var env = argv_default.env || "development";
var root = approot.path;
var { name, description, version, author } = fse.readJSONSync(path3.join(root, "package.json"));
var _modes = ["web", "node"];
var parseConfig = (isBuild, c = {}) => {
const port = c.port || argv_default.port || 3e3;
const mode = c.mode != null ? c.mode : _modes[0];
const minify = c.minify != null ? c.minify : false;
const info = { ...c.info ? c.info : {}, isBuild, name, description, version, author, env, mode };
const injects = c.injects || ["index.html"];
const rebuildBuffer = Math.max(0, Number(c.rebuildBuffer) || 100);
const bundle = c.bundle || [];
const plugins = c.plugins || [];
const loader = c.loader || {};
const jsx = c.jsx || {};
if (!_modes.includes(mode)) {
throw Error(`mode should be one of '${_modes.join("', '")}' but '${mode}' provided`);
}
const isWeb = mode === "web";
const lib = c.lib || {};
const demo = c.demo || {};
lib.isLib = true;
lib.dir = lib.dir || "";
lib.format = "esm";
lib.splitting = true;
demo.dir = demo.dir || "demo";
demo.format = isWeb ? "iife" : "esm";
for (const x of [lib, demo]) {
x.srcdir = path3.join(x.dir, x.srcdir || "src");
x.distdir = path3.join(x.dir, x.distdir || "dist");
x.entries = x.entries || ["index.js"];
x.entryPoints = x.entries.map((e) => path3.join(x.srcdir, e));
x.minify = x.minify != null ? x.minify : minify;
x.plugins = [...x.plugins || [], ...plugins];
x.bundle = x.isLib || !isWeb ? [...x.bundle || [], ...bundle] : void 0;
x.loader = { ...x.loader || {}, ...loader };
x.jsx = x.jsx ? { ...jsx, ...x.jsx } : jsx;
x.info = { ...x.info || {}, ...argv_default, ...info, port, mode, dir: { root, dist: x.distdir } };
x.rebuild = buildFactory(x);
}
if (lib.standalone) {
const libRebuild = lib.rebuild;
const sa = typeof lib.standalone == "object" ? lib.standalone : { ...lib, entries: { [lib.standalone]: "index.js" }, distdir: "" };
const { distdir, entries, bundle: bundle2, plugins: plugins2, loader: loader2, jsx: jsx2 } = sa;
const temp = {
distdir: path3.join(lib.distdir, distdir || "standalone"),
minify: false,
splitting: false,
plugins: plugins2 || lib.plugins,
bundle: bundle2 || lib.bundle,
loader: loader2 || lib.loader,
format: "iife",
jsx: jsx2 || lib.jsx,
info: lib.info
};
const saRebuilds = Object.entries(entries).map(([name2, entry]) => {
return buildFactory({
globalName: name2,
filename: name2,
entries: [entry],
entryPoints: [path3.join(lib.srcdir, entry)],
...temp
});
});
lib.rebuild = (_) => Promise.all([libRebuild(), ...saRebuilds.map((sarb) => sarb())]);
}
const statics = !lib.statics ? [] : lib.statics.map((stc) => {
const srcdir = path3.join(lib.srcdir, stc);
const distdir = path3.join(lib.distdir, stc);
const rebuild = (_) => fse.copy(srcdir, distdir);
return { srcdir, distdir, rebuild };
});
const pub = !isWeb ? null : {
srcdir: path3.join(demo.dir, "public"),
distdir: demo.distdir,
rebuild: async () => {
await fse.copy(pub.srcdir, pub.distdir);
await Promise.all(injects.map((file) => injectFile(path3.join(pub.distdir, file), demo.info)));
}
};
const peersFile = path3.join(lib.dir, "peers.js");
return { port, lib, demo, pub, statics, peersFile, isWeb, mode, rebuildBuffer, log: logger(name, version, env) };
};
// src/tools/templates.js
var templates_default = {
html: `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="{{description}}" />
<title>{{name}} v{{version}} by {{author}}</title>
</head>
<body>
<div id="root"></div>
<script src="index.js"><\/script>
</body>
</html>`,
lib: `
import { info, log } from "@randajan/simple-lib/lib";
export default _=>log.bold.magenta("helloworld", JSON.stringify(info, null, 2));
`,
node: `
import { info, log } from "@randajan/simple-lib/node";
import dist from "../../dist/esm/index.mjs";
dist();
`,
web: `
import { info, log } from "@randajan/simple-lib/web";
import dist from "../../dist/esm/index.mjs";
dist();
`,
peers: `
import "@randajan/simple-lib/peers"
`
};
// src/index.js
import path4 from "path";
var index_default = async (isBuild, config = {}) => {
isBuild = typeof isBuild === "boolean" ? isBuild : argv_default.isBuild || false;
const { port, isWeb, mode, lib, demo, pub, statics, peersFile, rebuildBuffer, log } = parseConfig(isBuild, config);
const logbold = log.bold;
const logred = logbold.red;
if (!fs3.existsSync(peersFile)) {
await fs3.outputFile(peersFile, templates_default.peers);
}
if (!fs3.existsSync(lib.srcdir)) {
await fs3.outputFile(path4.join(lib.srcdir, "index.js"), templates_default.lib);
}
if (!fs3.existsSync(demo.srcdir)) {
await fs3.outputFile(path4.join(demo.srcdir, "index.js"), isWeb ? templates_default.web : templates_default.node);
}
if (pub && !fs3.existsSync(pub.srcdir)) {
await fs3.outputFile(path4.join(pub.srcdir, "index.html"), templates_default.html);
}
if (fs3.existsSync(lib.distdir)) {
await fs3.remove(lib.distdir);
}
if (fs3.existsSync(demo.distdir)) {
await fs3.remove(demo.distdir);
}
await pub?.rebuild();
await Promise.all(statics.map((s) => s.rebuild()));
await lib.rebuild();
await demo.rebuild();
if (isBuild) {
process.exit(0);
}
const rebuildDemo = async () => {
await demo.rebuild();
if (isWeb) {
return;
}
if (demo.current) {
demo.current.postMessage("shutdown");
}
demo.current = new Worker(("./" + demo.distdir + "/index.js").replaceAll("\\", "/"));
};
const rebuildLib = async (_) => {
await lib.rebuild();
await rebuildDemo();
};
const rebootOn = (name2, customLog, path5, exe, ignored) => {
const reboot = async (_) => {
const msg = name2 + " change";
const before = demo.current;
try {
await exe();
} catch (e) {
logred(msg, " failed");
log(e.stack);
return;
}
;
if (before) {
before.postMessage("refresh:" + name2);
}
customLog(msg + "d");
};
let timer;
watch(path5 + "/**/*", { ignoreInitial: true, ignored }).on("all", (...args) => {
clearTimeout(timer);
timer = setTimeout(reboot, rebuildBuffer);
});
};
const libIgnore = statics.map(({ srcdir, rebuild }) => {
rebootOn("Static", logbold.cyan, srcdir, async (_) => {
await rebuild();
rebuildDemo();
});
return srcdir;
});
logbold.inverse(`Started`);
await rebuildDemo();
rebootOn("Lib", logbold.blue, lib.srcdir, rebuildLib, libIgnore);
rebootOn("Demo", logbold.green, demo.srcdir, rebuildDemo, [pub?.srcdir]);
if (isWeb) {
rebootOn("Public", logbold.magenta, pub.srcdir, async (_) => {
await pub.rebuild();
rebuildDemo();
});
return server.start({
port,
root: demo.distdir,
open: true,
file: "index.html",
wait: 100,
logLevel: 0
});
} else {
["SIGTERM", "SIGINT", "SIGQUIT"].forEach((signal) => {
process.on(signal, (_) => {
demo.current.on("exit", (_2) => process.exit(0));
demo.current.postMessage("shutdown");
});
});
}
};
export {
argv_default as argv,
index_default as default,
root
};
//# sourceMappingURL=index.js.map