I am trying to wrap my head around typescript project references and how they are intended to be used in a production build, specifically for an Azure Function App. I am not using any functionality for monorepos at the package manager level, like npm workspaces or lerna. I do not want to publish any packages to npm.
I guess the main problem I have is that I want my compiled output from typescript to be in a folder structure that is compatible with the conventions of an Azure Function App, while having a different structure for the non-compiled projects. I am using es6 modules and the file references for the imports will be wrong if the folder stucture of the project changes.
Lets pretend that we have the following folder structure:
ts-monorepo
packages
myApp
GetHello
function.json <-- Azure Function App specific file
index.ts
host.json <-- Azure Function App specific file
package.json
tsconfig.json
myLib
lib
greeter.ts
package.json
tsconfig.json
myApp wants to use myLib and hence packages/myApp/GetHello/index.ts has the following line in it:
// packages/myApp/GetHello/index.ts
import { sayHello } from '../../myLib/lib/greeter';
(The above should probably be using tsconfig paths property to make an "alias" for the lib, but I don't think that is important for the problem I am about to describe).
If I specify that I want both projects to use a dist directory for the typescript output, then the compiled files would end up under a different file path than is specified in the imports, which creates errors because of that the referenced files are not found.
After the compilation:
ts-monorepo
packages
myApp
dist <-- new folder from typescript compilation
GetHello
function.json
index.js <-- In file: import { sayHello } from '../../myLib/lib/greeter'; // gives error
host.json
GetHello
function.json
index.ts
package.json
tsconfig.json
myLib
dist <-- new folder from typescript compilation
lib
greeter.js
lib
greeter.ts
package.json
tsconfig.json
This would mean that it is important to keep the same folder structure after the compilation?
So I guess it would be an option to specify in both projects tsconfig.json that the outDir should be the original folder names, but inside of a new common e.g build folder?
// tsconfig.json for myApp
{
...
"outDir": "../build/myApp"
}
and
// tsconfig.json for myLib
{
...
"outDir": "../build/myLib"
}
Ending up in that all output is placed in the build folder:
ts-monorepo
packages
build <-- new typescript generated folder
myApp
host.json
GetHello
function.json
index.js <-- Now import { sayHello } from '../../myLib/lib/greeter'; is correct.
myLib
lib
greeter.js
myApp
GetHello
function.json
index.ts
package.json
tsconfig.json
myLib
lib
greeter.ts
package.json
tsconfig.json
Combining the output with Azure Function App conventions
If I somehow get the node_modules into the folders as well and if this would be a normal Node.js application, then node packages/build/myApp/GetHello/index.js would run locally, but it is not going to work as an Azure Function App. This is because by convention you need to have the host.json file in the root of the folder that gets deployed as a Function App and all functions needs to be folders that are direct children to that root folder. I basically need to deploy the build/myApp folder to the Function App, but then I cannot have myLib outside. And if I move myLib into myApp I need to rewrite all of the imports of files inside of myApp.
I have been thinking about maybe moving or combining the approach with some monorepo package level tools like npm workspaces but the ones that I have looked at works by creating symbolic links. Those links will still point to folders outside of the myApp folder and hence be broken after the deploy. ( Similar to this)
If anyone knows or have a suggestion on how to solve this scenario it would be greatly appreciated.