Skip to content

Commit e30beb7

Browse files
authored
Add support + docs for custom esbuild plugins (#1270)
* Add support + docs for custom esbuild plugins * Fixed the missing subpath export * Add support for specifying the prisma client generator * Add `—env-file` support to dev and deploy
1 parent 99a63d4 commit e30beb7

File tree

17 files changed

+1048
-78
lines changed

17 files changed

+1048
-78
lines changed

.changeset/rotten-eggs-occur.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@trigger.dev/build": patch
3+
"@trigger.dev/core": patch
4+
---
5+
6+
Added support for custom esbuild plugins

docs/guides/new-build-system-preview.mdx

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ If you've added the `trigger.dev` CLI to your `devDependencies`, then you should
3939

4040
Once you do that make sure you re-install your dependencies using `npm i` or the equivalent with your preferred package manager.
4141

42+
<Note>If you deploy using GitHub actions, make sure you update the version there too.</Note>
43+
4244
## Update your `trigger.config.ts`
4345

4446
The new build system does not effect your trigger task files at all, so those can remain unchanged. However, you may need to make changes to your `trigger.config.ts` file.
@@ -229,6 +231,49 @@ export default defineConfig({
229231
});
230232
```
231233

234+
If you have multiple `generator` statements defined in your schema file, you can pass in the `clientGenerator` option to specify the `prisma-client-js` generator, which will prevent other generators from being generated:
235+
236+
<CodeGroup>
237+
238+
```prisma schema.prisma
239+
datasource db {
240+
provider = "postgresql"
241+
url = env("DATABASE_URL")
242+
directUrl = env("DATABASE_URL_UNPOOLED")
243+
}
244+
245+
// We only want to generate the prisma-client-js generator
246+
generator client {
247+
provider = "prisma-client-js"
248+
}
249+
250+
generator kysely {
251+
provider = "prisma-kysely"
252+
output = "../../src/kysely"
253+
enumFileName = "enums.ts"
254+
fileName = "types.ts"
255+
}
256+
```
257+
258+
```ts trigger.config.ts
259+
import { defineConfig } from "@trigger.dev/sdk/v3";
260+
import { prismaExtension } from "@trigger.dev/build/extensions/prisma";
261+
262+
export default defineConfig({
263+
project: "<project ref>",
264+
build: {
265+
extensions: [
266+
prismaExtension({
267+
schema: "prisma/schema.prisma",
268+
clientGenerator: "client",
269+
}),
270+
],
271+
},
272+
});
273+
```
274+
275+
</CodeGroup>
276+
232277
### audioWaveform
233278

234279
Previously, we installed [Audio Waveform](https://github.com/bbc/audiowaveform) in the build image. That's been moved to a build extension:
@@ -245,6 +290,115 @@ export default defineConfig({
245290
});
246291
```
247292

293+
### esbuild plugins
294+
295+
You can now add esbuild plugins to customize the build process using the `esbuildPlugin` build extension. The example below shows how to automatically upload sourcemaps to Sentry using their esbuild plugin:
296+
297+
```ts
298+
import { defineConfig } from "@trigger.dev/sdk/v3";
299+
import { esbuildPlugin } from "@trigger.dev/build/extensions";
300+
import { sentryEsbuildPlugin } from "@sentry/esbuild-plugin";
301+
302+
export default defineConfig({
303+
project: "<project ref>",
304+
build: {
305+
extensions: [
306+
esbuildPlugin(
307+
sentryEsbuildPlugin({
308+
org: process.env.SENTRY_ORG,
309+
project: process.env.SENTRY_PROJECT,
310+
authToken: process.env.SENTRY_AUTH_TOKEN,
311+
}),
312+
// optional - only runs during the deploy command, and adds the plugin to the end of the list of plugins
313+
{ placement: "last", target: "deploy" }
314+
),
315+
],
316+
},
317+
});
318+
```
319+
320+
## Changes to the `trigger.dev` CLI
321+
322+
### No more typechecking during deploy
323+
324+
We no longer run typechecking during the deploy command. This was causing issues with some projects, and we found that it wasn't necessary to run typechecking during the deploy command. If you want to run typechecking before deploying to Trigger.dev, you can run the `tsc` command before running the `deploy` command.
325+
326+
```sh
327+
tsc && npx [email protected] deploy
328+
```
329+
330+
Or if you are using GitHub actions, you can add an additional step to run the `tsc` command before deploying to Trigger.dev.
331+
332+
```yaml
333+
- name: Install dependencies
334+
run: npm install
335+
336+
- name: Typecheck
337+
run: npx tsc
338+
339+
- name: 🚀 Deploy Trigger.dev
340+
env:
341+
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
342+
run: |
343+
npx [email protected] deploy
344+
```
345+
346+
### deploy --dry-run
347+
348+
You can now inspect the build output of your project without actually deploying it to Trigger.dev by using the `--dry-run` flag:
349+
350+
```sh
351+
npx [email protected] deploy --dry-run
352+
```
353+
354+
This will save the build output and print the path to the build output directory. If you face any issues with deploying, please include the build output in your issue report.
355+
356+
### --env-file
357+
358+
You can now pass the path to your local `.env` file using the `--env-file` flag during `dev` and `deploy` commands:
359+
360+
```sh
361+
npx [email protected] dev --env-file ../../.env
362+
npx [email protected] deploy --env-file ../../.env
363+
```
364+
365+
The `.env` file works slightly differently in `dev` vs `deploy`:
366+
367+
- In `dev`, the `.env` file is loaded into the CLI's `process.env` and also into the environment variables of the Trigger.dev environment.
368+
- In `deploy`, the `.env` file is loaded into the CLI's `process.env` but not into the environment variables of the Trigger.dev environment. If you want to sync the environment variables from the `.env` file to the Trigger.dev environment variables, you can use the `syncEnvVars` build extension.
369+
370+
### dev debugging in VS Code
371+
372+
Debugging your tasks code in `dev` is now supported via VS Code, without having to pass in any additional flags. Create a launch configuration in `.vscode/launch.json`:
373+
374+
```json launch.json
375+
{
376+
"version": "0.2.0",
377+
"configurations": [
378+
{
379+
"name": "Trigger.dev: Dev",
380+
"type": "node",
381+
"request": "launch",
382+
"cwd": "${workspaceFolder}",
383+
"runtimeExecutable": "npx",
384+
"runtimeArgs": ["[email protected]", "dev"],
385+
"skipFiles": ["<node_internals>/**"],
386+
"sourceMaps": true
387+
}
388+
]
389+
}
390+
```
391+
392+
Then you can start debugging your tasks code by selecting the `Trigger.dev: Dev` configuration in the debug panel, and set breakpoints in your tasks code.
393+
394+
### TRIGGER_ACCESS_TOKEN in dev
395+
396+
You can now authenticate the `dev` command using the `TRIGGER_ACCESS_TOKEN` environment variable. Previously this was only supported in the `deploy` command.
397+
398+
```sh
399+
TRIGGER_ACCESS_TOKEN=<your access token> npx [email protected] dev
400+
```
401+
248402
## Known issues
249403

250404
- Path aliases are not yet support in your `trigger.config.ts` file. To workaround this issue you'll need to rewrite path aliases to their relative paths. (See [this](https://github.com/unjs/jiti/issues/166) and [this](https://knip.dev/reference/known-issues#path-aliases-in-config-files)) for more info.

packages/build/package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"exports": {
2424
"./package.json": "./package.json",
2525
".": "./src/index.ts",
26+
"./extensions": "./src/extensions/index.ts",
2627
"./extensions/core": "./src/extensions/core.ts",
2728
"./extensions/prisma": "./src/extensions/prisma.ts",
2829
"./extensions/audioWaveform": "./src/extensions/audioWaveform.ts",
@@ -68,6 +69,17 @@
6869
"default": "./dist/commonjs/index.js"
6970
}
7071
},
72+
"./extensions": {
73+
"import": {
74+
"@triggerdotdev/source": "./src/extensions/index.ts",
75+
"types": "./dist/esm/extensions/index.d.ts",
76+
"default": "./dist/esm/extensions/index.js"
77+
},
78+
"require": {
79+
"types": "./dist/commonjs/extensions/index.d.ts",
80+
"default": "./dist/commonjs/extensions/index.js"
81+
}
82+
},
7183
"./extensions/core": {
7284
"import": {
7385
"@triggerdotdev/source": "./src/extensions/core.ts",

packages/build/src/extensions/core/additionalPackages.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,16 @@ export function additionalPackages(options: AdditionalPackagesOptions): BuildExt
4141
continue;
4242
}
4343

44-
console.log("Resolved module path", { modulePath });
44+
context.logger.debug("[additionalPackages] Resolved module path", { modulePath });
4545

4646
const packageJSON = await readPackageJSON(dirname(modulePath));
4747

4848
if (packageJSON.version) {
4949
dependencies[name] = packageJSON.version;
5050
} else {
51-
console.warn(`Could not resolve version for package ${name}, defaulting to latest`);
51+
context.logger.warn(
52+
`Could not resolve version for package ${name}, defaulting to latest`
53+
);
5254

5355
dependencies[name] = "latest";
5456
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "@trigger.dev/core/v3/build";

packages/build/src/extensions/prisma.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,34 @@ export type PrismaExtensionOptions = {
99
schema: string;
1010
migrate?: boolean;
1111
version?: string;
12+
/**
13+
* The client generator to use. Set this param to prevent all generators in the prisma schema from being generated.
14+
*
15+
* @example
16+
*
17+
* ### Prisma schema
18+
*
19+
* ```prisma
20+
* generator client {
21+
* provider = "prisma-client-js"
22+
* }
23+
*
24+
* generator typegraphql {
25+
* provider = "typegraphql-prisma"
26+
* output = "./generated/type-graphql"
27+
* }
28+
* ```
29+
*
30+
* ### PrismaExtension
31+
*
32+
* ```ts
33+
* prismaExtension({
34+
* schema: "./prisma/schema.prisma",
35+
* clientGenerator: "client"
36+
* });
37+
* ```
38+
*/
39+
clientGenerator?: string;
1240
directUrlEnvVarName?: string;
1341
};
1442

@@ -86,6 +114,10 @@ export class PrismaExtension implements BuildExtension {
86114

87115
let prismaDir: string | undefined;
88116

117+
const generatorFlag = this.options.clientGenerator
118+
? `--generator=${this.options.clientGenerator}`
119+
: "";
120+
89121
if (usingSchemaFolder) {
90122
const schemaDir = dirname(this._resolvedSchemaPath);
91123

@@ -116,7 +148,9 @@ export class PrismaExtension implements BuildExtension {
116148
}
117149

118150
commands.push(
119-
`${binaryForRuntime(manifest.runtime)} node_modules/prisma/build/index.js generate` // Don't add the --schema flag or this will fail
151+
`${binaryForRuntime(
152+
manifest.runtime
153+
)} node_modules/prisma/build/index.js generate ${generatorFlag}` // Don't add the --schema flag or this will fail
120154
);
121155
} else {
122156
prismaDir = dirname(this._resolvedSchemaPath);
@@ -135,7 +169,7 @@ export class PrismaExtension implements BuildExtension {
135169
commands.push(
136170
`${binaryForRuntime(
137171
manifest.runtime
138-
)} node_modules/prisma/build/index.js generate --schema=./prisma/schema.prisma`
172+
)} node_modules/prisma/build/index.js generate --schema=./prisma/schema.prisma ${generatorFlag}`
139173
);
140174
}
141175

packages/build/src/extensions/typescript.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BuildExtension, createExtensionForPlugin } from "@trigger.dev/core/v3/build";
1+
import { BuildExtension, esbuildPlugin } from "@trigger.dev/core/v3/build";
22
import type { Plugin } from "esbuild";
33
import { readFile } from "node:fs/promises";
44
import { readTSConfig } from "pkg-types";
@@ -13,7 +13,7 @@ export type EmitDecoratorMetadataOptions = {
1313
};
1414

1515
export function emitDecoratorMetadata(options: EmitDecoratorMetadataOptions = {}): BuildExtension {
16-
return createExtensionForPlugin(plugin(options));
16+
return esbuildPlugin(plugin(options));
1717
}
1818

1919
function plugin(options: EmitDecoratorMetadataOptions = {}): Plugin {

packages/cli-v3/src/commands/deploy.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ const DeployCommandOptions = CommonCommandOptions.extend({
6969
saveLogs: z.boolean().default(false),
7070
skipUpdateCheck: z.boolean().default(false),
7171
noCache: z.boolean().default(false),
72+
envFile: z.string().optional(),
7273
});
7374

7475
type DeployCommandOptions = z.infer<typeof DeployCommandOptions>;
@@ -100,6 +101,10 @@ export function configureDeployCommand(program: Command) {
100101
"--skip-sync-env-vars",
101102
"Skip syncing environment variables when using the syncEnvVars extension."
102103
)
104+
.option(
105+
"--env-file <env file>",
106+
"Path to the .env file to load into the CLI process. Defaults to .env in the project directory."
107+
)
103108
)
104109
.addOption(
105110
new CommandOption(
@@ -209,7 +214,7 @@ async function _deployCommand(dir: string, options: DeployCommandOptions) {
209214
}
210215

211216
const serverEnvVars = await projectClient.client.getEnvironmentVariables(resolvedConfig.project);
212-
loadDotEnvVars(resolvedConfig.workingDir);
217+
loadDotEnvVars(resolvedConfig.workingDir, options.envFile);
213218

214219
const destination = getTmpDir(resolvedConfig.workingDir, "build", options.dryRun);
215220
const externalsExtension = createExternalsBuildExtension("deploy", resolvedConfig);

packages/cli-v3/src/commands/dev.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const DevCommandOptions = CommonCommandOptions.extend({
1717
config: z.string().optional(),
1818
projectRef: z.string().optional(),
1919
skipUpdateCheck: z.boolean().default(false),
20+
envFile: z.string().optional(),
2021
});
2122

2223
export type DevCommandOptions = z.infer<typeof DevCommandOptions>;
@@ -32,6 +33,10 @@ export function configureDevCommand(program: Command) {
3233
"-p, --project-ref <project ref>",
3334
"The project ref. Required if there is no config file."
3435
)
36+
.option(
37+
"--env-file <env file>",
38+
"Path to the .env file to use for the dev session. Defaults to .env in the project directory."
39+
)
3540
.option("--debug-otel", "Enable OpenTelemetry debugging")
3641
.option("--skip-update-check", "Skip checking for @trigger.dev package updates")
3742
).action(async (_, options) => {

packages/cli-v3/src/dev/workerRuntime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ class DevWorkerRuntime implements WorkerRuntime {
229229
);
230230

231231
const processEnv = gatherProcessEnv();
232-
const dotEnvVars = resolveDotEnvVars();
232+
const dotEnvVars = resolveDotEnvVars(undefined, this.options.args.envFile);
233233
const OTEL_IMPORT_HOOK_INCLUDES = getInstrumentedPackageNames(this.options.config).join(",");
234234

235235
const stripEmptyValues = (obj: Record<string, string | undefined>) => {

packages/cli-v3/src/utilities/dotEnv.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ import { env } from "std-env";
44

55
const ENVVAR_FILES = [".env", ".env.development", ".env.local", ".env.development.local"];
66

7-
export function resolveDotEnvVars(cwd?: string) {
7+
export function resolveDotEnvVars(cwd?: string, envFile?: string) {
88
const result: { [key: string]: string } = {};
99

10+
const envFilePath = envFile
11+
? resolve(cwd ?? process.cwd(), envFile)
12+
: ENVVAR_FILES.map((p) => resolve(cwd ?? process.cwd(), p));
13+
1014
dotenv.config({
1115
processEnv: result,
12-
path: ENVVAR_FILES.map((p) => resolve(cwd ?? process.cwd(), p)),
16+
path: envFilePath,
1317
});
1418

1519
env.TRIGGER_API_URL && (result.TRIGGER_API_URL = env.TRIGGER_API_URL);
@@ -21,8 +25,12 @@ export function resolveDotEnvVars(cwd?: string) {
2125
return result;
2226
}
2327

24-
export function loadDotEnvVars(cwd?: string) {
28+
export function loadDotEnvVars(cwd?: string, envFile?: string) {
29+
const envFilePath = envFile
30+
? resolve(cwd ?? process.cwd(), envFile)
31+
: ENVVAR_FILES.map((p) => resolve(cwd ?? process.cwd(), p));
32+
2533
dotenv.config({
26-
path: ENVVAR_FILES.map((p) => resolve(cwd ?? process.cwd(), p)),
34+
path: envFilePath,
2735
});
2836
}

0 commit comments

Comments
 (0)