packages/bundles/scripts/build.ts (162 lines of code) (raw):

import * as path from 'path'; import { createRequire } from 'module'; import { fileURLToPath } from 'url'; import fs from 'fs-extra'; import ncc from '@vercel/ncc'; import chalk from 'chalk'; import * as dts from 'dts-bundle'; import glob from 'glob'; import findUp from 'find-up'; import tasks, { taskExternals } from './tasks'; const cwd = process.cwd(); // @NOTE: Make ncc work, due to loader recognize cwd as resolving working directory. process.cwd = () => path.join(cwd, '..'); const require = createRequire(import.meta.url); const __dirname = path.dirname(fileURLToPath(import.meta.url)); interface Options { pkgName?: string; rootDir?: string; target?: string; file?: string; externals?: Record<string, string>; minify?: boolean; declaration?: boolean; bundleName?: string; emptyDir?: boolean; skipCompile?: boolean; matchCopyFiles?: (data: { resolvePath: string; resolveId: string; }) => boolean; patch?: () => void; } export async function packDependency(options: Options): Promise<void> { const { pkgName, file, rootDir, target, externals, matchCopyFiles, patch, emptyDir = true, bundleName = 'index.js', minify = true, declaration = true, skipCompile } = options; console.log(chalk.green(`start pack ${pkgName || file}`)); const targetPath = path.join(rootDir, target); if (emptyDir) { fs.removeSync(targetPath); } const filesToCopy = []; const packEntry = file ? path.join(rootDir, file) : require.resolve(pkgName, { paths: [rootDir], }); fs.ensureDirSync(targetPath); if (!skipCompile) { const { code, assets } = await ncc(packEntry, { cache: false, externals, minify, target: 'es5', assetsBuilds: false, customEmit(filePath: string, opts: {id: string}) { const { id } = opts; if (matchCopyFiles && matchCopyFiles({ resolvePath: filePath, resolveId: id, })) { filesToCopy.push(require.resolve(filePath, { paths: [path.dirname(id)], })); return `'./${path.basename(filePath)}'`; } }, }); for (const assetKey of Object.keys(assets)) { const asset = assets[assetKey]; const data = asset.source; const fileTarget = path.join(targetPath, assetKey); fs.ensureDirSync(path.dirname(fileTarget)); fs.writeFileSync(fileTarget, data); } // copy files for (const fileToCopy of filesToCopy) { let content = fs.readFileSync(fileToCopy, 'utf-8'); for (const key of Object.keys(externals)) { content = content.replace( new RegExp(`require\\(['"]${key}['"]\\)`, 'gm'), `require('${externals[key]}')`, ); content = content.replace( new RegExp(`require\\(['"]${key}/package(.json)?['"]\\)`, 'gm'), `require('${externals[key]}/package.json')`, ); } const copyTarget = path.join(targetPath, path.basename(fileToCopy)); console.log(chalk.green(`fileToCopy ${copyTarget}`)); fs.writeFileSync( copyTarget, content, 'utf-8', ); } // write code to package const outfile = path.join(targetPath, bundleName); fs.ensureDirSync(path.dirname(outfile)); fs.writeFileSync(path.join(targetPath, bundleName), code, 'utf-8'); } if (pkgName) { const packageRoot = path.dirname( findUp.sync('package.json', { cwd: require.resolve(pkgName, { paths: [rootDir] }), })); // create license file const licensePath = path.join(packageRoot, 'LICENSE'); if (fs.existsSync(licensePath)) { console.log(chalk.green(`create LICENSE for ${pkgName || file}`)); fs.copyFileSync(licensePath, path.join(targetPath, 'LICENSE')); } // create package.json const pkgJson = fs.readJSONSync(path.join(packageRoot, 'package.json')); let dtsName = ''; if (declaration) { if (pkgJson.types) { dtsName = 'index.d.ts'; console.log(chalk.green(`bundle dts file for ${pkgName || file}`)); dts.bundle({ name: pkgJson.name, outputAsModuleFolder: true, out: path.join(targetPath, dtsName), main: path.join(packageRoot, pkgJson.types), headerPath: '', headerText: '', }); } else { try { const typesRoot = path.dirname(require.resolve(`@types/${pkgName}/package.json`, { paths: [rootDir], })); const typeJson = fs.readJSONSync(path.join(typesRoot, 'package.json')); dtsName = typeJson.types.endsWith('.d.ts') ? typeJson.types : `${typeJson.types}.d.ts`; // copy dts to package root const files = glob.sync('**/*.d.ts', { cwd: typesRoot, nodir: true }); console.log(chalk.green(`copy dts file for ${pkgName || file}`)); for (const file of files) { const from = path.join(typesRoot, file); const to = path.join(targetPath, file); await fs.mkdirp(path.dirname(to)); await fs.copyFile(from, to); } } catch (err) { console.log(chalk.yellow(`can not find dts file of ${pkgName}`)); } } } console.log(chalk.green(`create package.json for ${pkgName || file}`)); fs.writeJSONSync(path.join(targetPath, 'package.json'), { name: pkgJson.name, main: 'index.js', ...(dtsName ? { types: dtsName } : {}), ...(pkgJson.author ? { author: pkgJson.author } : {}), ...(pkgJson.license ? { license: pkgJson.license } : {}), }); } if (patch) { patch(); } } (async () => { for (let task of tasks) { await packDependency({ rootDir: path.join(__dirname, '..'), externals: taskExternals, target: `compiled/${task.pkgName}`, ...task, }); } })();