My issue here is incredibly similar if not exactly the same as the one outlined in this issue. Unfortunately, I haven't been able to resolve it using the strategy it provides. So here are my own details:
I am using Create React App, React Router 4, Express, and Heroku and have followed the instructions here with regards to setting up a server with CRA.
Locally, I am able to access routes such as myapp/about, yet after building and pushing to heroku, these 404.
I can navigate to this route via the UI (i.e. by clicking on a menu item that pushes a route onto history), yet am unable to navigate to this route using only my browser's address bar. Furthermore, when I navigate using the UI, I'm not seeing any network activity related to the route such as an /about request. Yet when I change the address bar and hit enter, this yields a network request to said route.
Here are some select snippets from my code:
app.js
<Switch>
<Route exact path="/about" component={About} />
<Route path="/"
render={props => <coolListContainer {...props}/>} />
</Switch>
server.js
if (process.env.NODE_ENV === 'production') {
app.use(express.static('client/build'));
}
//...what some of my api routes look like:
app.route('/api/verify')
.post( async (req, res) => {
try {
await db.verifyCode(req.body)
res.json('success')
} catch (err) {
res.json(err);
}
}
});
My directory structure as provided by full-stack-react`'s express demo.
└── myapp
├── Procfile
├── README.md
├── client
│ ├── build
│ │ ├── asset-manifest.json
│ │ ├── index.html
│ │ └── static
│ │ ├── css
│ │ │ ├── main.e8c50ca0.css
│ │ │ └── main.e8c50ca0.css.map
│ │ └── js
│ │ ├── main.24fe0ebe.js
│ │ └── main.24fe0ebe.js.map
│ ├── package.json
│ ├── public
│ │ └── index.html
│ ├── src
│ │ ├── About.js
│ │ └── index.js
│ └── styles
│ └── about..css
├── package.json
├── server.js
└── static.json
Per answer given to this post, I've also plopped a static.json file into the root directory.
static.json
{
"root": "client/build/",
"clean_urls": false,
"routes": {
"/**": "index.html"
}
}
The above configuration gives me 404s on any route.
Alrighty, I figured this out.
All I needed was to ensure that any request not relevant for my internal API, such as a GET request via the address bar, is routed directly to my index.html file which handles the dynamic routing via React Router. Seems obvious enough now.
Here is the final route in my app.js:
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, '/client/build/index.html'));
});
Related
I try to get static file to using 'python manage.py collectstatic', but it's not working.
I run my django project in Ubuntu 20.04.4, and using Nginx as a webserver, and Guicorn for WSGI server.
Here is my error log,
You have requested to collect static files at the destination
location as specified in your settings.
This will overwrite existing files!
Are you sure you want to do this?
Type 'yes' to continue, or 'no' to cancel: yes
Traceback (most recent call last):
File "manage.py", line 22, in <module>
main()
File "manage.py", line 18, in main
execute_from_command_line(sys.argv)
File "/home/devadmin/venvs/bio_platform/lib/python3.8/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
utility.execute()
File "/home/devadmin/venvs/bio_platform/lib/python3.8/site-packages/django/core/management/__init__.py", line 440, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/devadmin/venvs/bio_platform/lib/python3.8/site-packages/django/core/management/base.py", line 414, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/devadmin/venvs/bio_platform/lib/python3.8/site-packages/django/core/management/base.py", line 460, in execute
output = self.handle(*args, **options)
File "/home/devadmin/venvs/bio_platform/lib/python3.8/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 209, in handle
collected = self.collect()
File "/home/devadmin/venvs/bio_platform/lib/python3.8/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 135, in collect
handler(path, prefixed_path, storage)
File "/home/devadmin/venvs/bio_platform/lib/python3.8/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 368, in copy_file
if not self.delete_file(path, prefixed_path, source_storage):
File "/home/devadmin/venvs/bio_platform/lib/python3.8/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 278, in delete_file
if self.storage.exists(prefixed_path):
File "/home/devadmin/venvs/bio_platform/lib/python3.8/site-packages/django/core/files/storage.py", line 362, in exists
return os.path.lexists(self.path(name))
File "/home/devadmin/venvs/bio_platform/lib/python3.8/site-packages/django/contrib/staticfiles/storage.py", line 39, in path
raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: You're using the staticfiles app without having set the STATIC_ROOT setting to a filesystem path.
I found the many solution from google, and i guessing that it cause because i didn't set a STATIC_ROOT properly.
Here is my project dir structure and code below;
└── bio_platform
├── common
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-310.pyc
│ │ ├── __init__.cpython-38.pyc
│ │ ├── __init__.cpython-39.pyc
│ │ ├── admin.cpython-310.pyc
│ │ ├── admin.cpython-38.pyc
│ │ ├── admin.cpython-39.pyc
│ │ ├── apps.cpython-310.pyc
│ │ ├── apps.cpython-38.pyc
│ │ ├── apps.cpython-39.pyc
│ │ ├── forms.cpython-310.pyc
│ │ ├── forms.cpython-38.pyc
│ │ ├── forms.cpython-39.pyc
│ │ ├── models.cpython-310.pyc
│ │ ├── models.cpython-38.pyc
│ │ ├── models.cpython-39.pyc
│ │ ├── urls.cpython-310.pyc
│ │ ├── urls.cpython-38.pyc
│ │ ├── urls.cpython-39.pyc
│ │ ├── views.cpython-310.pyc
│ │ ├── views.cpython-38.pyc
│ │ └── views.cpython-39.pyc
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── migrations
│ │ ├── __init__.py
│ │ └── __pycache__
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── config
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-310.pyc
│ │ ├── __init__.cpython-38.pyc
│ │ ├── __init__.cpython-39.pyc
│ │ ├── settings.cpython-310.pyc
│ │ ├── settings.cpython-38.pyc
│ │ ├── settings.cpython-39.pyc
│ │ ├── urls.cpython-310.pyc
│ │ ├── urls.cpython-38.pyc
│ │ ├── urls.cpython-39.pyc
│ │ ├── wsgi.cpython-310.pyc
│ │ ├── wsgi.cpython-38.pyc
│ │ └── wsgi.cpython-39.pyc
│ ├── asgi.py
│ ├── settings
│ │ ├── __pycache__
│ │ ├── base.py
│ │ ├── local.py
│ │ └── prod.py
│ ├── urls.py
│ └── wsgi.py
├── db.sqlite3
├── manage.py
├── node_modules
│ └── bootstrap
│ ├── LICENSE
│ ├── README.md
│ ├── dist
│ ├── js
│ ├── package.json
│ └── scss
├── package-lock.json
├── pybo
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-310.pyc
│ │ ├── __init__.cpython-38.pyc
│ │ ├── __init__.cpython-39.pyc
│ │ ├── admin.cpython-310.pyc
│ │ ├── admin.cpython-38.pyc
│ │ ├── admin.cpython-39.pyc
│ │ ├── apps.cpython-310.pyc
│ │ ├── apps.cpython-38.pyc
│ │ ├── apps.cpython-39.pyc
│ │ ├── forms.cpython-310.pyc
│ │ ├── forms.cpython-38.pyc
│ │ ├── forms.cpython-39.pyc
│ │ ├── models.cpython-310.pyc
│ │ ├── models.cpython-38.pyc
│ │ ├── models.cpython-39.pyc
│ │ ├── urls.cpython-310.pyc
│ │ ├── urls.cpython-38.pyc
│ │ ├── urls.cpython-39.pyc
│ │ └── views.cpython-310.pyc
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_question_author.py
│ │ ├── 0003_answer_author.py
│ │ ├── 0004_answer_modify_date_question_modify_date.py
│ │ ├── 0005_comment.py
│ │ ├── 0006_answer_voter_question_voter_alter_answer_author_and_more.py
│ │ ├── 0007_auto_20220411_1325.py
│ │ ├── __init__.py
│ │ └── __pycache__
│ ├── models.py
│ ├── templatetags
│ │ ├── __pycache__
│ │ └── pybo_filter.py
│ ├── tests.py
│ ├── urls.py
│ └── views
│ ├── __pycache__
│ ├── answer_views.py
│ ├── base_views.py
│ ├── comment_views.py
│ ├── question_views.py
│ └── vote_views.py
├── static
│ ├── bootstrap.min.css
│ ├── bootstrap.min.js
│ ├── jquery-3.6.0.min.js
│ └── style.css
├── templates
│ ├── base.html
│ ├── common
│ │ ├── login.html
│ │ └── signup.html
│ ├── form_errors.html
│ ├── navbar.html
│ └── pybo
│ ├── answer_form.html
│ ├── comment_form.html
│ ├── question_detail.html
│ ├── question_form.html
│ └── question_list.html
└── winehq.key
As you could notice, i divide my setting files like this,
It because i'd like to operate Server development environment and Local development environment separately.
├── settings
│ │ ├── __pycache__
│ │ ├── base.py
│ │ ├── local.py
│ │ └── prod.py
And here is my full code of setting files
(I blanked the private parts which is like IP address).
base.py
"""
Django settings for config project.
Generated by 'django-admin startproject' using Django 4.0.3.
For more information on this file, see
https://docs.djangoproject.com/en/4.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.0/ref/settings/
"""
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'blank' #private part
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['blank'] #private part
# Application definition
INSTALLED_APPS = [
'common.apps.CommonConfig',
'pybo.apps.PyboConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'config.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'config.wsgi.application'
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/4.0/topics/i18n/
LANGUAGE_CODE = 'ko-kr'
TIME_ZONE = 'Asia/Seoul'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/
STATIC_URL = 'static/'
#STATIC_ROOT = os.path.join(BASE_DIR,'static')
STATICFILES_DIRS = [
BASE_DIR / 'static',
]
# Default primary key field type
# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'
local.py
from .base import *
ALLOWED_HOSTS = []
prod.py
from .base import *
import os
ALLOWED_HOSTS = ['blank'] #private part
STATIC_URL = 'static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
#STATIC_ROOT = BASE_DIR / 'static/'
STATICFILES_DIRS = []
# concept addon
Also, here is my bio_platform.service for nignx server.
bio_platform.service
server {
listen 80;
server_name blank; #private part
location = /favicon.ico { access_log off; log_not_found off; }
location /static {
alias /home/devadmin/projects/bio_platform/static;
}
location / {
include proxy_params;
proxy_pass http://unix:/tmp/gunicorn.sock;
}
}
I did some of solution that given in google and stackoverflow also which is like:
what i try
set a STATIC_ROOT and STATIC_URL on prod.py
set a STATIC_ROOT and STATIC_URL on base.py
But as you know, it didn't work and django.core.exceptions.ImproperlyConfigured: You're using the staticfiles app without having set the STATIC_ROOT setting to a filesystem path. error is still remain.
For know, i'm not sure where sould i set STATIC_ROOT or STATIC_URL, STATICFILES_DIR.
Please helpe me guys....
I did found what i wrong in my project.
The problem was caused by path setting which is bring prod.py settings automaticly from venvs folder.
I made a bio_platform.sh file under the path
~/venvs/
before
#!/bin/bash
cd ~/projects/bio_paltform
export DJANGO_SETTINGS_MODULE=config.settings.prod
. ~/venvs/bio_paltform/bin/activate
As you guys could see that i typed wrong that bio_paltform.
So i change the bio_paltform to bio_platform.
after
#!/bin/bash
cd ~/projects/bio_platform
export DJANGO_SETTINGS_MODULE=config.settings.prod
. ~/venvs/bio_platform/bin/activate
After i modify this file, python managy.py collectstatic order is work.
$ python manage.py collectstatic
You have requested to collect static files at the destination
location as specified in your settings:
/home/devadmin/projects/bio_platform/static
This will overwrite existing files!
Are you sure you want to do this?
Type 'yes' to continue, or 'no' to cancel: yes
128 static files copied to '/home/devadmin/projects/bio_platform/static'.
I have a terragrunt project like this
├── common_vars.hcl
├── envs
│ ├── dev
│ │ ├── env_vars.hcl
│ │ ├── rds-aurora
│ │ │ └── terragrunt.hcl
│ │ ├── rds-sg
│ │ │ └── terragrunt.hcl
│ │ └── vpc
│ │ └── terragrunt.hcl
│ └── prod
│ ├── env_vars.hcl
│ ├── rds-sg
│ │ └── terragrunt.hcl
│ └── vpc
│ └── terragrunt.hcl
├── modules
│ ├── aws-data
│ │ ├── main.tf
│ │ └── outputs.tf
│ ├── rds-aurora
│ │ └── main.tf
│ ├── rds-sg
│ │ └── main.tf
│ └── vpc
│ └── main.tf
└── terragrunt.hcl
The rds-sg is the security group depends on the vpc.
The terragrunt.hcl under dev and prod has the same code like this.
terraform {
source = format("%s/modules//%s", get_parent_terragrunt_dir(), path_relative_to_include())
}
include {
path = find_in_parent_folders()
}
dependencies {
paths = ["../vpc"] # not dry
}
dependency "vpc" {
config_path = "../vpc" # not dry
}
inputs = {
vpc_id = dependency.vpc.outputs.vpc_id # if something changes or we need more inputs
}
As described in the comments, some codes are not so DRY. If I want to change something like change to another vpc or add more inputs, then I need to modify this file everywhere.
So I want something in the main.tf under modules
module "rds-sg" {
source = "terraform-aws-modules/security-group/aws//modules/mysql"
name = "${var.name_prefix}-db-sg"
description = "Security group for mysql 3306 port open within VPC"
vpc_id = ""
# I want something like
# vpc_id = dependency.vpc.outputs.vpc_id
}
Is that possible? or some better practices to solve this problem?
Thanks very much.
Maybe using terraform_remote_state can fix this problem. Any better idea?
This comment may explain this problem better.
https://github.com/gruntwork-io/terragrunt/issues/759#issuecomment-687610130
I would use Data sources to read any ID for any resources:
Add this to the module that uses VPC ID.
data "aws_vpc" "this" {
filter {
name = "tag:Name"
values = [var.name]
}
}
...
vpc_id = data.aws_vpc.this.id
This way you are making sure to read from AWS API not from State file, which has on plan validation also.
Prerequisite
this is my first usage of React/Node.JS/Azure App Service. I usually deploy apps using flask/jinja2/gunicorn.
The use case
I would like to use the environment variables stored in the Configuration of my App Service on Azure
Unfortunately, the environment variables displays 3 environment variables (NODE_END, PUBLIC_URL and FAST_REFRESH) instead of several dozens.
The partial content of the Azure App Service appsettings
[
{
"name": "REACT_APP_APIKEY",
"value": "some key",
"slotSetting": false
},
{
"name": "REACT_APP_APPID",
"value": "an app id",
"slotSetting": false
},
{
"name": "REACT_APP_AUTHDOMAIN",
"value": "an auth domain",
"slotSetting": false
},
{
"name": "APPINSIGHTS_INSTRUMENTATIONKEY",
"value": "something",
"slotSetting": false
},
{
"name": "APPLICATIONINSIGHTS_CONNECTION_STRING",
"value": "something else",
"slotSetting": false
},
{
"name": "ApplicationInsightsAgent_EXTENSION_VERSION",
"value": "some alphanumeric value",
"slotSetting": false
},
{
"name": "KUDU_EXTENSION_VERSION",
"value": "78.11002.3584",
"slotSetting": false
}
]
The CI/CD process
I am using Azure DevOps to build and deploy the app on Azure.
The process runs npm install and npm run build before generating the zip file containing the build (see the directory tree list here below)
How do I Run the App?
The startup command contains npx serve -l 8080 .
The Issue
I display the environment variables with
console.log('process.env', process.env);
The content of the process.env is
{
"NODE_ENV": "production",
"PUBLIC_URL": "",
"FAST_REFRESH": true
}
The Wired part
I use SSH on Azure and I run
printenv | grep APPINS the result is
APPSETTING_APPINSIGHTS_INSTRUMENTATIONKEY=something
APPINSIGHTS_INSTRUMENTATIONKEY=something
printenv | grep APPLICATION the result is
APPSETTING_APPLICATIONINSIGHTS_CONNECTION_STRING=something else
APPLICATIONINSIGHTS_CONNECTION_STRING=something else
Misc
Directory Tree list
.
├── asset-manifest.json
├── favicon.ico
├── images
│ ├── app
│ │ └── home_page-ott-overthetop-platform.png
│ ├── films
│ │ ├── children
│ │ │ ├── despicable-me
│ │ │ │ ├── large.jpg
│ │ │ │ └── small.jpg
│ ├── icons
│ │ ├── add.png
│ ├── misc
│ │ ├── home-bg.jpg
│ ├── series
│ │ ├── children
│ │ │ ├── arthur
│ │ │ │ ├── large.jpg
│ │ │ │ └── small.jpg
│ └── users
│ ├── 1.png
├── index.html
├── static
│ ├── css
│ │ ├── 2.679831fc.chunk.css
│ │ └── 2.679831fc.chunk.css.map
│ ├── js
│ │ ├── 2.60c35184.chunk.js
│ │ ├── 2.60c35184.chunk.js.LICENSE.txt
│ │ ├── 2.60c35184.chunk.js.map
│ │ ├── main.80f5c16d.chunk.js
│ │ ├── main.80f5c16d.chunk.js.map
│ │ ├── runtime-main.917a28e7.js
│ │ └── runtime-main.917a28e7.js.map
│ └── media
│ └── logo.623fc416.svg
└── videos
└── bunny.mp4
74 directories, 148 files
When you run your application locally, you could use .env file to config your environment variables. Format like "name=value"(without quotes).
Here is a sample:
REACT_APP_APIKEY=REACT_APP_APIKEY
REACT_APP_APPID=REACT_APP_APPID
REACT_APP_AUTHDOMAIN=REACT_APP_AUTHDOMAIN
When I call console.log('process.env', process.env); in index.js file, it works well:
After configuring the app settings on portal, deploy the nodejs web app to Azure.
You can view log output (calls to console.log) from the app directly in the VS Code output window. Just right-click the app node and choose Start Streaming Logs in the AZURE APP SERVICE explorer.
It shows the environment variables on portal Application settings:
By the way:
If you are very new to use node with Azure web app, you could have a look at this: https://learn.microsoft.com/en-us/azure/app-service/quickstart-nodejs?pivots=platform-windows
About how to use .env file, see this: https://holycoders.com/node-js-environment-variable/
We are using Google Cloud Functions quite a bit (around 40 functions currently deployed). They are all in one repository, which is a monorepo for our nodejs backend. They are deployed using Github Actions when a new features/bugfix is merged. Our problem is that all functions are deployed, we dealt with concurrency to deploy more than one function at a time (multiple deploys are run in parallel) but we hit a wall. We are hitting the write quota (which is 80 requests pre 100 seconds) and we are not sure why. It seems that a single function deploy sends around 40 write requests which is isane and while deploying the functions in a slower manner (2 at a time max) it's not acceptable as the deploy would then take 40+ minutes.
While searching info about the quota I found that a single function deploy should do 1 write request (makes sense), but it does multiple for us and I couldn't find any way to debug this.
Example command used for deploying:
gcloud functions deploy functionName --runtime nodejs10 --memory=2048MB --timeout=540s --set-env-vars FN_NAME=functionName --trigger-http --allow-unauthenticated --project our-project --set-env-vars APP_ENV=production
Our functions structure looks like this (names have been replaced):
functions/src
├── fns
│ │
│ ├── atlas
│ │ ├── some-function.fn.ts
│ │ ├── some-function.fn.ts
│ │ ├── newsletter
│ │ │ ├── some-function.fn.ts
│ │ │ └── some-function.fn.ts
│ │ ├── suggestion
│ │ │ ├── some-function.fn.ts
│ │ │ └── some-function.fn.ts
│ │ ├── some-function.fn.ts
│ │ └── some-function.fn.ts
│ │
│ ├── leads
│ │ ├── some-function.fn.ts
│ │ ├── some-function.fn.ts
│ │ ├── some-function.fn.ts
│ │ ├── some-function.fn.ts
│ │ ├── some-function.fn.ts
│ │ └── some-function.fn.ts
│ │
│ ├── utils
│ │ ├── some-function.fn.ts
│ │ ├── some-function.fn.ts
│ │ ├── some-function.fn.ts
│ │ └── some-function.fn.ts
│ └── development.fn.ts
├── utils
│ ├── some-file-used-by-multiple-functions.ts
│ └── some-file-used-by-multiple-functions.ts
└── index.ts
development.fn.ts contains code which is run only on local machine and is ignored during deploy. It basically starts all the functions.
Every .fn.ts exports a single variable named after the function, which is simply a function handling the request request. This is wrapped in our "bootstrap" which handles connecting to databse, PubSub client and others.
index.ts is the entry file for Google Cloud with this content:
import { fns, getFnDefinition } from './bootstrap/get-fns';
// should export util
const ENV_FUNCTION_NAME = process.env.FN_NAME;
const shouldExportFn = (fnName: string) => {
if (!ENV_FUNCTION_NAME) {
return true;
}
return ENV_FUNCTION_NAME === fnName;
};
// export cycle
for (const fn of fns) {
if (shouldExportFn(fn.name)) {
const fnDefinition = getFnDefinition(fn);
exports[fn.name] = fnDefinition.handler;
}
}
export default exports;
Where fns is an array of { name, absolutePath } for our functions. It's read from filesystem (so no imports) and getFnDefinition requires the file and based on the result (exportet object) decides whether the function is triggered by HTTP request or PubSub message.
Also I saw the --entry-point=ENTRY_POINT option, but I'm not sure if that would solve our problem. Would it help if every function had its own entry point instead of the index.js?
The issue is how you are deploying them. You have all 40 functions in one Github repo, but how are you deploying them when one function requires a change? Do you resync / redeploy the whole thing? That would explain the 40 writes since you have 40 functions. I would recommend having them in individual repo or make sure each individual update doesn't cause all the functions to get updated.
Running into this too, but with READS! I hit 150k READS in a few hours just deploying (about 24 functions) about two dozen times. Looks like I have to even optimize my deployment strategy...
Our current solution is kind of dumb, but it works.
So it turns out the limit we were hitting (write quota) can be easily bypassed. What we do now is create a zip of the functions deploy, upload it to gcloud storage and then pass it as a parameter during deploy. This means we now don't reach the write quota (as no files are being uploaded) and everything works. We will however need to solve this in a better way in the future, as there is a limit of 60 when deploying functions and we currently have 48.
Routes on a deployed Angular app do not work when served by Node with Express. I know this has been asked before but there is something I am probably missing that is driving me crazy.
File structure in the "express" folder where Node runs is roughly the following:
express
├── controller.js
├── index.js
├── ngForm
│ ...see below...
├── node_modules
│ ...
├── package.json
├── public
│ ├── file.json
│ └── rubric.html
├── router.js
├── ssl
├── cert.pem
└── key.pem
and the Angular project is in ngForm:
ngForm
├── angular.json
├── dist
│ └── rubric
│ ├── assets
│ ├── favicon.ico
│ ├── index.html
│ ├── main.js
│ ├── main.js.map
│ ├── polyfills.js
│ ├── polyfills.js.map
│ ├── runtime.js
│ ├── runtime.js.map
│ ├── styles.js
│ ├── styles.js.map
│ ├── vendor.js
│ └── vendor.js.map
├── e2e
├── node_modules
├── package.json
├── src
├── tsconfig.json
└── tslint.json
Some relevant Angular code:
app.module.ts:
const appRoutes: Routes = [
{path: '', redirectTo: '/rubric', pathMatch: 'full' },
{path: 'rubric', component: RubricComponent},
{path: 'rubricbuilder', component: RubricbuilderComponent},
{path: '**', component: PageNotFoundComponent}
]
app.component.ts:
#Component({
selector: 'app-root',
styleUrls: ['app.component.scss'],
template: `<router-outlet></router-outlet>`
})
The relevant Node.js code:
server.js:
app.use(express.static("ngForm/dist/rubric"));
app.get('/', (req, res) => {
res.sendFile(path.join(__dirname, 'ngForm/dist/rubric/index.html'));
});
I did run ng build from the Angular project in ngForm, and the output is in ngForm/dist.
When running ng serve in the AngularProject I can navigate to
https://localhost:4200/rubric and https://localhost:4200/rubricbuilder .
From Node I can only get to https://localhost:8000/ which redirects/changes the url to https://localhost:8000/rubric , but I cannot launch https://localhost:8000/rubric itself or https://localhost:8000/rubricbuilder. By poking around with the angular routes and re-running the build, I can make express show rubricbuilder on the / route, which changes the url to https://localhost:8000/rubricbuilder. What am I missing?
I'm not that familiar with angular but this question is related to VueRouter.
Because you did not define /rubric router in express middleware so you might get an error like 404 NOT FOUND.
When using SPA router in HTML5 history mode, you need extra configurations for your server,
for example, send your SPA at every route:
app.use(express.static("ngForm/dist/rubric"));
app.use((req, res) => {
res.sendFile(path.join(__dirname, 'ngForm/dist/rubric/index.html'));
});
This might not be the best practice for express, you can search for other solutions, for example like VueRouter suggest using connect-history-api-fallback with express.