UNPKG

@randajan/simple-lib

Version:

Supersimple start for developing custom js library

384 lines (366 loc) 11.8 kB
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, legalComments, splitting, plugins, bundle, loader, format, jsx, info } = opt; let context; return async (_) => { if (!context) { context = await esbuild.context({ globalName, format, minify, legalComments, 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.legalComments = x.legalComments || c.legalComments || (x.minify ? "eof" : "inline"); 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