Skip to content

Instantly share code, notes, and snippets.

@nielsmaerten
Created December 15, 2021 16:09
Show Gist options
  • Save nielsmaerten/c1707b5c3882fcce7dba0d5c9430864b to your computer and use it in GitHub Desktop.
Save nielsmaerten/c1707b5c3882fcce7dba0d5c9430864b to your computer and use it in GitHub Desktop.
Deploy hooks for Firebase Functions + Yarn Workspaces
#!/usr/bin/env node
/**
* @description Firebase Functions Workspace Deploy Hooks
* @author Niels Maerten <https://github.com/nielsmaerten>
* @license MIT
*
* This script is designed for Yarn v3 workspaces.
*
* ### WHAT DOES THIS SCRIPT DO? ###
* Firebase Functions do not support 'monorepos'. This means that you can not
* have dependencies in package.json that point to 'workspace:my-package-name'.
* This script will find your workspace dependencies, package them, and copy the tgz-file
* into this project before deploying.
*
* When the deploy is complete and this script runs again, the original package.json is restored.
*
* By doing this, it is possible to slipstream workspace dependencies into your project
* and have it run on Cloud Functions
*/
const logTag = "[GLOBAL]";
const fs = require('fs');
// Find all dependencies in package.json where the value starts with 'workspace:'
const workspaceDeps = Object.entries(require('./package.json').dependencies).filter(([key, value]) => value.startsWith('workspace:'));
// This is a preDeploy if workspaceDeps has any entries
const isPreDeploy = workspaceDeps.length > 0;
const prePostDeploy = isPreDeploy ? 'Pre-deploy' : 'Post-deploy';
// If this is a preDeploy: backup the local package.json
// else: restore the backup
if (isPreDeploy) {
console.log(logTag, 'Backing up package.json');
fs.copyFileSync('./package.json', './package.json.bak');
} else {
console.log(logTag, 'Restoring package.json backup');
fs.copyFileSync('./package.json.bak', './package.json');
fs.unlinkSync('./package.json.bak');
}
// If preDeploy: Package all workspace dependencies into this directory
workspaceDeps.forEach(([workspace]) => {
const logTag = `[${workspace}]`;
console.log(logTag, `Running yarn pack`);
const workspacePath = `../${workspace}`;
const packageFilename = `${workspace}.tgz`;
const packCommand = `yarn pack --filename ${packageFilename}`;
const packResult = require('child_process').execSync(packCommand, { cwd: workspacePath });
// console.log(packResult.toString());
// Copy the package into this directory using node fs
console.log(logTag,`Copying package into this directory`);
const packPath = `${workspacePath}/${packageFilename}`;
const targetPath = `${__dirname}/${packageFilename}`;
fs.copyFileSync(packPath, targetPath);
// Update the package in the local package.json
console.log(logTag, `Updating local package.json`);
const localPackageJson = require('./package.json');
localPackageJson.dependencies[workspace] = `file:${packageFilename}`;
fs.writeFileSync('./package.json', JSON.stringify(localPackageJson, null, 2));
console.log(logTag, `Workspace successfully packaged into this directory`);
});
// If postDeploy, remove .tgz files in current dir
if (!isPreDeploy) {
console.log(logTag, 'Removing .tgz files');
fs.readdirSync(__dirname).forEach(file => {
if (file.endsWith('.tgz')) {
fs.unlinkSync(`${__dirname}/${file}`);
}
});
}
console.log(logTag, prePostDeploy, "hook ran successfully");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment