Bug description
I’m trying to deploy a GraphQL server using Netlify Functions; my app works in development, but doesn’t work in production because the necessary Prisma binary is not copied over post build.
This has been mentioned in another issue (here).
The binary apparently gets copied over using the netlify build
command, but not with the specialized netlify-lambda build
command.
The current Prisma docs offers an example that deploys the Prisma Client to Netlify Functions using REST API endpoints. For that particular use-case, the netlify functions:build
command is entirely sufficient (see here). However, in order to build a GraphQL server, only the netlify-lambda build
command will work. See here for a step-by-step instruction on how to set up a GraphQL server using Netlify Functions.
Using the netlify-lambda
commands, the GraphQL server gets build on Netlify, but Prisma Client’s rhel-openssl-1.0.x
binary never gets copied into the functions folder, producing the following log at /graphql.js
:
Invalid `prisma.user.findOne()` invocation:
Query engine binary for current platform "rhel-openssl-1.0.x" could not be found.
This probably happens, because you built Prisma Client on a different platform.
(Prisma Client looked in "/query-engine-rhel-openssl-1.0.x")
You already added the platforms "native", "rhel-openssl-1.0.x" to the "generator" block
in the "schema.prisma" file as described in https://pris.ly/d/client-generator,
but something went wrong. That's suboptimal.
Attempts to manually fix it
Since I know (or think I know) what the issue is (i.e. a missing rhel-openssl-1.0.x
binary file), I tried to copy it post-installation into the functions destination folder. At first I tried using a custom webpack plugin, which I was able to pass into the build by using netlify-lambda build functions -c ./webpack.config.js
(documentation here):
webpack.config.js
const CopyPlugin = require('copy-webpack-plugin')
module.exports = {
plugins: [
new CopyPlugin([
{
from: './node_modules/@prisma/client/runtime/query-engine-rhel-openssl-1.0.x'
}
])
]
}
However, the issue with that is that Webpack just packs the binary into the build-functions
folder. However, then zip-it-and-ship-it just takes the graphql.js
function out of the build-functions
folder — and not the binary — and places it into a folder like this: /tmp/zisi-5e8687894a4e660007b0e842
. Thus, the binary gets lost in production.
Next, I tried salvaging the binary by using a custom-built plugin.
prisma-client-plugin.js
const fs = require('fs')
module.exports = {
onPostBuild: api => {
console.log('Copying over `rhel-openssl-1.0.x` binary engine...')
const src = `node_modules/@prisma/client/runtime/query-engine-rhel-openssl-1.0.x`
const dest = `${api.constants.FUNCTIONS_DIST}/query-engine-rhel-openssl-1.0.x`
fs.copyFile(src, dest, err => console.log(err))
}
}
Sure enough, that got the binary actually copied into that temporary folder! Still, however, nothing happened. Binary was still missing in production.
So I wondered if the binary needs to be zipped in order for it to make it into the live site. So I did that:
const fs = require('fs')
const zip = new require('node-zip')()
module.exports = {
onPostBuild: api => {
console.log('Copying over `rhel-openssl-1.0.x` binary engine...')
const src = `node_modules/@prisma/client/runtime/query-engine-rhel-openssl-1.0.x`
const dest = `${api.constants.FUNCTIONS_DIST}/query-engine-rhel-openssl-1.0.x`
fs.copyFile(src, dest, err => console.log(err))
console.log('Zipping binary engine...')
zip.file(`query-engine-rhel-openssl-1.0.x`, fs.readFileSync(dest))
const data = zip.generate({ base64: false, compression: 'DEFLATE' })
fs.writeFileSync(`${api.constants.FUNCTIONS_DIST}/query.zip`, data, 'binary')
console.log('Removing unzipped binary engine...')
fs.unlinkSync(dest)
}
}
The zipping works, but now there’s a query.js
function file
So as before, Prisma Client cannot access the rhel-openssl-1.0.x
binary engine.
I have spent days trying, to no avail. Any help would be greatly appreciated!
netlify.toml
[build]
publish = "build/"
# Needed to take all netlify-lambda commands out of the package.json file and place them directly into the netlify.toml file for production, since during development Netlify attempts to run scripts that contain `netlify-lambda` functions! See: https://github.com/netlify/cli/issues/723#issuecomment-605511147
command = "cd functions && yarn && cd .. && yarn && npx prisma generate && npx netlify-lambda build functions && react-scripts build"
# During production, `functions` folder cannot be the same as destination when using `netlify-lambda`, so you need to create another destination.
functions = "build-functions/"
[build.environment]
# Fix to ensure the Prisma binary is packaged with the lambda function; [note from Martin: this seems unnecessary when using the netlify-lambda commands]
ZISI_VERSION = "0.4.0-9"
[[plugins]]
package = "./prisma-client-plugin"
[context.develop]
# `netlify dev` in local development won't work unless destination is the same as actual `functions` folder.
functions = "functions/"
How to reproduce
For reproduction, I created a dummy repo that contains all the crucial files. Feel free to clone and connect to your own Postgres db and deploy via Netlify Functions using this guide.