simondotm / nx-firebase

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

Importing other libraries types and constants not linked #129

Closed pikilon closed 11 months ago

pikilon commented 11 months ago

I import them and it compiles (despite TSC should break on compilation) but I can't do type checking and my IDE is not helping me with the imported constants.

image

I am using "^2.0.0-beta.1" and nx v16.5.1 and the latest firebase functions.

Thanks you again

simondotm commented 11 months ago

@pikilon - hmm perhaps VSCode's Typescript service isn't detecting the library alias from tsconfig.base.json

Try reloading your window or restarting the Typescript server ?

As you say, esbuild would emit a compilation error if the code was faulty.

pikilon commented 11 months ago

I tried but it didn't work, maybe the tsconfig.app.json is confusing VSC?

pikilon commented 11 months ago

Importing the types is not working because I introduced compilation errors on purpose on the typescript and it is not breaking in build

simondotm commented 11 months ago

does the esbuild .js output in dist from building the function look ok?

pikilon commented 11 months ago

Hello again Simon, To find out why is building but not using the types I created a very stupid code that should break on compilation time, but it doesn't In the cloud-functions nx-firebase app tsconfig.ts, I have

{
  "extends": "../../tsconfig.base.json",
  "files": [],
  "include": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
  ],
  "compilerOptions": {
    "esModuleInterop": true,
    "noEmitOnError": true // to break on build time
  }
}

And in the main.ts

import { onRequest } from "firebase-functions/v2/https";

type ExampleType = 'foo' | 'bar';
type ExampleRecord = Record<ExampleType, string>;

const record: ExampleRecord = {
  'should_break': 'nope',
}

export const helloWorld = onRequest((request, response) => {

  response.send("Hello from Firebase!" + record.should_break);
});

This is the result of the building npx nx build cloud-functions

// main.js
// apps/cloud-functions/src/main.ts
import { onRequest } from "firebase-functions/v2/https";
var record = {
  "should_break": "nope"
};
var helloWorld = onRequest((request, response) => {
  response.send("Hello from Firebase!" + record.should_break);
});
export {
  helloWorld
};

My main target on the typing is to share models with the frontend.

simondotm commented 11 months ago

That's really strange. I just added the code above to a boilerplate function I generated with the plugin and I do get a TS compilation error:

image

simondotm commented 11 months ago

My main target on the typing is to share models with the frontend.

Yes of course. I use shared libraries just for models too and it works nicely with my backend / frontend projects. So I'm not sure what's going on with your setup.

tsconfig.app.ts for my function is the default generator output:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../../../dist/out-tsc",
    "module": "es2020",
    "types": ["node"],
    "target": "es2020"
  },
  "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
  "include": ["src/**/*.ts"]
}

I'm using 16.1.1 of Nx however. I wonder if something has changed... 🤔

pikilon commented 11 months ago

That's really strange. I just added the code above to a boilerplate function I generated with the plugin and I do get a TS compilation error:

image

I see the same VSC typing error but it does compile: image

I execute yarn nx run cloud-functions:build --skip-nx-cache=true in the root of the nx workspace and I get this image

pikilon commented 11 months ago

{ "extends": "./tsconfig.json", "compilerOptions": { "outDir": "../../../../dist/out-tsc", "module": "es2020", "types": ["node"], "target": "es2020" }, "exclude": ["jest.config.ts", "src//*.spec.ts", "src/*/.test.ts"], "include": ["src//*.ts"] }

I see you have nested the cloud-functions folder app inside another project. I have it on the root:

simondotm commented 11 months ago

Could be the structure affecting this?

I can't think of a reason why that would be an issue.

You haven't somehow got skipTypeCheck enabled on your function project.json build target options by any chance? https://nx.dev/packages/esbuild/executors/esbuild#skiptypecheck

If this is set to true in my test function, I see the same issue as you - esbuild succeeds even though there are TS errors in the code.

Or possibly there's a bug/change in the latest Nx version related to this option 🤔

Try adding "skipTypeCheck": false to enforce it and see if anything changes.

in project.json

  "targets": {
    "build": {
      "executor": "@nx/esbuild:esbuild",
      "outputs": ["{options.outputPath}"],
      "options": {
        ....
        "skipTypeCheck": false,
       ....
      }
    },
pikilon commented 11 months ago

I added to the project.json in cloud-functions and even in firebase apps. Still compiling.

I have updated nx today to v16.5.2, still the same.

I think I am going to start a new demo workspace only with this functionality and check if it works, then compare the differences. I will let you know the results

pikilon commented 11 months ago

I have started a new project (today is on version v16.5.3) and it breaks, I will try to fix my older (upgraded many times) installation and bring back the results here if anyone has the same problem

pikilon commented 11 months ago

I feel very stupid, for some reason, there was a 2 on every src file in apps/cloud-functions/tsconfig.app.json

  "exclude": ["jest.config.ts", "src2/**/*.spec.ts", "src2/**/*.test.ts"],
  "include": ["src2/**/*.ts"]

I am sorry to bother you with this error.

I finally achieved what I wanted, type the onCall functions names (and more in the future). This will prevent any typo on the functions and consistency between backend and frontend

This is an example if someone wants to use it.

In types-constants package:

export type SearchFunctionName = 'search'

export const FUNCTIONS: Record<string, SearchFunctionName | OtherFunctionName> = {
  SEARCH: 'search
}

in the cloud-functions search module

Import { SearchFunctionName } from '@my-nx-project/types-constants'
import { onCall } from 'firebase-functions/v2/https'

const nameCheck: Record<SearchFunctionName, any> = {
  search: onCall(async (request) => { /* ... */ }
}

export { search } from nameCheck;

In the frontend

import { FUNCTIONS } from '@my-nx-project/types-constants'
import { getFunctions, httpsCallable } from 'firebase/functions'
// ...
export const fbFunctions = getFunctions(app)

export const searchHunts = httpsCallable(fbFunctions, FUNCTIONS.SEARCH)
simondotm commented 11 months ago

Glad to hear you found the issue. 👍