I’m using StaticSite for one Angular app, I used r...
# sst
g
I’m using StaticSite for one Angular app, I used replaceValues property to fill all environment variables (userpool id, api endpoint, regions, and much more). When I run
npx sst deploy
everything works great but when I run
npx sst start
app is unreachable (it show me the sst page which say to run static site locally). So I run
npx ng serve
to run angular locally, but. it doesn’t work because all environment variables are not filled to properly values. All environment variables in angular are defined in two file (one for prod) which is called environments.ts:
export const environment = {
production: false,
API_BASE_PATH:                '{{ API_DOMAIN }}',
IDENTITY_POOL_ID:             '{{ IDENTITY_POOL_ID }}',
IDENTITY_POOL_REGION:         '{{ IDENTITY_POOL_REGION }}',
USER_POOL_ID:                 '{{ USER_POOL_ID }}',
USER_POOL_WEB_CLIENT_ID:      '{{ USER_POOL_WEB_CLIENT_ID }}',
USER_POOL_REGION:             '{{ USER_POOL_REGION }}',
BUCKET_NAME:                  '{{ BUCKET_NAME }}',
BUCKET_REGION:                '{{ BUCKET_REGION }}'
};
I have two question: 1. Which is the way to run properly an angular app? 2. Why SST doesn’t implement a short way (included in sst start) to serve a local site (maybe specifying external tool command)?
t
There is a cli tool to get the environment variables and make them available to your angular app! https://docs.serverless-stack.com/packages/static-site-env I also had a similar idea, that specifying a dev command for the staticsite construct would be useful https://serverless-stack.slack.com/archives/C01HQQVC8TH/p1634663411001000
r
Does that work for angular? It puts them on the node environment for react? We actually do this in our
environment.ts
for Angular
import * as config from '../../../sst/.build/static-site-environment-output-values.json';
and then specify them in the environment parameter of the StaticSite construct. eg.
Copy code
new sst.StaticSite(this, "frontend", {
      ...
      environment: {
        "#{userPoolId}": userPoolStack.userPoolId,
      },
      replaceValues: [
        {
          files: '*.js',
          search: '#{userPoolId}',
          replace: userPoolStack.userPoolId,
        }
    }
It does double up, we could fix that with a little javascript, but it then works for local dev and deployments
Actually, looking here, you don't need to double up, you can assume it replaces inside {{ $key }} in index.html and *.js files https://github.com/serverless-stack/serverless-stack/blob/1cf6dabfc7538b5f6cadf088c74771505a53da1e/packages/resources/src/StaticSite.ts#L610 Not sure if it works, but I gather that's what it does
f
Hey @gio
1. Which is the way to run properly an angular app?
Angular seems to use
environment.ts
files instead of
process.env
for environment variables. This seems to be the only workaround I found, which generates the
environment.ts
file from
process.env
variables. The
package.json
will look something like:
Copy code
"scripts": {
  "config": "ts-node ./scripts/set-env.ts",
  "serve": "npm run config -- --environment=dev && ng serve --environment=dev",
  "build": "npm run config -- --environment=prod && ng build --environment=prod",
  "start": "sst-env -- npm run serve",
}
2. Why SST doesn’t implement a short way (included in sst start) to serve a local site (maybe specifying external tool command)?
I know @thdxr mentioned that he didn’t feel comfortable having a long run process
sst start
spawning another long running process. I will let Dax chime in.
r
Is there any downside to doing it this way?
environment.ts
Copy code
import * as config from '../../../sst/.build/static-site-environment-output-values.json';

export const environment = {
  production: false,
  bucketUrl: config[0].environmentOutputs["bucketUrl"],
  userPoolClientId: config[0].environmentOutputs["userPoolClientId"],
  userPoolId: config[0].environmentOutputs["userPoolId"],
  ApiEndpoint: config[0].environmentOutputs["apiEndpoint"],
};
The only problem I've found is that in our folder structure, the json file doesn't get watched properly by the angular builder, so sometimes I have to
touch
the
environment.ts
for it to pick up the changed environment. It also has the benefit of being able to start up the parallel to
sst start
and not require relaunching if you change anything on the environment.
g
@Ryan your workaround works when sst is started, when I try to run
sst deploy
I receive this error:
ERROR in src/environments/environment.ts(1,25): error TS2307: Cannot find module '../../../../.build/static-site-environment-output-values.json'.
Error: There was a problem building the "BackOffice" StaticSite.
@Frank thanks for your suggestion, I give a try soon, if works it could be a nice feature to implement in a specific AngularStaticSite constructor
@Ryan I applied this fix to make work sst deploy:
let config;
try {
config = require('../../../../.build/static-site-environment-output-values.json');
} catch {
<http://console.info|console.info>('configuration file not found');
}
export const environment = {
production:               config ? config[0].environmentOutputs["STAGE"] === 'prod'         : '{{ STAGE }}',
API_BASE_PATH:            config ? config[0].environmentOutputs["API_DOMAIN"]               : '{{ API_DOMAIN }}',
IDENTITY_POOL_ID:         config ? config[0].environmentOutputs["IDENTITY_POOL_ID"]         : '{{ IDENTITY_POOL_ID }}',
IDENTITY_POOL_REGION:     config ? config[0].environmentOutputs["IDENTITY_POOL_REGION"]     : '{{ IDENTITY_POOL_REGION }}',
USER_POOL_ID:             config ? config[0].environmentOutputs['USER_POOL_ID']             : '{{ USER_POOL_ID }}',
USER_POOL_WEB_CLIENT_ID:  config ? config[0].environmentOutputs['USER_POOL_WEB_CLIENT_ID']  : '{{ USER_POOL_WEB_CLIENT_ID }}',
USER_POOL_REGION:         config ? config[0].environmentOutputs['USER_POOL_REGION']         : '{{ USER_POOL_REGION }}',
BUCKET_NAME:              config ? config[0].environmentOutputs['BUCKET_NAME']              : '{{ BUCKET_NAME }}',
BUCKET_REGION:            config ? config[0].environmentOutputs['BUCKET_REGION']            : '{{ BUCKET_REGION }}'
};
And in sst definition:
environment: {
STAGE: app.stage,
`API_DOMAIN:
https://${refs.backoffice_api_domain.name}
,`
IDENTITY_POOL_ID: refs.admin_pool.cognitoIdentityPoolId,
IDENTITY_POOL_REGION: app.region,
USER_POOL_REGION: app.region,
USER_POOL_ID: refs.admin_pool.cognitoUserPool?.userPoolId as string,
USER_POOL_WEB_CLIENT_ID: refs.admin_pool.cognitoUserPoolClient?.userPoolClientId as string,
BUCKET_NAME: refs.admins_storage_bucket.bucketName,
BUCKET_REGION: app.region
},
replaceValues: [
{
files: "**/*.js",
search: "{{ API_DOMAIN }}",
`replace:
https://${refs.backoffice_api_domain.name}
,
Copy code
},`
{
files: "**/*.js",
search: "{{ IDENTITY_POOL_ID }}",
replace: refs.admin_pool.cognitoIdentityPoolId,
},
{
files: "**/*.js",
search: "{{ IDENTITY_POOL_REGION }}",
replace: app.region,
},
{
files: "**/*.js",
search: "{{ USER_POOL_REGION }}",
replace: app.region,
},
{
files: "**/*.js",
search: "{{ USER_POOL_ID }}",
replace: refs.admin_pool.cognitoUserPool?.userPoolId as string,
},
{
files: "**/*.js",
search: "{{ USER_POOL_WEB_CLIENT_ID }}",
replace: refs.admin_pool.cognitoUserPoolClient?.userPoolClientId as string,
},
{
files: "**/*.js",
search: "{{ BUCKET_NAME }}",
replace: refs.admins_storage_bucket.bucketName,
},
{
files: "**/*.js",
search: "{{ BUCKET_REGION }}",
replace: app.region,
}
]
It doesn’t look good of course, I try to follow the guide suggested by Frank
r
Ahh, nice workaround. I usually deploy the prod build which doesn't reference the file.