simondotm / nx-firebase

Firebase plugin for Nx Monorepos
https://www.npmjs.com/package/@simondotm/nx-firebase
MIT License
175 stars 31 forks source link

Custom Serve Executor Doesn't Respect Configurations #159

Open tommyc38 opened 8 months ago

tommyc38 commented 8 months ago

I have configurations for serve, watch, and the firebase targets. My configs for each are dev, prod, and local. The problem I am facing is that the serve target/executor doesn't respect any configurations under it. Is this by design or a bug?

simondotm commented 8 months ago

Hi @tommyc38 , thanks for reporting this. It was tricky adding the custom executor as I imagined folks would inevitably customise some of their projects and so compatibility was hard to predict.

Could you share an example of your project.json with your extra configs here? That way I can look at making the executor more compatible.

tommyc38 commented 8 months ago

@simondotm below is a contrived example that resembles my project. Please don't hesitate to ask any questions and thank you for writing this lib!

Project Structure:

workspace/
  firebase/
  firebase-functions/
  ui/
    env/
      - local.ts
      - dev.ts
      - prod.ts
  - firebase.dev.json
  - firebase.local.json
  - firebase.json
  - .firebaserc
// firebase/project.json
{
  ...

  "firebase": {
    "executor": "nx:run-commands",
    "options": {
      "command": "firebase --config=firebase.json --project=dev"
    },
    // I want my dev and prod environments to be the same in terms of everything in the firebase project.
    // However, when I run the emulator I need to serve the app from their respective build folders
    // (e.g. dist/ui (prod), dist/ui-local, dist/ui-dev) so all of the firebase.<env>.json are exactly the same
    // except for the hosting.public property pointing to the aforementioned dist directories.
    "configurations": {
      "prod": {
        "command": "firebase --config=firebase.json --project=prod"
      },
      "dev": {
        "command": "firebase --config=firebase.dev.json --project=dev"
      },
      "local": {
        "command": "firebase --config=firebase.local.json --project=dev"
      }
    },
  },
  "watch": {
    "executor": "nx:run-commands",
    "options": {
      "command": "nx run-many --targets=build --projects=tag:firebase:dep:firebase --parallel=100 --watch"
    },
    // Both projects, ui and firebase-functions, have the tag "firebase:dep:firebase" so they are both built in watch mode
    "configurations": {
      "prod": {
        "command": "nx run-many --targets=build:prod --projects=tag:firebase:dep:firebase --parallel=100 --watch"
      },
      "dev": {
        "command": "nx run-many --targets=build:dev --projects=tag:firebase:dep:firebase --parallel=100 --watch"
      },
      "local": {
        "command": "nx run-many --targets=build:local --projects=tag:firebase:dep:firebase --parallel=100 --watch"
      }
    }
  },
  "emulate": {
    "executor": "nx:run-commands",
    "options": {
      "commands": [
        "nx run firebase:killports",
        "nx run firebase:firebase emulators:start --import=firebase/.emulators --export-on-exit"
      ],
      "parallel": false
    },
    "configurations": {
      "prod": {
        "commands": [
          "nx run firebase:killports",
          "nx run firebase:firebase:prod emulators:start --import=firebase/.emulators --export-on-exit"
        ]
      },
      "dev": {
        "commands": [
          "nx run firebase:killports",
          "nx run firebase:firebase:dev emulators:start --import=firebase/.emulators --export-on-exit"
        ]
      },
      "local": {
        "commands": [
          "nx run firebase:killports",
          "nx run firebase:firebase:local emulators:start --import=firebase/.emulators --export-on-exit"
        ]
      }
    }
  },
  "serve": {
    "executor": "@simondotm/nx-firebase:serve",
    "options": {
      "commands": [
        "nx run firebase:watch",
        "nx run firebase:emulate"
      ]
    },
    "configurations": {
      "prod": {
        "commands": [
          "nx run firebase:watch:prod",
          "nx run firebase:emulate:prod"
        ]
      },
      "dev": {
        "commands": [
          "nx run firebase:watch:dev",
          "nx run firebase:emulate:dev"
        ]
      },
      "local": {
        "commands": [
          "nx run firebase:watch:local",
          "nx run firebase:emulate:local"
        ]
      }
    }
  },
}
tommyc38 commented 8 months ago

The problem is this command:

function getCommandFromTarget(
  project: ProjectConfiguration,
  targetName: ValidTarget,
  commandGrep: string,
) {
  const target = project.targets[targetName] as NxRunCommandsTargetConfiguration
  if (!target) {
    throw new Error(
      `Could not find target '${targetName}' in project '${project.name}'`,
    )
  }
  const commands: string[] = [
    ...(target.options.command ? [target.options.command] : []),
    ...(target.options.commands ? target.options.commands : []),
  ].filter((cmd) => cmd.includes(commandGrep))

  if (commands.length === 0) {
    throw new Error(
      `Could not find a command in target '${targetName}' that matches '${commandGrep}'`,
    )
  }

  if (commands.length !== 1) {
    logger.warn(
      `Found multiple commands in target '${targetName}' that match '${commandGrep}', using first match`,
    )
  }
  return commands[0]
}

Then you call like this where you are effectively hard coding the target and the command in:

  const watchCommand = getCommandFromTarget(
      project,
      'watch',
      'nx run-many --targets=build',
    )

I've just briefly looked at the code but it looks like we need to call the actual ExecutiveContext properties (e.g. target and target configuration) rather than the hard coded target and target options.

Here is a link to the ExecutorContext Interface.

simondotm commented 8 months ago

@tommyc38 I'll take a look at this when I get a spare moment over the next week or so. 👍

tommyc38 commented 8 months ago

@simondotm have you had a chance to take a look at this?

simondotm commented 7 months ago

@tommyc38 not yet unfortunately, slammed with work atm. On my radar though