-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor build system for better CJS + ESM support, switch to esbuild…
… vs rollupjs. (#102) This PR migrates Pepr's build and bundling systems from RollupJS -> esbuild + tsc. It also unifies the `pepr dev` and `pepr build` code in addition to addressing issues with ESM imports. See the ADR for further details.
- Loading branch information
1 parent
2c10e7c
commit 87de7a8
Showing
45 changed files
with
843 additions
and
701 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# 3. Use CommonJS and ESBuild | ||
|
||
Date: 2023-05-22 | ||
|
||
## Status | ||
|
||
Accepted | ||
|
||
## Context | ||
|
||
As a Typescript-based project that is trying to create a Node.js Command Line Interface (CLI), a Node.js runtime component for Kubernetes (K8s), and a TypeScript (TS) Software Development Kit (SDK), there are some edge cases that we have encountered. The bottom line is CommonJS (CJS) and ECMA Script Modules (ESM) don't work well together in all cases. TS further complicates this by it's [odd stance](https://github.com/microsoft/TypeScript/issues/49083#issuecomment-1125503248) on making a pure import system. | ||
|
||
Producing a clean JS SDK and JS CLI for NodeJS out of TS project is well-documented and suited the initial Pepr needs well. However, there were limitations to this model. Specifically a key value of Pepr is the `pepr dev` experience that allows zero-config breakpoint inspection in VSCode. Without leaning on `ts-node`, we [ran into issues](https://github.com/defenseunicorns/pepr/pull/94) preserving this experience or not creating very odd offset behaviors between the TS source and the transpiled code in the debugger. This same code must also produce the smallest possible output for the runtime controller in a single file, the presented the second issue where `pepr dev` would work due to `ts-node` magic, but the bundled output would break on ESM imports. | ||
|
||
During the evaluation of alternative solutions, the codebase was [rewritten](https://github.com/defenseunicorns/pepr/pull/102/commits/80ed6c88d1b7789c318e04ca3adb98d40f1b46c5) to fully leverage ESM instead of CJS. Though this did solve some of the bundling issues, the DevX was very confusing due to the forced use of phantom `.js` files for imports in addition to odd behaviors with default imports. This made both developing and testing Pepr Modules confusing and frustrating. | ||
|
||
Other build systems were explored, including [esbuild](https://esbuild.github.io/) to replace RollupJS. | ||
|
||
## Decision | ||
|
||
The decision has been made to implement CommonJS (CJS) in combination with ESBuild and TypeScript (tsc) in the Pepr project. This decision has been made with the objective of sustaining efficient debugging and breakpoints, operational CLI, SDK publishing, and successful bundling. esbuild is also what [Typescript themselves](https://github.com/microsoft/TypeScript/pull/51387) chose to use in their module system modernization efforts. This change also allowed the unification of the `pepr dev` and `pepr build` process to use the same code and configurations reducing risk of bugs in prod not being caught in dev. | ||
|
||
## Consequences | ||
|
||
The adoption of CJS with ESBuild and tsc is expected to resolve the disruptions caused by the integration of ESM dynamic imports and bundled output. The integration of ESBuild's superior bundling capabilities with tsc for type-checking and typedef generation is expected to enhance the build process and the overall user experience. | ||
|
||
This decision does not introduce breaking changes in the existing system, highlighting its backward compatibility. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* eslint-disable no-undef */ | ||
|
||
import { analyzeMetafile, build } from "esbuild"; | ||
|
||
import packageJSON from "./package.json" assert { type: "json" }; | ||
|
||
const { dependencies, peerDependencies } = packageJSON; | ||
const external = Object.keys(dependencies).concat(Object.keys(peerDependencies)); | ||
|
||
const buildOpts = { | ||
bundle: true, | ||
external, | ||
format: "cjs", | ||
legalComments: "eof", | ||
metafile: true, | ||
platform: "node", | ||
}; | ||
|
||
async function builder() { | ||
try { | ||
// Build the CLI | ||
const cli = await build({ | ||
...buildOpts, | ||
entryPoints: ["src/cli.ts"], | ||
outfile: "dist/cli.js", | ||
}); | ||
|
||
console.log(await analyzeMetafile(cli.metafile)); | ||
|
||
// Build the controller runtime | ||
const controller = await build({ | ||
...buildOpts, | ||
entryPoints: ["src/cli/run.ts"], | ||
outfile: "dist/controller.js", | ||
}); | ||
|
||
console.log(await analyzeMetafile(controller.metafile)); | ||
|
||
// Build the library | ||
const lib = await build({ | ||
...buildOpts, | ||
entryPoints: ["src/lib.ts"], | ||
outfile: "dist/lib.js", | ||
sourcemap: true, | ||
}); | ||
|
||
console.log(await analyzeMetafile(lib.metafile)); | ||
} catch (e) { | ||
console.error(e); | ||
process.exit(1); | ||
} | ||
} | ||
|
||
builder(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.