Hi there, I decided to choose SST as my primary fr...
# sst
f
Hi there, I decided to choose SST as my primary framework for building big new monorepo project. I have 5+ years of validated experience with building big monorepo project based on Serverless Framework, but I wanted to upgrade to something more modern. I started to prepare the monorepo and I stumbled upon a many issues and questions, but now I want to discuss the one which would probably require a code modification of SST. Use case: I have a monorepo managed via NPM workspaces feature. I want to import a file from other package
Copy code
import { someFunction } from '@packages/some-package' // or import from '../../packages/some-package' - it's is the same in this case

export const handler = async (event) => {
	someFunction('hello')
    return '123'
}
Then I start the debugging session with
$ sst start
When I change the file of the lambda function handler, I can see in the terminal info message:
Copy code
Functions: Building api functions/lambda.handler...
Functions: Done building api functions/lambda.handler (101ms)
And everything works great so far. πŸ‘ The problem: When I change a file inside the package
@packages/some-package
which is located in completely different folder (
../../packages/some-package
), no reload/recompilation happens and the application is still using the old source code of the package. How I hacked it and fixed it: When I did the reverse engineering, I found out that here: https://github.com/serverless-stack/serverless-stack/blob/9d8cc00da72942ef39348b25ff993117e502f30f/packages/core/src/runtime/watcher.ts and here: https://github.com/serverless-stack/serverless-stack/blob/9d8cc00da72942ef39348b25ff993117e502f30f/packages/core/src/runtime/handler/node.ts#L2[…]24 the SST is defining which files it will be watching. When I added to the list path to my packages folder, it started to work βœ… What do you think would be the best way how to address this issue? I’m happy to contribute. πŸ™‚ Thanks.
t
Are you using TS or js?
If using TS we recommend using package aliases instead of discrete seperate packages on the backend. There's a lot you lose when doing that and little gained. Either way let me take a look at this issue
Think I know how to fix
f
Sorry, I forgot to mention, I use TypeScript. Can you please send me some reference/docs/article regarding the package aliases? I will take a look into that.
Check this out, there's seemingly two packages, core + api but just implemented via aliases in tsconfig. This still allows editors to bulk rename things across "packages"
f
I tried it, but it doesn’t seem to fix the issue. (Let me know if it was supposed to fixed the issue.) Only difference I can see there, is that it doesn’t need to have it’s own
package.json
. Or is there something more to it? Some faster compile times or something like that?
t
The src path is set to API here so everything in it should be watched
Also curious in your current setup, if you have TS in both packages don't you need the dependecy package to be built first? Or are you pointing main to a TS file
f
Here is my file structure
Copy code
.
β”œβ”€β”€ api
β”‚   β”œβ”€β”€ functions
β”‚   β”‚   └── lambda.ts // this is the Lambda
β”‚   β”œβ”€β”€ package.json
β”‚   β”œβ”€β”€ schema.graphql
β”‚   └── tsconfig.json
β”œβ”€β”€ frontend
β”‚   β”œβ”€β”€ README.md
β”‚   β”œβ”€β”€ next-env.d.ts
β”‚   β”œβ”€β”€ next.config.js
β”‚   β”œβ”€β”€ package.json
β”‚   β”œβ”€β”€ public
β”‚   β”œβ”€β”€ styles
β”‚   └── tsconfig.json
β”œβ”€β”€ package-lock.json
β”œβ”€β”€ package.json
β”œβ”€β”€ packages
β”‚   └── some-package
β”‚       β”œβ”€β”€ package.json
β”‚       β”œβ”€β”€ src
β”‚       β”‚   └── index.ts
β”‚       └── tsconfig.json
β”œβ”€β”€ sst.json
β”œβ”€β”€ stacks
β”‚   β”œβ”€β”€ API.ts
β”‚   β”œβ”€β”€ Frontend.ts
β”‚   └── index.ts
β”œβ”€β”€ tsconfig.json
└── vitest.config.ts
There are two services - API an Frontend - which are split into two SST stacks. Workspaces configuration
Copy code
"workspaces": [
	"api",
	"frontend",
	"packages/*"
],
So the
some-package
package is not inside the
api
and that’s the reason why the changes are not captured. And because in future there will be more backend services/stacks (containing Step Functions, DynamoDB tables etc.) I want to be able to use the packages inside all the backend services (=stacks) - not just in the API.
t
I'm suggesting to put the shared package inside the API package
And use a package alias to make it look like a real package
Otherwise you lose some TS functionality, it can't do full type analysis between real packages
You can rename the API folder to something like Backend if you feel like it's inaccurate
It's meant to house all the code for all your node stuff
In the example my
core
folder is the same as your
some-package
folder
I'll fix your issue either way but just pointing out there's a reason we didn't make every shared module a real package
f
How does SST knows that the
api
folder is the base folder? It it because I use set it inside the stack?
Copy code
export function ApiStack({ stack }: StackContext): void {
	stack.setDefaultFunctionProps({
		srcPath: 'api'
	})
t
That's right
f
Well, then if I rename the
api
folder to
backend
. let’s say I set it in the stack like this:
Copy code
export function ApiStack({ stack }: StackContext): void {
	stack.setDefaultFunctionProps({
		srcPath: 'backend'
	})
then I will have to address my API like this:
Copy code
new AppSyncApi(stack, 'GraphqlApi', {
    schema: 'api/schema.graphql',
    dataSources: {
        notesDS: 'api/functions/lambda.handler',
        notesDS1: 'api/functions/lambda.handler',
        notesDS2: 'api/functions/lambda.handler',
        notesDS3: 'api/functions/lambda.handler',
        notesDS4: 'api/functions/lambda.handler',
        notesDS5: 'api/functions/lambda.handler',
        notesDS6: 'api/functions/lambda.handler',
    },
    resolvers: {
        'Query    listNotes': 'notesDS',
    }
})
which means that I will have to include the
api
folder prefix in all file names. and then when I will want to create another stack
Copy code
export function OtherStack({ stack }: StackContext): void {
	stack.setDefaultFunctionProps({
		srcPath: 'backend'
	})
and have source files inside
backend/otherApi
It will have to have the folder also in the file names:
Copy code
new AppSyncApi(stack, 'GraphqlApi', {
    schema: 'otherApi/schema.graphql',
    dataSources: {
        notesDS: 'otherApi/functions/lambda.handler',
        notesDS1: 'otherApi/functions/lambda.handler',
        notesDS2: 'otherApi/functions/lambda.handler',
        notesDS3: 'otherApi/functions/lambda.handler',
        notesDS4: 'otherApi/functions/lambda.handler',
        notesDS5: 'otherApi/functions/lambda.handler',
        notesDS6: 'otherApi/functions/lambda.handler',
    },
    resolvers: {
        'Query    listNotes': 'notesDS',
    }
})
And in that case, it seems like the default
srcPath
β€œsugar” is not that helpful anymore. So I tried to do change the default
srcPath
to
.
Copy code
export function ApiStack({ stack }: StackContext): void {
	stack.setDefaultFunctionProps({
		srcPath: '.'
	})
and that makes my current setup with the packages reloading work fine πŸ™‚ πŸ‘ So let me try to work with it a bit, so that I can check whether everything works for me in such setup.
t
yeah the
srcPath
is more than just an alias, it's actually used by sst to understand where your project "starts"
f
Is it okay if I set
srcPath
to
.
? Aren’t there going to be any issues like β€œCDK code vs. the lambda code” or something like that? I will rather create the
backend
folder and move all the stuff there.. so that I can make sure that correct tsconfig etc. is being used there. So I will do it as you’ve suggested πŸ™‚ πŸ‘
t
and it generally expects everything dependent to be within it
yeah you can remove srcPath but I think this might have issues in monorepos
f
And big thanks for such a quick and in-depth response @thdxr such chat really boosts the adoption and the learning curve for people with some former Serverless experience. πŸ™‚ Keep it up and expect more questions from me! πŸ˜πŸ‘ πŸ‘
t
after this convo we decided to rename
api
to
services
to avoid the confusion