Hi, it's my first message here so first things fir...
# help
t
Hi, it's my first message here so first things first I wanted to say that SST looks absolutely awesome! I'm warming up to use it in a going-to-production project. Since I'm relatively new to CDK (and SST) I wanted to ask for a small bit of advice - so that I don't go straight into a rabbit whole right from beginning 😄 1. My app will be composed out of a. S3 bucket hosting a "widget-like" JS library (self contained react app that can be dropped onto any page to deliver certain functionality) - with CloudFront in front of it for performance b. Sample/demo-page referencing the widget - hosted from S3 bucket (bucket number 2 🙂 ) c. Api gateway endpoint reading data from yet another S3 bucket - this endpoint will serve data to the react app (JSON config that react app will need to work). Again CloudFront will be in front if this one I would like to have stack-per-feature-branch on top of some more "fixed" stages like staging & prod. I want to make sure that when I build the stack - it gets all of it's resources unique - I will need to move it to a seperate/tightly controlled AWS account for prod deployment - I want to ideally avoid asking for anything to be created manually - just change stage to prod, swap the AWS keys and deploy it there I need to do a bit of "plumbing" here: 1. React app needs to know what's the url of the api gateway when it's being built - it will be making calls to that endpoint in runtime 2. Sample/demo-page needs to know where is the bucket where react-app is stored Out of this the order looks a bit like this: Create API gateway (and underlying S3) -> Build react app -> Create S3 & deploy React app to it -> Create S3 and deploy demo-site to it (demo site is just bunch of static files). What's the best way to pass those variables around? Should each of those "stages" as I mentioned them above be a seperate stack? Should I then be deploying every stack individually? Not sure also where to plug the actual react app build. I ideally want to have a way to deploy the whole thing from local machine - so that I don't don't do all the plumbing in CI/CD (so that devs can quickly just boostrap another stack from local env and work on whatever crazy feature they need to add 🙂 ). Sorry for a whole wall of text 😛
f
Hi @Tomasz Sobczyk, 👋 welcome!
Are you putting all the resources (S3 buckets, API Gateway, etc) in the same stack?
In another words, do you just have 1 stack per stage?
t
Didn't make up my mind yet on that to be honest - I could go both ways - split it or keep it in one.
f
yeah, you’d definitely deploy all stacks in a stage in one shot by running
sst deploy
And you can deploy to 1 stage at a time like
sst deploy --stage dev
,
sst deploy --stage prod
, or even
sst deploy --stage pr23
t
One thing that was suggesting to me that I might want to split it was the fact that I need to build the react app with some outputs from the previous steps (provide it with url to api gateway)
My whole deploy could be series of multiple commands - I could create a shorthand npm command that would run all of it in one go - don't mind that
f
right.. i guess the API Gateway endpoint will go into your React app’s config file right?
t
yes
I started reading about cdk.CfnOutput as I guess that's a way in which I could pump out the outcome of building the API gateway into a file - which I could then use in ReactApp
f
Right, one way i’ve seen ppl do is that, they have a
cdk.CfnOutput
with the API endpoint, and they run
sst deploy --stage dev --outputs-file outputs.json
, then they grab the endpoint from
outputs.json
, sets that in React’s config, then deploys the React app.
t
makes sense
Splitting into stacks as we speak to get the ordering right 🙂
f
i haven’t thought this thru.. but it seems tricky to deploy both the API and React in one SST/CDK app, b/c packaging the React app is done at build time (before the API is deployed).
t
yeap, exactly - that's what I was suspecting - no worries - splitting the stacks deployment is not a big deal! I can deal with some internal complexities within the build process itself. Hard to expect that SST will be responsible to magically do a build of the react app in a certain way 😄
Thanks for you help @Frank! By the way - do you ever sleep? Looking at the pace you guys are running SST at - I guess not 😄
f
LOL i do have a messed up schedule😅
t
ok, going back to messing up my stacks 😄 thanks for your help!
f
But yeah we are working on an SPA construct.. this is the exact step we want to simply
havne’t really figured out a good approach yet
t
yeap reviewed all of the the ideas - I could definitely see there some things for myself (e.g. static site & spa)
f
maybe deploy the React app with the API Gateway together, and then update the React config with the deployed API endpoint after?
t
deploy api?
f
sorry, update the config with the deployed* API endpoint
I just made that up.. but we are experimenting with different approaches
t
ok so you mean push the whole thing out in the first place - but with "wrong" url - and then update it once I have it?
f
yeah
t
For dev box that would probably work - for prod - would mean a period of time with misconfiguration - and I will be deploying to a living and breathing ecosystem - with people hitting this thing literally around the clock (it's done for a global company)
on the other hand - for prod - I will have some good default value eventually (obviously I'm not gonna destroy the whole thing all the time in prod with redeployments) - so maybe I could piggy back on that fact
f
I mean if the API ednpoint has been deployed once, the React config would have the right config in the initial deploy
t
yeap correct. Once I have prod stage in place I could just provide that as a default value
f
but yeah.. not super clean
t
I'm up for working solutions - not perfect solutions 😉
I will definitely consider this one as well
o
I like the arch we use with the react app pointing to a static URL in prod, that’s hosted in Cloudfront. The deploy updates the api gateway endpoint in cloudfront. So there’s not a direct coupling between where the react app points and the API gateway.
t
nice! Didn't think about this bit 😄
o
We do it this way to host the UI and its API on the same domain using cloudfront and eliminate latency from CORS preflight requests
f
@Jay This looks neat. Let’s test this out for the SPA construct.
j
@Omi Chowdhury have you got more info you can share on the setup to use cloudfront in this way to remove CORS?
o
@Jack Fraser sure - nothing out of the ordinary really. I’ve got an S3 origin and a API Gateway origin (also a 3rd one that hosts a webhook) and a couple of behaviours that point to them
I’m using serverless and SEED to deploy, so once the API gateway is deployed, its host doesn’t change. In a previous version, we used to deploy a new stack with a new API gateway endpoint, and had some code that used cloudfront’s APIs to point the origin at the new API gateway
One gotcha I remember is that I had to set a behavior path in cloudfront that matches the stage in APIG (
/dev
in the screenshots). For some reason setting an origin path to point to the right APIG stage didn’t work. And I couldn’t get the new cache policies to work (Managed-CacheDisabled seemed ideal).
f
@Tomasz Sobczyk @Omi Chowdhury @Jack Fraser Hey guys, I’m taking a crack at the SPA construct. Like you guys mentioned in the thread, people currently have 1 app for the backend, and 1 app for the SPA. They would deploy their backend first, then copy over the deployed api url and other CF output to their SPA’s config file, and then deploy the SPA. We want to remove this manual step, so you can have just 1 app and the deployed URL automatically gets passed into the SPA construct. Can you take a quick look at the “Cross stack reference” section of the spec and let me know what you think? https://github.com/serverless-stack/serverless-stack/discussions/194
t
Hi @Frank - just in time! We're about to start implementation next week 😄 my colleague @Tomasz Michalak just joined the space - we will definitely take part in the discussions!
t
Hello, the second Tomek in the thread, so maybe we will help / write a feedback 🙂
Right now I’m checking your GH repository and reading documentation. I had some time last week to pass the guide - it’s really impressive, great job!
o
@Frank This makes a lot of sense. I’m not an SST user (yet!) so others would be better equipped to answer how well it fits into that workflow. I assume you’d be able to pass in different values depending on stage (so you can use a custom domain in prod, but the raw api gateway URL in dev)
f
@Tomasz Sobczyk @Tomasz Michalak Thanks guys! Is it a React app you are working on?
t
Hi @Frank, yes, basically the setup more less still stands as I originally described it. We might be simplifying things a bit and deploying the react app "widget" to the same s3 as the "demo" site - that way I could reference the js of the react app as relative url from demo page. Having said that the main requirement would be to allow dynamically passing the url to the config endpoint ( which is a lambda with api gateway in front of it and then cloudfront distriburion in front of api gateway) to the react app. I want every stack to be a sell contained thing, so that a developer can simply deploy the whole thing and work in complete isolation, amd then when I wanna create staging / prod it is simply a new stack. One requirement that I will have in front of me will be that production urls will be "fixed", I will create prod stage once and then ask my client to point predefined dns entries (lets say api-app.customer.com etc) to aws resources. Effectively I want to be able to pass things around dynamically but then also to say if stage == prod then use fixed urls. Hope this makes sense. If not gimme a shout, once I put kids to bed I can try to draw some Pictures of the architecture
f
That makes a lot of sense. The Problem
main requirement would be to allow dynamically passing the url to the config endpoint
This is not supported by CDK out of the box. CDK currently works like this: 1. zips up the React build and uploads to a temporary S3 location 2. deploys API stack’s CF template 3. deploys SPA stack’s CF template (CDK adds a custom resource implemented in Lambda that will download the React build from the temporary S3 locations, unzip it, and syncs it to the static website S3 bucket) So on the first deploy, React app doesn’t know the URL b/c it is built and zipped up (in step 1) before the API is deployed (in step 2). The Solution And our proposed solution is that in you use a placeholder for the API url, ie.
{{ SST_API_URL }}
in your React app. And in Step 3, SST asks the custom resource Lambda function to replace
{{ SST_API_URL }}
with the deployed API url in Step 2. You define the SPA construct like this:
Copy code
new sst.Spa(this, "SPA", {
  indexPage: "index.html",
  bucket: "my-spa-bucket",
  replaceValues: [
    {
      file: "*.js",
      str: "{{ SST_API_URL }}",
      newStr: this.stage === "prod"
        ? "<http://api-app.customer.com|api-app.customer.com>"
        : api.url, // api is the sst.Api construct from another stack
    },
  ],
});
Does this make sense? And are you comfortable with this implementation?
t
Yes this sounds good for me at this stage. I see replace values is an array so I assume I could do more than one of those replacements if needed
f
Yup, correct.
t
Happy to give it a try even from a feature branch if you will have it around any time soon. I don't want to even go to copy past ing solution :) that kills the whole idea of feature branch stacks which I wanna have (with GH actions spinning up stuff on demand)
f
Yup, totally! We should have something soon.
t
The SPA construct looks promising, however the entire development process requires some new best practices such as directory structure, React application updates, common development environment for front-end and back-end (or maybe it is not the case).
@Tomasz Sobczyk what is your opinion?
Hi @Frank, We have an issue:
Copy code
➤ YN0000: Preparing your SST app
➤ YN0000: Detected tsconfig.json
➤ YN0000: Transpiling source
➤ YN0000: Running type checker
➤ YN0000: /bin/sh: .../forms-widget/.yarn/cache/typescript-patch-70a7929abf-3be4431759.zip/node_modules/.bin/tsc: Not a directory
during
yarn run build
. We use Yarn 2, and it looks that there is some issue with TS & PnP. We use Yarn workspaces as we split the application to different modules. In the React module, which also uses TS, we have no issue, it ends with:
Copy code
➤ YN0000: Creating an optimized production build...
➤ YN0000: Compiled successfully.
➤ YN0000: 
➤ YN0000: File sizes after gzip:
➤ YN0000: 
➤ YN0000:   41.34 KB  build/static/js/2.ad6aac36.chunk.js
➤ YN0000:   1.63 KB   build/static/js/3.776157f8.chunk.js
➤ YN0000:   1.17 KB   build/static/js/runtime-main.115d915c.js
➤ YN0000:   597 B     build/static/js/main.2c885fb9.chunk.js
➤ YN0000:   574 B     build/static/css/main.9d5b29c0.chunk.css
➤ YN0000: 
➤ YN0000: The project was built assuming it is hosted at /.
➤ YN0000: You can control this with the homepage field in your package.json.
➤ YN0000: 
➤ YN0000: The build folder is ready to be deployed.
➤ YN0000: You may serve it with a static server:
➤ YN0000: 
➤ YN0000:   npm install -g serve
➤ YN0000:   serve -s build
Any suggestions?
When using
npm install
and
npm run build
, the result is correct:
Copy code
Successfully compiled 1 stack to .build/cdk.out:

  dev-json-schema-transformer-my-stack
f
@Tomasz Michalak I see. Let me take a look.
t
It is easy to reproduce, I can share an example with GitHub, but tomorrow. I believe that the issue is connected with TS code, I have not checked JS version.
f
I see. I will give yarn v2 a try with the TS code.
So I did a brief test with yarn v2, I’m not even able to create an SST app. Running
Copy code
yarn create serverless-stack my-sst-app --language typescript --use-yarn
resulted in the error:
Copy code
Internal Error: root-workspace-0b6124@workspace:.: This package doesn't seem to be present in your lockfile; try to make an install to update your resolutions
Yarn v2 expects the project to have a
yarn.lock
file, which the SST template app doesn’t have.
Just curious, how did u managed the create the app? Did you create the app with yarn v1 and recently updated to v2?
t
Yes, we generated both React and Lambda modules with Yarn 1 and then switched to the Yarn 2 and Yarn workspaces as we wanted one dependency source (I have no opinion if this is a good choice to make these modules dependent on each other).
f
Yeah, I don’t see why that’s a bad choice.
I opened an issue for yarn 2 support here - https://github.com/serverless-stack/serverless-stack/issues/381
Is this blocking you guys? Can you use npm/yarn 1 for now?
t
nah - we're good for now with yarn 1
@Frank: How is it going with SPA construct?
f
Hey @Tomasz Sobczyk there were a bit of confusion in the way how the SPA construct is going to work. @Tomasz Michalak suggested in the discussion that on
sst start
, use invoke the deployed static website URL, the request gets proxied to your local machine, and fetches the js/html/css resources on your local machine. Instead, I was thinking to keep SST and React loosely coupled. I explained what I had in mind in the comment. Let me know if that makes sense. I’m hoping to have something ready by next week.
t
Thanks for response. I will go through the discussion and add my thoughts.
Hi @Frank - just dropped a note to the discussion - sorry for a massive lag - we kicked off the project - and had a lot of other stuff on my plate.
Just small FYI - in the absence of your much anticipated SPA construct -we've hacked things around with a good old bash script and a aws cloudformation describe-stacks cli 😄 throwing urls all over the place from one stack to another 😄
f
Hey @Tomasz Sobczyk No worries! I just release the construct today, calling it
StaticSite
. We ended up not doing the auto-replacing frontend config for now. The proposed solution in the discussion didn’t feel too clean using it. We will continue to look for a better solution.
The
StaticSite
is fairly simple with a couple of features: • the ability to redirect from an alias domain (ie. www.domain.com) to the main domain (ie. domain.com) • redirect http to https • specify a bulid command, and the frontend will be built by CDK
Hey @Tomasz Michalak @Tomasz Sobczyk, just wanted to keep you posted that I just released v0.29.1 with some improvements to `StaticSite`: • You can configure different 
cacheControl
 settings to different files. For example, don’t cache 
*.html
 and cache 
*.css *.js
 forever. Example here - https://docs.serverless-stack.com/constructs/StaticSite#configure-caching
StaticSite
 now does atomic deploys. Each deployment gets deployed to a new folder in S3 bucket. So you won’t have orphan files from previous deployments. • You can specify a list of glob patterns, with the search and replace terms for each. Example here - https://docs.serverless-stack.com/constructs/StaticSite#replace-deployed-values
So with this update, you can now replace 
{{ API_ENDPOINT }}
 in ur React config with the deployed endpoint automatically.
t
Hi Frank, we are now focusing on the business features in the project but for sure we would come back with the feedback soon, thanks!
t
Yeap, currently pretty deep into delivering the project. For the time being we have split everything into 3 stacks and a bit of magical bash scripting to pass stuff around :) I am hoping that we will find some time soon to merge it all back into one stack :)
Deployment times currently are bit annoying :D
f
Which step takes long for you? Updating CloudFront distribution?
Hey @Tomasz Michalak @Tomasz Sobczyk! Just want to keep you posted that we added a
ReactStaticSite
construct. It supports React environment variables. Ie.
process.env.REACT_APP_API_URL
in your React app can get automatically replaced with the deployed Api endpoint. You can read more about how it works here - https://docs.serverless-stack.com/constructs/ReactStaticSite
t
We are currently in the moment of the first production release. After go-live we will have some time to test it :)
f
Sounds good! It’s based on our prior discussion in GitHub. Thank you guys for helping designing it!