Skip to content

#1926 - banana #2375

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

Closed
wants to merge 1 commit into from
Closed
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
25 changes: 19 additions & 6 deletions docs/config/extensions/prismaExtension.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ If you are using Prisma, you should use the prisma build extension.
- Automatically handles copying Prisma files to the build directory
- Generates the Prisma client during the deploy process
- Optionally will migrate the database during the deploy process
- Support for TypedSQL and multiple schema files
- You can use `prismaSchemaFolder` to specify just the directory containing your schema file, instead of the full path
- You can add the extension twice if you have multiple separate schemas in the same project (example below)

You can use it for a simple Prisma setup like this:
Expand Down Expand Up @@ -109,14 +107,27 @@ export default defineConfig({
});
```

</CodeGroup>
### Prisma 6.6.0+

In Prisma 6.6.0+, the `output` path for the Prisma client is no longer in `node_modules` by default. This means that the `prismaExtension` will no longer work out of the box with this version. To fix this, you will need to add the following to your `package.json` file:

```json
{
"prisma": {
"schema": "prisma/schema.prisma"
}
}
```

### TypedSQL
This will ensure that the Prisma client is generated in the correct location.

If you are using [TypedSQL](https://www.prisma.io/typedsql), you'll need to enable it via the `typedSql` option:
### The `copy` option

By default, the prisma schema and migrations are copied to the output directory. You can set this to false to disable this behavior.

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

export default defineConfig({
project: "<project ref>",
Expand All @@ -125,13 +136,15 @@ export default defineConfig({
extensions: [
prismaExtension({
schema: "prisma/schema.prisma",
typedSql: true,
copy: false,
}),
],
},
});
```

</CodeGroup>

<Note>
The `prismaExtension` will inject the `DATABASE_URL` environment variable into the build process. Learn more about setting environment variables for deploying in our [Environment Variables](/deploy-environment-variables) guide.

Expand Down
125 changes: 35 additions & 90 deletions packages/build/src/extensions/prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@ import { BuildManifest, BuildTarget } from "@trigger.dev/core/v3";
import { binaryForRuntime, BuildContext, BuildExtension } from "@trigger.dev/core/v3/build";
import assert from "node:assert";
import { existsSync } from "node:fs";
import { cp, readdir } from "node:fs/promises";
import { cp } from "node:fs/promises";
import { dirname, join, resolve } from "node:path";

export type PrismaExtensionOptions = {
schema: string;
migrate?: boolean;
version?: string;
/**
* Adds the `--sql` flag to the `prisma generate` command. This will generate the SQL files for the Prisma schema. Requires the `typedSql preview feature and prisma 5.19.0 or later.
*/
typedSql?: boolean;
/**
* The client generator to use. Set this param to prevent all generators in the prisma schema from being generated.
*
Expand Down Expand Up @@ -42,6 +38,11 @@ export type PrismaExtensionOptions = {
*/
clientGenerator?: string;
directUrlEnvVarName?: string;
/**
* By default, the prisma schema and migrations are copied to the output directory. Set this to false to disable this behavior.
* @default true
*/
copy?: boolean;
};

const BINARY_TARGET = "linux-arm64-openssl-3.0.x";
Expand Down Expand Up @@ -98,6 +99,12 @@ export class PrismaExtension implements BuildExtension {
externals: manifest.externals,
});

context.logger.debug("[PrismaExtension] Debugging paths and options", {
resolvedSchemaPath: this._resolvedSchemaPath,
options: this.options,
workingDir: context.workingDir,
});

const prismaExternal = manifest.externals?.find(
(external) => external.name === "@prisma/client"
);
Expand All @@ -112,117 +119,55 @@ export class PrismaExtension implements BuildExtension {

context.logger.debug(`PrismaExtension is generating the Prisma client for version ${version}`);

const usingSchemaFolder = dirname(this._resolvedSchemaPath).endsWith("schema");

const commands: string[] = [];

let prismaDir: string | undefined;

const generatorFlags: string[] = [];

if (this.options.clientGenerator) {
generatorFlags.push(`--generator=${this.options.clientGenerator}`);
}

if (this.options.typedSql) {
generatorFlags.push(`--sql`);

const prismaDir = usingSchemaFolder
? dirname(dirname(this._resolvedSchemaPath))
: dirname(this._resolvedSchemaPath);

context.logger.debug(`Using typedSql`);

// Find all the files prisma/sql/*.sql
const sqlFiles = await readdir(join(prismaDir, "sql")).then((files) =>
files.filter((file) => file.endsWith(".sql"))
);

context.logger.debug(`Found sql files`, {
sqlFiles,
});

const sqlDestinationPath = join(manifest.outputPath, "prisma", "sql");

for (const file of sqlFiles) {
const destination = join(sqlDestinationPath, file);
const source = join(prismaDir, "sql", file);

context.logger.debug(`Copying the sql from ${source} to ${destination}`);

await cp(source, destination);
}
}

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

prismaDir = dirname(schemaDir);

context.logger.debug(`Using the schema folder: ${schemaDir}`);
const prismaDir = dirname(this._resolvedSchemaPath);
const doCopy = this.options.copy ?? true;

// Find all the files in schemaDir that end with .prisma (excluding the schema.prisma file)
const prismaFiles = await readdir(schemaDir).then((files) =>
files.filter((file) => file.endsWith(".prisma"))
);

context.logger.debug(`Found prisma files in the schema folder`, {
prismaFiles,
});

const schemaDestinationPath = join(manifest.outputPath, "prisma", "schema");

const allPrismaFiles = [...prismaFiles];

for (const file of allPrismaFiles) {
const destination = join(schemaDestinationPath, file);
const source = join(schemaDir, file);

context.logger.debug(`Copying the prisma schema from ${source} to ${destination}`);

await cp(source, destination);
}

commands.push(
`${binaryForRuntime(
manifest.runtime
)} node_modules/prisma/build/index.js generate ${generatorFlags.join(" ")}` // Don't add the --schema flag or this will fail
);
} else {
prismaDir = dirname(this._resolvedSchemaPath);
if (doCopy) {
// Now we need to add a layer that:
// Copies the prisma schema to the build outputPath
// Adds the `prisma` CLI dependency to the dependencies
// Adds the `prisma generate` command, which generates the Prisma client
const schemaDestinationPath = join(manifest.outputPath, "prisma", "schema.prisma");
const schemaDestinationPath = join(manifest.outputPath, "schema.prisma");
// Copy the prisma schema to the build output path
context.logger.debug(
`Copying the prisma schema from ${this._resolvedSchemaPath} to ${schemaDestinationPath}`
);

await cp(this._resolvedSchemaPath, schemaDestinationPath);

commands.push(
`${binaryForRuntime(
manifest.runtime
)} node_modules/prisma/build/index.js generate --schema=./prisma/schema.prisma ${generatorFlags.join(
" "
)}`
);
}

commands.push(
`${binaryForRuntime(
manifest.runtime
)} node_modules/prisma/build/index.js generate --schema=./schema.prisma ${generatorFlags.join(
" "
)}`
);

const env: Record<string, string | undefined> = {};

if (this.options.migrate) {
// Copy the migrations directory to the build output path
const migrationsDir = join(prismaDir, "migrations");
const migrationsDestinationPath = join(manifest.outputPath, "prisma", "migrations");
if (doCopy) {
// Copy the migrations directory to the build output path
const migrationsDir = join(prismaDir, "migrations");
const migrationsDestinationPath = join(manifest.outputPath, "migrations");

context.logger.debug(
`Copying the prisma migrations from ${migrationsDir} to ${migrationsDestinationPath}`
);
context.logger.debug(
`Copying the prisma migrations from ${migrationsDir} to ${migrationsDestinationPath}`
);

await cp(migrationsDir, migrationsDestinationPath, { recursive: true });
if (existsSync(migrationsDir)) {
await cp(migrationsDir, migrationsDestinationPath, { recursive: true });
}
}

commands.push(
`${binaryForRuntime(manifest.runtime)} node_modules/prisma/build/index.js migrate deploy`
Expand Down