Skip to content

Commit

Permalink
feat(client): preview feature deno (#15281)
Browse files Browse the repository at this point in the history
Co-authored-by: Yoshiya Hinosawa <stibium121@gmail.com>
Co-authored-by: Jan Piotrowski <piotrowski+github@gmail.com>
  • Loading branch information
3 people committed Oct 17, 2022
1 parent cff8216 commit 1343c82
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 6 deletions.
11 changes: 10 additions & 1 deletion packages/cli/src/Generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,15 @@ Please run \`prisma generate\` manually.`
)
let hint = ''
if (prismaClientJSGenerator) {
const generator = prismaClientJSGenerator.options?.generator
const isDeno = generator?.previewFeatures.includes('deno') && !!globalThis.Deno
if (isDeno && !generator?.isCustomOutput) {
throw new Error(`Can't find output dir for generator ${chalk.bold(
generator?.name,
)} with provider ${chalk.bold(generator?.provider.value)}.
When using Deno, you need to define \`output\` in the client generator section of your schema.prisma file.`)
}

const importPath = prismaClientJSGenerator.options?.generator?.isCustomOutput
? prefixRelativePathIfNecessary(
replacePathSeparatorsIfNecessary(
Expand Down Expand Up @@ -241,7 +250,7 @@ ${chalk.dim('```')}${
To use Prisma Client in edge runtimes like Cloudflare Workers or Vercel Edge Functions, import it like this:
${chalk.dim('```')}
${highlightTS(`\
import { PrismaClient } from '${importPath}/edge'`)}
import { PrismaClient } from '${importPath}/${isDeno ? 'deno/' : ''}edge${isDeno ? '.ts' : ''}'`)}
${chalk.dim('```')}
You will need a Prisma Data Proxy connection string. See documentation: ${link('https://pris.ly/d/data-proxy')}
Expand Down
16 changes: 15 additions & 1 deletion packages/client/helpers/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ const edgeRuntimeBuildConfig: BuildOptions = {
logLevel: 'error',
}

// we define the config for edge in esm format (used by deno)
const edgeEsmRuntimeBuildConfig: BuildOptions = {
...edgeRuntimeBuildConfig,
name: 'edge-esm',
outfile: 'runtime/edge-esm',
format: 'esm',
}

// we define the config for generator
const generatorBuildConfig: BuildOptions = {
name: 'generator',
Expand Down Expand Up @@ -126,7 +134,13 @@ function bundleTypeDefinitions(filename: string, outfile: string) {
}
}

void build([generatorBuildConfig, nodeRuntimeBuildConfig, browserBuildConfig, edgeRuntimeBuildConfig]).then(() => {
void build([
generatorBuildConfig,
nodeRuntimeBuildConfig,
browserBuildConfig,
edgeRuntimeBuildConfig,
edgeEsmRuntimeBuildConfig,
]).then(() => {
if (process.env.DEV !== 'true') {
bundleTypeDefinitions('declaration/runtime/index', 'runtime/index')
bundleTypeDefinitions('declaration/runtime/index-browser', 'runtime/index-browser')
Expand Down
10 changes: 10 additions & 0 deletions packages/client/scripts/default-deno-edge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class PrismaClient {
constructor() {
throw new Error(
`@prisma/client/deno/edge did not initialize yet. Please run "prisma generate --data-proxy" and try to import it again.
In case this error is unexpected for you, please report it in https://github.com/prisma/prisma/issues`,
)
}
}

export { PrismaClient }
7 changes: 7 additions & 0 deletions packages/client/scripts/postinstall.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,10 @@ async function createDefaultGeneratedThrowFiles() {
const defaultBrowserIndexPath = path.join(dotPrismaClientDir, 'index-browser.js')
const defaultEdgeIndexPath = path.join(dotPrismaClientDir, 'edge.js')
const defaultEdgeIndexDtsPath = path.join(dotPrismaClientDir, 'edge.d.ts')
const defaultDenoClientDir = path.join(dotPrismaClientDir, 'deno')
const defaultDenoEdgeIndexPath = path.join(defaultDenoClientDir, 'edge.ts')
await makeDir(dotPrismaClientDir)
await makeDir(defaultDenoClientDir)

if (!fs.existsSync(defaultNodeIndexPath)) {
await copyFile(path.join(__dirname, 'default-index.js'), defaultNodeIndexPath)
Expand All @@ -230,6 +233,10 @@ async function createDefaultGeneratedThrowFiles() {
if (!fs.existsSync(defaultEdgeIndexDtsPath)) {
await copyFile(path.join(__dirname, 'default-index.d.ts'), defaultEdgeIndexDtsPath)
}

if (!fs.existsSync(defaultDenoEdgeIndexPath)) {
await copyFile(path.join(__dirname, 'default-deno-edge.ts'), defaultDenoEdgeIndexPath)
}
} catch (e) {
console.error(e)
}
Expand Down
4 changes: 3 additions & 1 deletion packages/client/src/generation/TSClient/TSClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export interface TSClientOptions {
outputDir: string
activeProvider: string
dataProxy: boolean
deno?: boolean
}

export class TSClient implements Generatable {
Expand All @@ -66,6 +67,7 @@ export class TSClient implements Generatable {
runtimeName,
datasources,
dataProxy,
deno,
} = this.options
const envPaths = getEnvPaths(schemaPath, { cwd: outputDir })

Expand Down Expand Up @@ -132,7 +134,7 @@ ${buildWarnEnvConflicts(edge, runtimeDir, runtimeName)}
${buildDebugInitialization(edge)}
const PrismaClient = getPrismaClient(config)
exports.PrismaClient = PrismaClient
Object.assign(exports, Prisma)
Object.assign(exports, Prisma)${deno ? '\nexport { exports as default, Prisma, PrismaClient }' : ''}
${buildNFTAnnotations(dataProxy, engineType, platforms, relativeOutdir)}
`
return code
Expand Down
25 changes: 23 additions & 2 deletions packages/client/src/generation/TSClient/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,31 @@ export const commonCodeJS = ({
browser,
clientVersion,
engineVersion,
}: TSClientOptions): string => `
deno,
}: TSClientOptions): string => `${deno ? 'const exports = {}' : ''}
Object.defineProperty(exports, "__esModule", { value: true });
${
browser
deno
? `
import {
PrismaClientKnownRequestError,
PrismaClientUnknownRequestError,
PrismaClientRustPanicError,
PrismaClientInitializationError,
PrismaClientValidationError,
NotFoundError,
decompressFromBase64,
getPrismaClient,
sqltag,
empty,
join,
raw,
Decimal,
Debug,
objectEnumValues,
makeStrictEnum
} from '${runtimeDir}/edge-esm.js'`
: browser
? `
const {
Decimal,
Expand Down
24 changes: 24 additions & 0 deletions packages/client/src/generation/generateClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,27 @@ export async function buildClient({
fileMap['edge.d.ts'] = await TS(edgeTsClient, true)
}

if (generator?.previewFeatures.includes('deno') && !!globalThis.Deno) {
if (dataProxy === true) {
// we create a client that is fit for edge runtimes
const denoEdgeTsClient = new TSClient({
...tsClientOptions,
dataProxy: true, // edge only works w/ data proxy
runtimeName: 'index.d.ts',
runtimeDir: '../' + runtimeDirs.edge,
deno: true,
})

fileMap['deno/edge.js'] = await JS(denoEdgeTsClient, true)
fileMap['deno/index.d.ts'] = await TS(denoEdgeTsClient)
fileMap['deno/edge.ts'] = `
import './polyfill.js'
// @deno-types="./index.d.ts"
export * from './edge.js'`
fileMap['deno/polyfill.js'] = 'globalThis.process = { env: Deno.env.toObject() }; globalThis.global = globalThis'
}
}

return {
fileMap, // a map of file names to their contents
prismaClientDmmf: document, // the DMMF document
Expand Down Expand Up @@ -222,6 +243,9 @@ export async function generateClient(options: GenerateClientOptions): Promise<vo

await makeDir(finalOutputDir)
await makeDir(path.join(outputDir, 'runtime'))
if (generator?.previewFeatures.includes('deno') && !!globalThis.Deno) {
await makeDir(path.join(outputDir, 'deno'))
}
// TODO: why do we sometimes use outputDir and sometimes finalOutputDir?
// outputDir: /home/millsp/Work/prisma/packages/client
// finalOutputDir: /home/millsp/Work/prisma/.prisma/client
Expand Down
1 change: 0 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1343c82

Please sign in to comment.