Search code examples
google-cloud-platformgoogle-cloud-functionsmonorepopnpmturborepo

How do I deploy an app in a monorepo (Turborepo), with local dependencies, as a Google Cloud Function?


I'm moving a project to a monorepo (Turborepo w/pnpm) and having trouble deploying my Google Cloud Functions. Normally I would simply use the gcloud CLI. For example:

call pnpm run build && gcloud functions deploy myCloudFunction \\
  --entry-point myMainFunction --env-vars-file .env.yaml \\
  --runtime nodejs16 --trigger-topic MY_TOPIC

However now I have the obvious problem - in the monorepo I have local dependencies referencing "workspace:*" so the "gcloud functions deploy" build process fails. Is there an elegant way to build and package my code so that "gcloud functions deploy" will have access to all the local dependencies it needs?


Solution

  • In case anyone else is looking for the solution, the easiest way to make this work seems to be:

    1. Run pnpm pack, which will output a .tgz file with your project
    pnpm pack
    
    1. Convert the tgz file to a zip file. This is required for using the --source flag. You can do this with a variety of tar and zip tools. I run a little container with a bash script to do the conversion, so I can automate the deployment process. After you untar, enter the "package" folder and zip the files from there. If you have trouble, check as see what you are including in the .zip.

    The zipped project might look like this. ".npmrc" can be used if you have private npm packages to include. The "dist" folder just has the "index.js" build by the pnpm packer.

    Zip folder structure

    The package.json file might look like this:

    {
      "name": "my-cloud-function",
      "version": "0.0.1",
      "private": true,
      "description": "handle various Pub/Sub messages",
      "main": "dist/index.js",
      "files": [
        "dist",
        ".npmrc"
      ],
      "dependencies": {
        [... your dependencies]
      },
      "license": "UNLICENSED",
      "devDependencies": {
        "@google-cloud/functions-framework": "^3.2.0",
        "@types/express": "^4.17.11",
        "@types/node": "^18.11.6"
      }
    }
    
    1. Upload to a GCP bucket
    gsutil cp myfunction.zip gs://some-bucket/build
    
    1. Deploy with the --source flag
    gcloud functions deploy myCloudFunction \\
      --source gs://some-bucket/myfunction.zip \\
      --entry-point myMainFunction --env-vars-file .env.yaml \\
      --runtime nodejs16 --trigger-topic MY_TOPIC
    

    That does it. Using "pnpm pack" automatically deals with packing up the local dependencies that are referenced as "workspace:*" in the monorepo.