Duplicating the GraphQL schema to other repos via watchman

Hey folks, I use Relay across all clients connecting to my Redwood API and have multiple repos which need to have an up-to-date copy of the schema file generated in .redwood/graphql. So, I re-used some of the infra from the TypeScript Website and integrated it into my Redwood API to duplicate the .graphql files to separate repos.

The current technique I’ve been using for adding new commands to yarn dev on Redwood, is to make the webpack config trigger long-running processes. So, eject the webpack config in Redwood.

Then in your web/config/webpack.config.js add some code which hooks into any existing watchman project:

const { spawn, spawnSync } = require("child_process")
const { existsSync, cpSync } = require("fs")
const { join } = require("path")

/** @returns {import('webpack').Configuration} Webpack Configuration */
module.exports = (config, { mode }) => {

  if (mode === "development") {
    const help = spawnSync("watchman", ["--help"])
    const hasWatchman = !help.error
    if (!hasWatchman) {
      const showError = process.env.DEBUG
      const suffix = !showError ? "Run with DEBUG=* to see the error logs." : ""

      console.log(`Watchman failed to load, this is _OK_ but the graphql schema will not be synced. ` + suffix)
      if (showError) console.error(help.error)
    } else {
      const watchman = require("fb-watchman")
      const client = new watchman.Client({})

      const schemaFile = join(process.cwd(), "..", ".redwood", "schema.graphql")
      const appFolder = join(process.cwd(), "..", "..", "app")

      if (existsSync(schemaFile) && existsSync(appFolder)) {
        console.log("Watching for the schema changes")
        // Connect to the 'app project' which is current in metro/webpack/et al
        client.command(["watch-project", process.cwd()], (err, resp) => {
          // Say we want to register for when the graphql file changes
          client.command([
            "subscribe",
            resp.watch,
            "GraphQL Duplicator",
            {
              expression: ["anyof", ["match", "*.graphql"]],
              relative_root: ".redwood",
              fields: ["name", "exists", "type"],
            },
          ])

          client.on("subscription", function (resp) {
            if (resp.files.find((f) => f.name === "schema.graphql")) {
              console.log("Schema changed, saving the new schema to the app")
              cpSync(schemaFile, join(appFolder, "api-schema.graphql"))
            }
          })
        })
      } else {
        console.error(`Did not start up the schema watcher.`)
      }
    }
  }

  return config
}

Then you can change it to do whatever you actually need.

2 Likes