Sorry in advance for the long question, but project structure issues/bugs are kind of hard to explain.
I have a Next.js project, which is my root project. It's a Typescript project so it has its own tsconfig.json
Here is the basic structure:
> app // APP COMPONENTS
> pages // NEXT.JS PAGES
> types // SOME GLOBAL TYPES FOR THE PROJECT
firebase.json
firestore.rules
storage.rules
tsconfig.json
I need to add cloud functions to this project. So I've followed the docs on:
https://firebase.google.com/docs/functions/typescript
Basically I've typed firebase init functions
and followed the instructions from the CLI.
It then created a functions
as following (the >
sign is denoting a folder):
> app
> functions // NEW FOLDER FOR THE FUNCTIONS PROJECT
> src
index.ts
package.json
tsconfig.json
> pages
> types
firebase.json
firestore.rules
package.json
storage.rules
tsconfig.json
See now that the functions
folder has its own tsconfig.json
file and its own package.json
file. In essence, it is a project of its own. I'm fine with that idea.
Here is the tsconfig.json
file that was created:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "lib",
"sourceMap": true,
"strict": true,
"target": "es2017"
},
"compileOnSave": true,
"include": [
"src"
]
}
It also adds a predeploy
hook to my firebase.json
file.
"functions": {
"predeploy": "npm --prefix \"$RESOURCE_DIR\" run build"
}
This is necessary to build the .ts
file before deployment. It will build the files on the functions/src
folder to the functions/lib
folder, as per the tsconfig.json
.
The basic helloWorld
example builds and deploys just fine. I've added some files to the functions
folder and its all working.
See my files on functions/src
:
See the compiled files on functions/lib
:
It's the very same structure and files, just as you'd expect.
THE PROBLEM
The problem begins when I'm importing a type from the "outer" root project. For example:
I go on functions/src/index.ts
and do something like the following:
import SomeType from "../../types/whatever"
// USE THE TYPE HERE
Now see what the build result is (i.e: the functions/lib
folder):
Now it basically creates another functions
under the lib
folder. And it also basically copies the files from my types
folder. I have no idea why it is doing that.
I wasn't expecting that at all. I'd like to use my types from the outer root project, but without messing with the structure of the resulting functions/lib
folder.
What could be happening?
A way around it, that is not too hacky, is to declare your shared type as a namespace and import them with a /// <reference path="...">
command.
That way, you will be able to access your type through the declared namespace and the build will keep the required directory structure.
Assuming the following project
my-project/
functions/
src/
index.ts
shared/
type.d.ts
...otherFiles
shared.ts
declare namespace shared {
interface IType {
name: string
}
}
index.ts
// eslint-disable-next-line
/// <reference path="../../shared/model.d.ts" />
import * as functions from "firebase-functions";
export const helloWorld = functions.https.onRequest((request, response) => {
const type:shared.IType = {name: "John"};
functions.logger.info("Hello logs!", {structuredData: true});
response.send(`Hello ${type.name}!`);
});
The // eslint-disable-next-line
comments is required if you use eslint default rules from firebase template because of the @typescript-eslint/triple-slash-reference
rules.
I just solved a similar issue where I wanted to import the types from the project folder into the firebase functions folder.
// Default folder structure for Next.js and firebase functions
project-folder/
├── functions/
│ ├── src/
│ │ ├── index.ts
│ │ └── interfaces.ts // (See explanation for this one)
│ ├── package.json
│ └── tsconfig.json
├── interfaces/
│ └── index.ts
├── lib/
├── pages/
│ ├── _app.tsx
│ └── index.tsx
├── package.json
└── tsconfig.json
The functions/src/interfaces.ts
simply exports the types from the project folder, like so:
export * from "../../interfaces";
If you run tsc
in the functions-folder now, it will generate a file structure that looks different from before:
// Output when not importing from outside functions src folder
lib/
├── index.js
└── index.js.map
// Output when importing interfaces from outside src folder
lib/
├── functions/
│ └── src/
│ ├── index.js
│ └── index.js.map
└── interfaces/
All you now have to do is change package.json
a little bit:
{
"main": "lib/functions/src/index.js"
}
That's it! Files in your functions folder can import from the project folder.
Note about interfaces.ts
: I added this file because it seemed cleaner to have only one file that imports from outside the functions folder. Also, this way importing interfaces in the functions folder is similar to everywhere else in the project.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With