UNPKG

beesbuild

Version:

构建工具链

239 lines (238 loc) 8.97 kB
import path from "path"; import chalk from "chalk-unified"; import { consola, getBuildConfig, handleManifest, parseManifest, pathExtra } from "@beesbuild/utils"; import fs, { existsSync, mkdirSync, writeFileSync } from "fs-extra"; import jiti from "jiti"; import { resolveModuleExportNames } from "mlly"; import { fromPairs } from "lodash-unified"; import * as prettier from "prettier"; import { resolveAliases } from "../utils.mjs"; import { DEFAULT_EXTENSIONS } from "../variables.mjs"; import { getShebang, makeExecutable } from "./plugins/shebang.mjs"; import { createTypesProject } from "./untyped.mjs"; function tryResolve(id, rootDir = process.cwd()) { const _require = jiti(rootDir, { interopDefault: true, esmResolve: true }); try { return _require.resolve(id); } catch (error) { if (error.code !== "MODULE_NOT_FOUND") { consola.error(`Error trying import ${id} from ${rootDir}`, error); } return id; } } const stubBuild = async (module, ctx) => { const rootDir = ctx.options.rootDir; const outDir = ctx.options.outDir || "."; const entryFile = ctx.options.entries.find( ({ isEntry }) => isEntry ); let entryFilepath = (entryFile == null ? void 0 : entryFile.input) ? path.resolve(rootDir, entryFile.input) : path.resolve(rootDir, "src"); const buildConfig = fromPairs( getBuildConfig({ rootDir, outDir, manifest: ctx.pkg, rollup: { emitCJS: true, emitDts: true, emitUmd: true }, entryFile: entryFile == null ? void 0 : entryFile.input }) ); const { output, ext } = buildConfig[module]; const dir = path.resolve(output.path, `index.${ext}`); if (existsSync(dir)) return; const info = parseManifest(entryFilepath); entryFilepath = path.join(info.dir, info.name); const d = path.relative(path.dirname(dir), entryFilepath); const ddir = pathExtra.join(d.startsWith(".") ? d : `./${d}`); consola.info(`\u3010Start:d\u3011for stub types file: ${d} generated`); consola.info(`\u3010Start:dir\u3011for stub types file: ${buildConfig.dts.output.name} generated`); consola.info(`\u3010Start:ddir\u3011for stub types file: ${ddir} generated`); const code = []; switch (module) { case "cjs": code.push(`module.exports = require('${ddir}');`); break; default: code.push(`export * from '${ddir}';`, `export { default } from '${ddir}';`); break; } const codeStr = await prettier.format(code.join("\n"), { parser: "typescript", singleQuote: true }); consola.success(chalk.cyan(`\u3010End\u3011for stub types file: ${dir} generated`)); if (!existsSync(path.dirname(dir))) { mkdirSync(path.dirname(dir), { recursive: true }); } writeFileSync(dir, codeStr, "utf8"); return Promise.resolve(); }; const runBrowserRollupStub = async (modules, ctx) => { if (modules.includes("dts")) { let typesProject = ctx.caches[ctx.uid]["typesProject"]; if (!typesProject) { typesProject = createTypesProject(ctx); ctx.caches[ctx.uid]["typesProject"] = typesProject; const sourceFiles = typesProject.addSourceFiles(); consola.warn(sourceFiles.length, "sourceFiles"); } typesProject.typeCheck(true); } return Promise.allSettled(modules.map((module) => stubBuild(module, ctx))); }; const rollupStub = async (ctx) => { var _a, _b; if (((_a = ctx.options) == null ? void 0 : _a.runEnv) === "Browser") { return runBrowserRollupStub(["esm", "cjs", "dts"], ctx); } const rootDir = ctx.options.rootDir; const serializedJitiOptions = (_dirname) => { const JitiOptions = { ...ctx.options.stubOptions.jiti, alias: { ...resolveAliases(ctx), ...ctx.options.stubOptions.jiti.alias } }; for (const [key, p] of Object.entries(JitiOptions.alias)) { const pp = path.join(_dirname, path.relative(rootDir, p)); JitiOptions.alias[key] = `${pp}/`; } return JSON.stringify(JitiOptions, null, 2); }; const { esm, cjs, dts } = handleManifest(ctx.pkg, ctx.options.rootDir); const entries = ctx.options.entries.filter( (entry) => entry.builder === "rollup" && entry.isEntry ); for (const option of entries) { const { input, name } = option; const outDir = path.join(ctx.options.outDir, name != null ? name : "dist"); const output = path.resolve(rootDir, outDir); const resolvedEntry = path.normalize(tryResolve(input, rootDir) || input); const resolvedEntryWithoutExt = resolvedEntry.slice( 0, Math.max(0, resolvedEntry.length - path.extname(resolvedEntry).length) ); const code = await fs.readFile(resolvedEntry, "utf8"); const shebang = getShebang(code); let dirname = path.dirname(output); await fs.mkdir(dirname, { recursive: true }); const rollup = ctx.options.rollup; let cjsOutput = `${output}.${cjs.ext}`; if (rollup.emitCJS) { if (ctx.pkg.main) { const dir = path.dirname(path.resolve(ctx.options.rootDir, cjs.fullPath)); if (dir !== dirname) { dirname = dir; await fs.mkdir(dirname, { recursive: true }); } cjsOutput = path.resolve(ctx.options.rootDir, cjs.fullPath); } const _dirname2 = path.relative(path.dirname(cjsOutput), rootDir); const cjsPath = path.join(_dirname2, path.relative(rootDir, input)); const code2 = [ shebang, `const jiti = require('jiti');`, `const path = require('node:path');`, `const cjsPath = path.resolve(__dirname, '${cjsPath}')`, "", `/** @type { import('${cjsPath}') } */`, `const _module = jiti(null, ${serializedJitiOptions(_dirname2)})(cjsPath);`, "", "module.exports = _module;", "" ].join("\n"); await fs.writeFile(cjsOutput, code2); } const namedExports = await resolveModuleExportNames(resolvedEntry, { extensions: DEFAULT_EXTENSIONS }).catch((error) => { consola.warn(ctx, `Cannot analyze ${resolvedEntry} for exports:${error}`); return []; }); const hasDefaultExport = namedExports.includes("default") || namedExports.length === 0; let esmOutput = `${output}.${esm.ext}`; if (ctx.pkg.module) { const dir = path.dirname(path.resolve(ctx.options.rootDir, esm.fullPath)); if (dir !== dirname) { dirname = dir; await fs.mkdir(dirname, { recursive: true }); } esmOutput = path.resolve(ctx.options.rootDir, esm.fullPath); } if (((_b = ctx.argv) == null ? void 0 : _b.runEnv) === "Browser") { const code2 = [ shebang, `/** @type {import(${JSON.stringify(resolvedEntryWithoutExt)})} */`, `export * from ${JSON.stringify(resolvedEntry)};`, "", `/** @type {import(${JSON.stringify(resolvedEntryWithoutExt)})} */`, `import * as _module from ${JSON.stringify(resolvedEntry)};`, hasDefaultExport ? "\nexport default _module;" : "", ...namedExports.filter((name2) => name2 !== "default").map((name2) => `export const ${name2} = _module.${name2};`), "" ].join("\n"); await fs.writeFile(esmOutput, code2); } else { const _dirname2 = path.relative(path.dirname(esmOutput), rootDir); const esmPath = path.join(_dirname2, path.relative(rootDir, input)); const code2 = [ shebang, `import jiti from 'jiti';`, `import path from 'node:path';`, "", `const pathname = new URL(".", import.meta.url).pathname;`, `const mjsPath = path.resolve(pathname, '${esmPath}');`, `/** @type {import(${JSON.stringify(esmPath)})} */`, `const _module = jiti(null, ${serializedJitiOptions(_dirname2)})(mjsPath);`, "", hasDefaultExport ? "export default _module;" : "", "", ...namedExports.filter((name2) => name2 !== "default").map((name2) => `export const ${name2} = _module.${name2};`), "" ].join("\n"); await fs.writeFile(esmOutput, code2); } let dtsOutput = `${output}.d.ts`; if (ctx.pkg.typings || ctx.pkg.types) { const dir = path.dirname(path.resolve(ctx.options.rootDir, dts.fullPath)); if (dir !== dirname) { dirname = dir; await fs.mkdir(dirname, { recursive: true }); } dtsOutput = path.resolve(ctx.options.rootDir, dts.fullPath); } const _dirname = path.relative(path.dirname(dtsOutput), rootDir); const typesPath = path.join(_dirname, path.relative(rootDir, input)); const dtsCode = [ `export * from '${typesPath}';`, hasDefaultExport ? `export { default } from '${typesPath}';` : "", "" ].join("\n"); await fs.writeFile(dtsOutput, dtsCode); if (shebang) { await makeExecutable(cjsOutput); await makeExecutable(esmOutput); } } await ctx.hooks.callHook("rollup:done", ctx); return; }; export { rollupStub, runBrowserRollupStub, stubBuild, tryResolve };