build-packages.mjs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #!/usr/bin/env node
  2. /* eslint-disable unicorn/prefer-top-level-await */
  3. import { build } from 'esbuild';
  4. import glob from 'fast-glob';
  5. import childProcess from 'node:child_process';
  6. import fs from 'node:fs/promises';
  7. import path from 'node:path';
  8. import { fileURLToPath } from 'node:url';
  9. import { promisify } from 'node:util';
  10. // if this script is moved, this will need to be adjusted
  11. const exec = promisify(childProcess.exec);
  12. const rootDir = path.dirname(fileURLToPath(import.meta.url));
  13. const packages = await fs.readdir(`${rootDir}/packages`);
  14. const packageName = process.argv[2];
  15. if (!packageName || !packages.includes(packageName)) {
  16. console.error(
  17. `Please specify the name of the package to build: node build-packages.mjs <package-name> (one of ${packages.join(', ')})`,
  18. );
  19. process.exit(1);
  20. }
  21. console.info(`Compiling package ${packageName}`);
  22. const packageDir = `${rootDir}/packages/${packageName}`;
  23. const sourceDir = path.join(packageDir, 'src');
  24. const libDir = path.join(packageDir, 'lib');
  25. const [sourceFiles] = await Promise.all([
  26. // Find all .js and .ts files from /src.
  27. glob(`${glob.convertPathToPattern(sourceDir)}/**/*.{mjs,cjs,js,mts,cts,ts}`, {
  28. onlyFiles: true,
  29. absolute: false,
  30. }),
  31. // Delete /lib for a full rebuild.
  32. rmDir(libDir),
  33. ]);
  34. const filesToCompile = [];
  35. const filesToCopyToLib = [];
  36. for (const file of sourceFiles) {
  37. // mjs files cannot be built as they would be compiled to commonjs
  38. if (file.endsWith('.mjs') || file.endsWith('.d.ts')) {
  39. filesToCopyToLib.push(file);
  40. } else {
  41. filesToCompile.push(file);
  42. }
  43. }
  44. await Promise.all([
  45. copyFiles(filesToCopyToLib, sourceDir, libDir),
  46. build({
  47. // Adds source mapping
  48. sourcemap: true,
  49. // The compiled code should be usable in node v18
  50. target: 'node18',
  51. // The source code's format is commonjs.
  52. format: 'cjs',
  53. outdir: libDir,
  54. entryPoints: filesToCompile.map(file => path.resolve(file)),
  55. }),
  56. exec('tsc --emitDeclarationOnly', {
  57. env: {
  58. // binaries installed from modules have symlinks in
  59. // <pkg root>/node_modules/.bin.
  60. PATH: `${process.env.PATH || ''}:${path.join(rootDir, 'node_modules/.bin')}`,
  61. },
  62. cwd: packageDir,
  63. }),
  64. ]);
  65. const indexFiles = await glob(`${glob.convertPathToPattern(libDir)}/**/index.d.ts`, {
  66. onlyFiles: true,
  67. absolute: false,
  68. });
  69. // copy .d.ts files to .d.mts to provide typings for the ESM entrypoint
  70. await Promise.all(
  71. indexFiles.map(async indexFile => {
  72. await fs.copyFile(indexFile, indexFile.replace(/.d.ts$/, '.d.mts'));
  73. }),
  74. );
  75. async function rmDir(dirName) {
  76. try {
  77. await fs.stat(dirName);
  78. await fs.rm(dirName, { recursive: true });
  79. } catch {
  80. /* no-op */
  81. }
  82. }
  83. async function copyFiles(files, fromFolder, toFolder) {
  84. await Promise.all(
  85. files.map(async file => {
  86. const to = path.join(toFolder, path.relative(fromFolder, file));
  87. const dir = path.dirname(to);
  88. await fs.mkdir(dir, { recursive: true });
  89. await fs.copyFile(file, to);
  90. }),
  91. );
  92. }