diff --git a/action/commands/build.d.ts b/action/commands/build.d.ts index 588460a9..9d2c147b 100644 --- a/action/commands/build.d.ts +++ b/action/commands/build.d.ts @@ -1,7 +1,6 @@ -export declare const distDir = "dist"; +export declare const DIST_DIR = "dist"; export declare const buildCommand: import("../command").CommandFactory<{}, { single?: boolean | undefined; }>; -export declare function readPackageJson(baseDir: string): Promise; export declare function validatePackageJson(pkg: any): void; //# sourceMappingURL=build.d.ts.map \ No newline at end of file diff --git a/action/config.d.ts b/action/config.d.ts index 095e859b..e48026a6 100644 --- a/action/config.d.ts +++ b/action/config.d.ts @@ -14,6 +14,10 @@ export interface BobConfig { commands?: { [cmdName: string]: Command; }; + dists?: { + distDir: string; + distPath?: string; + }[]; } interface UseConfigOptions { config?: string; diff --git a/package.json b/package.json index 280f5db4..0831a270 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "yargs": "15.3.1" }, "scripts": { + "prepublish": "yarn build", "build": "tsc && ncc build src/action.ts -o action" }, "devDependencies": { diff --git a/src/commands/build.ts b/src/commands/build.ts index fa786e63..25a9939e 100644 --- a/src/commands/build.ts +++ b/src/commands/build.ts @@ -20,7 +20,14 @@ interface BuildOptions { bin?: Record; } -export const distDir = "dist"; +export const DIST_DIR = "dist"; + +interface PackageInfo { + packagePath: string; + cwd: string; + pkg: any; + fullName: string; +} export const buildCommand = createCommand< {}, @@ -42,8 +49,14 @@ export const buildCommand = createCommand< }); }, async handler(args) { + config.dists = config.dists || [ + { + distDir: DIST_DIR, + distPath: '' + } + ]; if (args.single) { - await buildSingle(); + await buildSingle({ distDir: DIST_DIR }); return; } @@ -51,22 +64,33 @@ export const buildCommand = createCommand< const packages = await globby("packages/**/package.json", { cwd: process.cwd(), absolute: true, - ignore: ["**/node_modules/**", `**/${distDir}/**`], + ignore: ["**/node_modules/**", ...config.dists.map(({ distDir }) => `**/${distDir}/**`)], }); - await Promise.all( - packages.map((packagePath) => - limit(() => build(packagePath, config, reporter)) - ) + const packageInfoList: PackageInfo[] = await Promise.all( + packages.map(packagePath => limit(async () => { + const cwd = packagePath.replace("/package.json", ""); + const pkg = await fs.readJSON(resolve(cwd, 'package.json')); + const fullName: string = pkg.name; + return { packagePath, cwd, pkg, fullName }; + })) ); + + for (const { distDir, distPath } of config.dists) { + await Promise.all( + packageInfoList.map(({ packagePath, cwd, pkg, fullName }) => + limit(() => build({ packagePath, cwd, pkg, fullName, config, reporter, distDir, distPath, packageInfoList })) + ) + ); + } }, }; }); -async function buildSingle() { +async function buildSingle({ distDir, distPath = '' }: { distDir: string; distPath?: string; }) { const cwd = process.cwd(); const packagePath = join(process.cwd(), "package.json"); - const pkg = await readPackageJson(cwd); + const pkg = await fs.readJSON(packagePath); validatePackageJson(pkg); @@ -87,7 +111,7 @@ async function buildSingle() { }), typescript(), generatePackageJson({ - baseContents: rewritePackageJson(pkg), + baseContents: rewritePackageJson(pkg, distPath), additionalDependencies: Object.keys(pkg.dependencies || {}), }), ], @@ -108,24 +132,16 @@ async function buildSingle() { const generates = [ { ...commonOutputOptions, - file: join(distDir, "index.cjs.js"), + file: join(distDir, "index.js"), format: "cjs" as const, }, { ...commonOutputOptions, - file: join(distDir, "index.esm.js"), + file: join(distDir, "index.mjs"), format: "esm" as const, }, ]; - if (pkg.exports) { - generates.push({ - ...commonOutputOptions, - file: join(distDir, "index.mjs"), - format: "esm" as const, - }); - } - await Promise.all( generates.map(async (outputOptions) => { await bundle.write(outputOptions); @@ -135,26 +151,22 @@ async function buildSingle() { // move README.md and LICENSE await copyToDist( cwd, - ["README.md", "LICENSE"].concat(buildOptions?.copy || []) + ["README.md", "LICENSE"].concat(buildOptions?.copy || []), + DIST_DIR + distPath ); } async function build( - packagePath: string, - config: BobConfig, - reporter: Consola +{ packagePath, cwd, pkg, fullName, config, reporter, distDir, distPath = '', packageInfoList }: { packagePath: string; cwd: string; pkg: any; fullName: string; config: BobConfig; reporter: Consola; distDir: string; distPath?: string; packageInfoList: PackageInfo[] }, ) { const scope = config.scope; - const cwd = packagePath.replace("/package.json", ""); - const pkg = await readPackageJson(cwd); - const fullName: string = pkg.name; if ((config.ignore || []).includes(fullName)) { reporter.warn(`Ignored ${fullName}`); return; } - const name = fullName.replace(`${scope}/`, ""); + const name = fullName.replace(`${scope}/`, distPath); validatePackageJson(pkg); @@ -184,7 +196,7 @@ async function build( packageJSONPath: packagePath, }), generatePackageJson({ - baseContents: rewritePackageJson(pkg), + baseContents: rewritePackageJson(pkg, distPath), additionalDependencies: Object.keys(pkg.dependencies || {}), }), ], @@ -205,24 +217,16 @@ async function build( const generates = [ { ...commonOutputOptions, - file: join(bobProjectDir, "index.cjs.js"), + file: join(bobProjectDir, "index.js"), format: "cjs" as const, }, { ...commonOutputOptions, - file: join(bobProjectDir, "index.esm.js"), + file: join(bobProjectDir, "index.mjs"), format: "esm" as const, }, ]; - if (pkg.exports) { - generates.push({ - ...commonOutputOptions, - file: join(distDir, "index.mjs"), - format: "esm" as const, - }); - } - const declarations = await globby("**/*.d.ts", { cwd: distProjectSrcDir, ignore: ["**/node_modules/**"], @@ -269,7 +273,7 @@ async function build( banner: `#!/usr/bin/env node`, preferConst: true, sourcemap: options.sourcemap, - file: join(bobProjectDir, pkg.bin[alias].replace(`${distDir}/`, "")), + file: join(bobProjectDir, pkg.bin[alias].replace(`${DIST_DIR}/`, "")), format: "cjs", }); }) @@ -277,29 +281,37 @@ async function build( } // remove /dist - await fs.remove(join(cwd, distDir)); + await fs.remove(join(cwd, DIST_DIR + distPath)); + + // fix distPath import in extra dists + function replaceAll(str: string, from: string, to: string) { + return str.split(from).join(to); + } + if (distPath) { + await Promise.all( + generates.map(({ file }) => limit(async () => { + let content = await fs.readFile(file, 'utf8'); + for (const { fullName } of packageInfoList) { + content = replaceAll(content, `'${fullName}'`, `'${fullName}${distPath}'`); + } + await fs.writeFile(file, content, { encoding: 'utf8', flag: 'w' }); + })) + ) + } + // move bob/ to /dist - await fs.move(bobProjectDir, join(cwd, distDir)); + await fs.move(bobProjectDir, join(cwd, DIST_DIR + distPath)); // move README.md and LICENSE await copyToDist( cwd, - ["README.md", "LICENSE"].concat(pkg.buildOptions?.copy || []) + ["README.md", "LICENSE"].concat(pkg.buildOptions?.copy || []), + DIST_DIR + distPath ); reporter.success(`Built ${pkg.name}`); } -// - -export async function readPackageJson(baseDir: string) { - return JSON.parse( - await fs.readFile(resolve(baseDir, "package.json"), { - encoding: "utf-8", - }) - ); -} - -function rewritePackageJson(pkg: Record) { +function rewritePackageJson(pkg: Record, distPath: string) { const newPkg: Record = {}; const fields = [ "name", @@ -323,18 +335,30 @@ function rewritePackageJson(pkg: Record) { } }); - newPkg.main = "index.cjs.js"; - newPkg.module = "index.esm.js"; + newPkg.name += distPath; + newPkg.main = "index.js"; + newPkg.module = "index.mjs"; newPkg.typings = "index.d.ts"; newPkg.typescript = { definition: newPkg.typings, }; + newPkg.exports = { + ".": { + require: "./index.js", + import: "./index.mjs", + }, + "./*": { + require: "./*.js", + import: "./*.mjs", + }, + }; + if (pkg.bin) { newPkg.bin = {}; for (const alias in pkg.bin) { - newPkg.bin[alias] = pkg.bin[alias].replace(`${distDir}/`, ""); + newPkg.bin[alias] = pkg.bin[alias].replace(`${DIST_DIR}/`, ""); } } @@ -352,18 +376,19 @@ export function validatePackageJson(pkg: any) { } } - expect("main", `${distDir}/index.cjs.js`); - expect("module", `${distDir}/index.esm.js`); - expect("typings", `${distDir}/index.d.ts`); - expect("typescript.definition", `${distDir}/index.d.ts`); + expect("main", `${DIST_DIR}/index.js`); + expect("module", `${DIST_DIR}/index.mjs`); + expect("typings", `${DIST_DIR}/index.d.ts`); + expect("typescript.definition", `${DIST_DIR}/index.d.ts`); - if (pkg.exports) { - expect("exports.require", `./${pkg.main}`); - expect("exports.default", `./${distDir}/index.mjs`); - } + expect("exports['.'].require", `./${DIST_DIR}/index.js`); + expect("exports['.'].import", `./${DIST_DIR}/index.mjs`); + + expect("exports['./*'].require", `./${DIST_DIR}/*.js`); + expect("exports['./*'].import", `./${DIST_DIR}/*.mjs`); } -async function copyToDist(cwd: string, files: string[]) { +async function copyToDist(cwd: string, files: string[], distDir: string) { const allFiles = await globby(files, { cwd }); return Promise.all( diff --git a/src/commands/pack-flat.ts b/src/commands/pack-flat.ts index 4eebd5f3..51e4b7c6 100644 --- a/src/commands/pack-flat.ts +++ b/src/commands/pack-flat.ts @@ -1,6 +1,6 @@ import globby from "globby"; import pLimit from "p-limit"; -import fs from "fs-extra"; +import fs, { readJSON } from "fs-extra"; import { resolve, join } from "path"; import { execSync } from "child_process"; import { Consola } from "consola"; @@ -8,7 +8,7 @@ import { paramCase } from "param-case"; import { createCommand } from "../command"; import { BobConfig } from "../config"; -import { readPackageJson, distDir } from "./build"; +import { DIST_DIR } from "./build"; export const packFlatCommand = createCommand< {}, @@ -36,7 +36,7 @@ export const packFlatCommand = createCommand< const packages = await globby("packages/**/package.json", { cwd: process.cwd(), absolute: true, - ignore: ["**/node_modules/**", `**/${distDir}/**`], + ignore: ["**/node_modules/**", `**/${DIST_DIR}/**`], }); await Promise.all( @@ -50,7 +50,7 @@ export const packFlatCommand = createCommand< async function pack(packagePath: string, commit: string, config: BobConfig, reporter: Consola) { const cwd = packagePath.replace("/package.json", ""); - const pkg = await readPackageJson(cwd); + const pkg = await readJSON(packagePath); const fullName: string = pkg.name; if ((config.ignore || []).includes(fullName)) { @@ -58,11 +58,11 @@ async function pack(packagePath: string, commit: string, config: BobConfig, repo return; } - const projectDistDir = join(cwd, distDir); + const projectDistDir = join(cwd, DIST_DIR); const bobDir = resolve(process.cwd(), ".bob-packed"); // replace version to 0.0.0-canary-${commit} - const distPkg = await readPackageJson(projectDistDir); + const distPkg = await readJSON(join(projectDistDir, 'package.json')); const version = `0.0.0-canary-${commit}`; distPkg.version = version; await fs.writeFile(join(projectDistDir, 'package.json'), JSON.stringify(distPkg, null, 2), { diff --git a/src/commands/validate.ts b/src/commands/validate.ts index 365d0efc..51dc9c97 100644 --- a/src/commands/validate.ts +++ b/src/commands/validate.ts @@ -163,14 +163,14 @@ export async function validatePackage({ shouldEqual( pkg.main, - "dist/index.cjs.js", - `${name}: 'main' should equal 'dist/index.cjs.js'`, + "dist/index.js", + `${name}: 'main' should equal 'dist/index.js'`, onError ); shouldEqual( pkg.module, - "dist/index.esm.js", - `${name}: 'module' should equal 'dist/index.esm.js'`, + "dist/index.msj", + `${name}: 'module' should equal 'dist/index.msj'`, onError ); shouldEqual( @@ -185,6 +185,33 @@ export async function validatePackage({ `${name}: 'typescript.definition' should equal 'dist/index.d.ts'`, onError ); + + shouldEqual( + pkg.exports?.['.']?.require, + "./dist/index.js", + `${name}: 'exports.['.'].require' should equal './dist/index.js'`, + onError + ); + shouldEqual( + pkg.exports?.['.']?.import, + "./dist/index.mjs", + `${name}: 'exports.['.'].import' should equal './dist/index.mjs'`, + onError + ); + + shouldEqual( + pkg.exports?.['./*']?.require, + "./dist/*.js", + `${name}: 'exports.['./*'].import' should equal './dist/*.js'`, + onError + ); + shouldEqual( + pkg.exports?.['./*']?.import, + "./dist/*.mjs", + `${name}: 'exports.['./*'].import' should equal './dist/*.mjs'`, + onError + ); + shouldEqual( pkg.scripts?.prepack, "bob prepack", diff --git a/src/config.ts b/src/config.ts index 17ffc3ef..bccce9f5 100644 --- a/src/config.ts +++ b/src/config.ts @@ -19,6 +19,10 @@ export interface BobConfig { commands?: { [cmdName: string]: Command; }; + dists?: { + distDir: string; + distPath?: string; + }[] } interface UseConfigOptions {