-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
build: use esbuild to bundle server code
A problem was that in production mode (compiled to ESM JS and running with `node`), importing internal packages (`@serieslist/*`) pointed to the TypeScript files. This meant that importing those packages DID NOT WORK (e.g., `@serieslist/logger`). `tsc` does not bundle any dependencies. To fix this, we can bundle the code while building, bundling the `@serieslist/*` packages INTO the `dist/` folder and marking all other direct dependencies as external. This means that we can keep `package.json` `main` and `exports` fields referencing the TypeScript files. I'm not super happy with the bundling, though, as there are some weird things going on with ESM. I considered these options for the bundler: - `esbuild` - Vite with `vite-node` might be nice as we're already using Vitest - `swc` - `webpack` The packages themselves are never built on their own. In order to build a package, one of the consuming apps needs to be built and pull the package code into the apps dist folder. This seems to be the approach that's mostly recommended for smaller and medium sized projects. Some more resources: - https://turbo.build/repo/docs/handbook/sharing-code/internal-packages - https://turbo.build/blog/you-might-not-need-typescript-project-references - https://www.reddit.com/r/typescript/comments/10ebgbs/handling_typescript_in_a_monorepo/ - https://nx.dev/concepts/more-concepts/incremental-builds I also tried to build the packages themselves and point `main` and `exports` to the compiled JS files in `dist/`, but that caused a couple issues like Go To Definition going to the type definition in `dist/`, not to the source code (which is super inconvenient). It would also mean that each package needs its own build step with configuration, which would be a bit more painful to set up. Related to #83
- Loading branch information
1 parent
d6f42b9
commit 6f25b13
Showing
13 changed files
with
258 additions
and
128 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { buildEsbuild } from '@serieslist/esbuild' | ||
|
||
import pkg from '../package.json' | ||
|
||
await buildEsbuild({ | ||
packageJson: pkg, | ||
entryPoints: ['src/main.ts'], | ||
tsconfig: 'tsconfig.build.json', | ||
external: ['pg-native'], | ||
}) |
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,10 @@ | ||
import { buildEsbuild } from '@serieslist/esbuild' | ||
|
||
import pkg from '../package.json' | ||
|
||
await buildEsbuild({ | ||
packageJson: pkg, | ||
entryPoints: ['src/server/server.ts'], | ||
outdir: 'dist/prodServer', | ||
tsconfig: 'tsconfig.server.json', | ||
}) |
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 |
---|---|---|
@@ -1,10 +1,7 @@ | ||
// https://stackoverflow.com/questions/46745014/alternative-for-dirname-in-node-when-using-the-experimental-modules-flag/50052194#50052194 | ||
|
||
import { dirname } from 'path' | ||
import { dirname, join } from 'path' | ||
import { fileURLToPath } from 'url' | ||
|
||
const __dirname = dirname(fileURLToPath(import.meta.url)) | ||
export const root = | ||
process.env.NODE_ENV === 'production' | ||
? `${__dirname}/../../..` | ||
: `${__dirname}/../..` | ||
export const root = join(__dirname, '..', '..') |
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,4 @@ | ||
{ | ||
"extends": "@serieslist/eslint-config-base", | ||
"root": true | ||
} |
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 @@ | ||
"@serieslist/prettier-config" |
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,19 @@ | ||
{ | ||
"name": "@serieslist/esbuild", | ||
"version": "1.0.0", | ||
"type": "module", | ||
"main": "./src/index.ts", | ||
"types": "./src/index.ts", | ||
"exports": { | ||
".": { | ||
"import": "./src/index.ts", | ||
"types": "./src/index.ts" | ||
} | ||
}, | ||
"devDependencies": { | ||
"@serieslist/eslint-config-base": "workspace:*", | ||
"@serieslist/prettier-config": "workspace:*", | ||
"@serieslist/typescript-config-base": "workspace:*", | ||
"esbuild": "^0.19.11" | ||
} | ||
} |
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,51 @@ | ||
import { type BuildOptions, build } from 'esbuild' | ||
|
||
type EsbuildOptions = BuildOptions & { | ||
/** | ||
* Whole package.json file, import with | ||
* ```typescript | ||
* import packageJson from './package.json' | ||
* ``` | ||
*/ | ||
packageJson: { | ||
dependencies: Record<string, string> | ||
devDependencies: Record<string, string> | ||
} | ||
} | ||
|
||
/** | ||
* Build options for compiling TypeScript for Node with esbuild. | ||
*/ | ||
const buildEsbuildConfig = ({ | ||
packageJson, | ||
...options | ||
}: EsbuildOptions): BuildOptions => { | ||
const { external = [], ...optionsWithoutExternal } = options | ||
|
||
const packages = Object.keys(packageJson.dependencies) | ||
.concat(Object.keys(packageJson.devDependencies)) | ||
.filter((name) => !name.startsWith('@serieslist')) | ||
|
||
return { | ||
outdir: 'dist', | ||
platform: 'node', | ||
target: 'esnext', | ||
format: 'esm', | ||
bundle: true, | ||
tsconfig: 'tsconfig.json', | ||
external: [...packages, ...external], | ||
banner: { | ||
// require does not exist in ESM, but some packages that are using require | ||
// are bundled into `dist/` and esbuild does not convert requires to | ||
// imports. This snippets creates a new `require` function that's used in | ||
// the bundle. | ||
// https://github.com/evanw/esbuild/issues/1921#issuecomment-1152991694 | ||
js: "import { createRequire } from 'module'; const require = createRequire(import.meta.url);", | ||
}, | ||
...optionsWithoutExternal, | ||
} | ||
} | ||
|
||
export const buildEsbuild = async (options: EsbuildOptions) => { | ||
return await build(buildEsbuildConfig(options)) | ||
} |
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 @@ | ||
export * from './esbuild' |
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,3 @@ | ||
{ | ||
"extends": "@serieslist/typescript-config-base" | ||
} |
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.