UNPKG

bob-the-bundler

Version:
244 lines (243 loc) • 10.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.readPackageJson = exports.runifyCommand = exports.distDir = void 0; const tslib_1 = require("tslib"); const globby_1 = tslib_1.__importDefault(require("globby")); const fse = tslib_1.__importStar(require("fs-extra")); const p_limit_1 = tslib_1.__importDefault(require("p-limit")); const fs_extra_1 = tslib_1.__importDefault(require("fs-extra")); const dependency_graph_1 = require("dependency-graph"); const path_1 = require("path"); const ncc_1 = tslib_1.__importDefault(require("@vercel/ncc")); const tsup_1 = require("tsup"); const child_process_1 = require("child_process"); const command_1 = require("../command"); exports.distDir = "dist"; exports.runifyCommand = (0, command_1.createCommand)((api) => { const { reporter } = api; return { command: "runify", describe: "Runify", builder(yargs) { return yargs.options({ tag: { describe: "Run only for following tags", array: true, type: "string", }, }); }, async handler({ tag }) { const [rootPackageJSONPath] = await (0, globby_1.default)("package.json", { cwd: process.cwd(), absolute: true, }); const rootPackageJSON = await fse.readJSON(rootPackageJSONPath); const isSinglePackage = Array.isArray(rootPackageJSON.workspaces) === false; if (isSinglePackage) { return runify((0, path_1.join)(process.cwd(), "package.json"), reporter); } const limit = (0, p_limit_1.default)(1); const packageJsonFiles = await (0, globby_1.default)("packages/**/package.json", { cwd: process.cwd(), absolute: true, ignore: ["**/node_modules/**", `**/${exports.distDir}/**`], }); const packageJsons = await Promise.all(packageJsonFiles.map((packagePath) => fs_extra_1.default.readJSON(packagePath))); const depGraph = new dependency_graph_1.DepGraph(); packageJsons.forEach((pkg, i) => { var _a, _b; depGraph.addNode(pkg.name, { path: packageJsonFiles[i], tags: (_b = (_a = pkg.buildOptions) === null || _a === void 0 ? void 0 : _a.tags) !== null && _b !== void 0 ? _b : [], }); }); packageJsons.forEach((pkg) => { var _a, _b, _c; [ ...Object.keys((_a = pkg.dependencies) !== null && _a !== void 0 ? _a : {}), ...Object.keys((_b = pkg.peerDependencies) !== null && _b !== void 0 ? _b : {}), ...Object.keys((_c = pkg.devDependencies) !== null && _c !== void 0 ? _c : {}), ] .filter((dep) => depGraph.hasNode(dep)) .forEach((dep) => { depGraph.addDependency(pkg.name, dep); }); }); const ordered = depGraph.overallOrder(); await Promise.all(ordered.map((name) => { const data = depGraph.getNodeData(name); if (tag) { if (!data.tags.some((t) => tag.includes(t))) { return; } } return limit(() => runify(depGraph.getNodeData(name).path, reporter)); })); }, }; }); async function runify(packagePath, reporter) { var _a, _b, _c, _d, _e, _f; const cwd = packagePath.replace("/package.json", ""); const pkg = await readPackageJson(cwd); const buildOptions = pkg.buildOptions || {}; if (!buildOptions.runify) { return; } if (isNext(pkg)) { const additionalRequire = (_d = (_c = (_b = (_a = pkg === null || pkg === void 0 ? void 0 : pkg.buildOptions) === null || _a === void 0 ? void 0 : _a.runify) === null || _b === void 0 ? void 0 : _b.next) === null || _c === void 0 ? void 0 : _c.header) !== null && _d !== void 0 ? _d : null; await buildNext(cwd, additionalRequire); await rewritePackageJson(pkg, cwd, (newPkg) => ({ ...newPkg, dependencies: pkg.dependencies, type: "commonjs", })); } else { await compile(cwd, (_e = buildOptions.bin) !== null && _e !== void 0 ? _e : "src/index.ts", buildOptions, Object.keys((_f = pkg.dependencies) !== null && _f !== void 0 ? _f : {}), pkg.type === "module"); await rewritePackageJson(pkg, cwd); } reporter.success(`Built ${pkg.name}`); } async function readPackageJson(baseDir) { return JSON.parse(await fs_extra_1.default.readFile((0, path_1.resolve)(baseDir, "package.json"), { encoding: "utf-8", })); } exports.readPackageJson = readPackageJson; async function rewritePackageJson(pkg, cwd, modify) { let filename = "index.js"; // only tsup keep the file name if (pkg.buildOptions.bin && pkg.buildOptions.tsup) { const bits = pkg.buildOptions.bin.split("/"); const lastBit = bits[bits.length - 1]; filename = lastBit.replace(".ts", ".js"); } let newPkg = { bin: filename, }; const fields = [ "name", "version", "description", "publishConfig", "registry", "repository", "type", ]; fields.forEach((field) => { if (typeof pkg[field] !== "undefined") { newPkg[field] = pkg[field]; } }); if (modify) { newPkg = modify(newPkg); } await fs_extra_1.default.writeFile((0, path_1.join)(cwd, "dist/package.json"), JSON.stringify(newPkg, null, 2), { encoding: "utf-8", }); } function isNext(pkg) { var _a, _b; return ((_a = pkg === null || pkg === void 0 ? void 0 : pkg.dependencies) === null || _a === void 0 ? void 0 : _a.next) || ((_b = pkg === null || pkg === void 0 ? void 0 : pkg.devDependencies) === null || _b === void 0 ? void 0 : _b.next); } async function buildNext(cwd, additionalRequire) { await new Promise((resolve, reject) => { const child = (0, child_process_1.spawn)("next", ["build"], { stdio: "inherit", cwd, }); child.on("exit", (code) => (code ? reject(code) : resolve(code))); child.on("error", reject); }); await fs_extra_1.default.mkdirp((0, path_1.join)(cwd, "dist")); if (additionalRequire) { await (0, tsup_1.build)({ entryPoints: [(0, path_1.join)(cwd, additionalRequire)], outDir: (0, path_1.join)(cwd, "dist"), target: "node16", format: ["cjs"], splitting: false, skipNodeModulesBundle: true, }); } await Promise.all([ fs_extra_1.default.copy((0, path_1.join)(cwd, ".next"), (0, path_1.join)(cwd, "dist/.next"), { filter(src) { // copy without webpack cache (it's 900mb...) return src.includes("cache/webpack") === false; }, }), fs_extra_1.default.copy((0, path_1.join)(cwd, "public"), (0, path_1.join)(cwd, "dist/public")), fs_extra_1.default.writeFile((0, path_1.join)(cwd, "dist/index.js"), [ `#!/usr/bin/env node`, `process.on('SIGTERM', () => process.exit(0))`, `process.on('SIGINT', () => process.exit(0))`, additionalRequire ? `require('${additionalRequire.replace(".ts", "")}')` : ``, ` require('next/dist/server/lib/start-server').startServer({ dir: __dirname, hostname: '0.0.0.0', port: parseInt(process.env.PORT), conf: {}, }).then(async (app)=>{ const appUrl = 'http://' + app.hostname + ':' + app.port; console.log('started server on '+ app.hostname + ':' + app.port + ', url: ' + appUrl); await app.prepare(); }).catch((err)=>{ console.error(err); process.exit(1); }) `, ].join("\n")), ]); } async function compile(cwd, entryPoint, buildOptions, dependencies, useEsm = false) { if (buildOptions.tsup) { const out = (0, path_1.join)(cwd, "dist"); await (0, tsup_1.build)({ entryPoints: [(0, path_1.join)(cwd, entryPoint)], outDir: out, target: "node16", format: [useEsm ? "esm" : "cjs"], splitting: false, sourcemap: true, clean: true, shims: true, skipNodeModulesBundle: false, noExternal: dependencies, external: buildOptions.external, banner: buildOptions.banner ? { js: buildOptions.banner.includes(".js") || buildOptions.banner.includes(".mjs") ? await fs_extra_1.default.readFile((0, path_1.join)(cwd, buildOptions.banner), "utf-8") : buildOptions.banner, } : {}, }); return; } const { code, map, assets } = await (0, ncc_1.default)((0, path_1.join)(cwd, entryPoint), { cache: false, sourceMap: true, }); await fs_extra_1.default.mkdirp((0, path_1.join)(cwd, "dist")); await Promise.all([ fs_extra_1.default.writeFile((0, path_1.join)(cwd, "dist/index.js"), code, { encoding: "utf-8", }), fs_extra_1.default.writeFile((0, path_1.join)(cwd, "dist/index.js.map"), map, { encoding: "utf-8", }), ].concat(Object.keys(assets).map(async (filepath) => { if (filepath.endsWith("package.json")) { return Promise.resolve(); } await fs_extra_1.default.ensureDir((0, path_1.dirname)((0, path_1.join)(cwd, "dist", filepath)), {}); await fs_extra_1.default.writeFile((0, path_1.join)(cwd, "dist", filepath), assets[filepath].source); }))); }