Skip to content

Add support + docs for custom esbuild plugins #1270

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/rotten-eggs-occur.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@trigger.dev/build": patch
"@trigger.dev/core": patch
---

Added support for custom esbuild plugins
154 changes: 154 additions & 0 deletions docs/guides/new-build-system-preview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ If you've added the `trigger.dev` CLI to your `devDependencies`, then you should

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

<Note>If you deploy using GitHub actions, make sure you update the version there too.</Note>

## Update your `trigger.config.ts`

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.
Expand Down Expand Up @@ -229,6 +231,49 @@ export default defineConfig({
});
```

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:

<CodeGroup>

```prisma schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DATABASE_URL_UNPOOLED")
}

// We only want to generate the prisma-client-js generator
generator client {
provider = "prisma-client-js"
}

generator kysely {
provider = "prisma-kysely"
output = "../../src/kysely"
enumFileName = "enums.ts"
fileName = "types.ts"
}
```

```ts trigger.config.ts
import { defineConfig } from "@trigger.dev/sdk/v3";
import { prismaExtension } from "@trigger.dev/build/extensions/prisma";

export default defineConfig({
project: "<project ref>",
build: {
extensions: [
prismaExtension({
schema: "prisma/schema.prisma",
clientGenerator: "client",
}),
],
},
});
```

</CodeGroup>

### audioWaveform

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

### esbuild plugins

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:

```ts
import { defineConfig } from "@trigger.dev/sdk/v3";
import { esbuildPlugin } from "@trigger.dev/build/extensions";
import { sentryEsbuildPlugin } from "@sentry/esbuild-plugin";

export default defineConfig({
project: "<project ref>",
build: {
extensions: [
esbuildPlugin(
sentryEsbuildPlugin({
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
authToken: process.env.SENTRY_AUTH_TOKEN,
}),
// optional - only runs during the deploy command, and adds the plugin to the end of the list of plugins
{ placement: "last", target: "deploy" }
),
],
},
});
```

## Changes to the `trigger.dev` CLI

### No more typechecking during deploy

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.

```sh
tsc && npx [email protected] deploy
```

Or if you are using GitHub actions, you can add an additional step to run the `tsc` command before deploying to Trigger.dev.

```yaml
- name: Install dependencies
run: npm install

- name: Typecheck
run: npx tsc

- name: 🚀 Deploy Trigger.dev
env:
TRIGGER_ACCESS_TOKEN: ${{ secrets.TRIGGER_ACCESS_TOKEN }}
run: |
npx [email protected] deploy
```

### deploy --dry-run

You can now inspect the build output of your project without actually deploying it to Trigger.dev by using the `--dry-run` flag:

```sh
npx [email protected] deploy --dry-run
```

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.

### --env-file

You can now pass the path to your local `.env` file using the `--env-file` flag during `dev` and `deploy` commands:

```sh
npx [email protected] dev --env-file ../../.env
npx [email protected] deploy --env-file ../../.env
```

The `.env` file works slightly differently in `dev` vs `deploy`:

- In `dev`, the `.env` file is loaded into the CLI's `process.env` and also into the environment variables of the Trigger.dev environment.
- 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.

### dev debugging in VS Code

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`:

```json launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Trigger.dev: Dev",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "npx",
"runtimeArgs": ["[email protected]", "dev"],
"skipFiles": ["<node_internals>/**"],
"sourceMaps": true
}
]
}
```

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.

### TRIGGER_ACCESS_TOKEN in dev

You can now authenticate the `dev` command using the `TRIGGER_ACCESS_TOKEN` environment variable. Previously this was only supported in the `deploy` command.

```sh
TRIGGER_ACCESS_TOKEN=<your access token> npx [email protected] dev
```

## Known issues

- 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.
Expand Down
12 changes: 12 additions & 0 deletions packages/build/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"exports": {
"./package.json": "./package.json",
".": "./src/index.ts",
"./extensions": "./src/extensions/index.ts",
"./extensions/core": "./src/extensions/core.ts",
"./extensions/prisma": "./src/extensions/prisma.ts",
"./extensions/audioWaveform": "./src/extensions/audioWaveform.ts",
Expand Down Expand Up @@ -68,6 +69,17 @@
"default": "./dist/commonjs/index.js"
}
},
"./extensions": {
"import": {
"@triggerdotdev/source": "./src/extensions/index.ts",
"types": "./dist/esm/extensions/index.d.ts",
"default": "./dist/esm/extensions/index.js"
},
"require": {
"types": "./dist/commonjs/extensions/index.d.ts",
"default": "./dist/commonjs/extensions/index.js"
}
},
"./extensions/core": {
"import": {
"@triggerdotdev/source": "./src/extensions/core.ts",
Expand Down
6 changes: 4 additions & 2 deletions packages/build/src/extensions/core/additionalPackages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,16 @@ export function additionalPackages(options: AdditionalPackagesOptions): BuildExt
continue;
}

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

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

if (packageJSON.version) {
dependencies[name] = packageJSON.version;
} else {
console.warn(`Could not resolve version for package ${name}, defaulting to latest`);
context.logger.warn(
`Could not resolve version for package ${name}, defaulting to latest`
);

dependencies[name] = "latest";
}
Expand Down
1 change: 1 addition & 0 deletions packages/build/src/extensions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "@trigger.dev/core/v3/build";
38 changes: 36 additions & 2 deletions packages/build/src/extensions/prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,34 @@ export type PrismaExtensionOptions = {
schema: string;
migrate?: boolean;
version?: string;
/**
* The client generator to use. Set this param to prevent all generators in the prisma schema from being generated.
*
* @example
*
* ### Prisma schema
*
* ```prisma
* generator client {
* provider = "prisma-client-js"
* }
*
* generator typegraphql {
* provider = "typegraphql-prisma"
* output = "./generated/type-graphql"
* }
* ```
*
* ### PrismaExtension
*
* ```ts
* prismaExtension({
* schema: "./prisma/schema.prisma",
* clientGenerator: "client"
* });
* ```
*/
clientGenerator?: string;
directUrlEnvVarName?: string;
};

Expand Down Expand Up @@ -86,6 +114,10 @@ export class PrismaExtension implements BuildExtension {

let prismaDir: string | undefined;

const generatorFlag = this.options.clientGenerator
? `--generator=${this.options.clientGenerator}`
: "";

if (usingSchemaFolder) {
const schemaDir = dirname(this._resolvedSchemaPath);

Expand Down Expand Up @@ -116,7 +148,9 @@ export class PrismaExtension implements BuildExtension {
}

commands.push(
`${binaryForRuntime(manifest.runtime)} node_modules/prisma/build/index.js generate` // Don't add the --schema flag or this will fail
`${binaryForRuntime(
manifest.runtime
)} node_modules/prisma/build/index.js generate ${generatorFlag}` // Don't add the --schema flag or this will fail
);
} else {
prismaDir = dirname(this._resolvedSchemaPath);
Expand All @@ -135,7 +169,7 @@ export class PrismaExtension implements BuildExtension {
commands.push(
`${binaryForRuntime(
manifest.runtime
)} node_modules/prisma/build/index.js generate --schema=./prisma/schema.prisma`
)} node_modules/prisma/build/index.js generate --schema=./prisma/schema.prisma ${generatorFlag}`
);
}

Expand Down
4 changes: 2 additions & 2 deletions packages/build/src/extensions/typescript.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BuildExtension, createExtensionForPlugin } from "@trigger.dev/core/v3/build";
import { BuildExtension, esbuildPlugin } from "@trigger.dev/core/v3/build";
import type { Plugin } from "esbuild";
import { readFile } from "node:fs/promises";
import { readTSConfig } from "pkg-types";
Expand All @@ -13,7 +13,7 @@ export type EmitDecoratorMetadataOptions = {
};

export function emitDecoratorMetadata(options: EmitDecoratorMetadataOptions = {}): BuildExtension {
return createExtensionForPlugin(plugin(options));
return esbuildPlugin(plugin(options));
}

function plugin(options: EmitDecoratorMetadataOptions = {}): Plugin {
Expand Down
7 changes: 6 additions & 1 deletion packages/cli-v3/src/commands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const DeployCommandOptions = CommonCommandOptions.extend({
saveLogs: z.boolean().default(false),
skipUpdateCheck: z.boolean().default(false),
noCache: z.boolean().default(false),
envFile: z.string().optional(),
});

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

const serverEnvVars = await projectClient.client.getEnvironmentVariables(resolvedConfig.project);
loadDotEnvVars(resolvedConfig.workingDir);
loadDotEnvVars(resolvedConfig.workingDir, options.envFile);

const destination = getTmpDir(resolvedConfig.workingDir, "build", options.dryRun);
const externalsExtension = createExternalsBuildExtension("deploy", resolvedConfig);
Expand Down
5 changes: 5 additions & 0 deletions packages/cli-v3/src/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const DevCommandOptions = CommonCommandOptions.extend({
config: z.string().optional(),
projectRef: z.string().optional(),
skipUpdateCheck: z.boolean().default(false),
envFile: z.string().optional(),
});

export type DevCommandOptions = z.infer<typeof DevCommandOptions>;
Expand All @@ -32,6 +33,10 @@ export function configureDevCommand(program: Command) {
"-p, --project-ref <project ref>",
"The project ref. Required if there is no config file."
)
.option(
"--env-file <env file>",
"Path to the .env file to use for the dev session. Defaults to .env in the project directory."
)
.option("--debug-otel", "Enable OpenTelemetry debugging")
.option("--skip-update-check", "Skip checking for @trigger.dev package updates")
).action(async (_, options) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli-v3/src/dev/workerRuntime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ class DevWorkerRuntime implements WorkerRuntime {
);

const processEnv = gatherProcessEnv();
const dotEnvVars = resolveDotEnvVars();
const dotEnvVars = resolveDotEnvVars(undefined, this.options.args.envFile);
const OTEL_IMPORT_HOOK_INCLUDES = getInstrumentedPackageNames(this.options.config).join(",");

const stripEmptyValues = (obj: Record<string, string | undefined>) => {
Expand Down
16 changes: 12 additions & 4 deletions packages/cli-v3/src/utilities/dotEnv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import { env } from "std-env";

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

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

const envFilePath = envFile
? resolve(cwd ?? process.cwd(), envFile)
: ENVVAR_FILES.map((p) => resolve(cwd ?? process.cwd(), p));

dotenv.config({
processEnv: result,
path: ENVVAR_FILES.map((p) => resolve(cwd ?? process.cwd(), p)),
path: envFilePath,
});

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

export function loadDotEnvVars(cwd?: string) {
export function loadDotEnvVars(cwd?: string, envFile?: string) {
const envFilePath = envFile
? resolve(cwd ?? process.cwd(), envFile)
: ENVVAR_FILES.map((p) => resolve(cwd ?? process.cwd(), p));

dotenv.config({
path: ENVVAR_FILES.map((p) => resolve(cwd ?? process.cwd(), p)),
path: envFilePath,
});
}
Loading
Loading