gcloud functions deploy not uploading html and css - node.js

I created following express API
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
require("dotenv/config");
//routes
const authRoute = require("./routes/auth.js");
const adminRoute = require("./routes/admin.js");
//middleweres
//converting body into json using body parser
app.use(cookieParser());
app.use(bodyParser.json());
app.use("/", express.static("public"));
app.use("/api/auth", authRoute);
app.use("/api/admin", adminRoute);
// starting express server
// app.listen(5000, () => {
// console.log("listning on port 5000");
// });
module.exports = {
app,
};
in public folder I have html file and css and js inside public/static folders
html, css and js in public folder are generated with react build.
I am trying to deploy this API in google cloud function with following command
gcloud functions deploy outreach-dashboard --entry-point app --runtime nodejs10 --trigger-http --allow-unauthenticated
function is getting deployed but problem is when I see the function on gcp dashboard it source does not contain public folder and if I download source as zip then I can see public folder there but its empty.
I need public folder to get deployed so I can serve it using
express.static("public")

You are trying to serve several endpoints in the same Cloud Functions. I saw some hack on Stack overflow where folks bend the framework to achieve this. It's not my recommendation.
Cloud Run is a very similar platform. The same underlying infrastructure, and feature very close (I wrote an article on this). But you serve a containerize webserver, more suitable for your use case.
You can easily have a try on it.
Uncomment your "starting app express" part
Test locally if it works.
Then run this command
gcloud beta run deploy outreach-dashboard --source=. --platform=managed --region=us-central1 --allow-unauthenticated
change the region if needed
The command :
upload the sources (take care of your .gitignore and .gcloudignore file to be sure to upload all the files)
Create a container with your source. To achieve this, Buildpacks.io is used. Exactly the same process that with Cloud Functions and App Engine.
Deploy the container on Cloud Run.
If the problem persist, there is may an issue with the automatic container build process (maybe some file are automatically discarded). In this case, you can write a very simple Dockerfile similar to this one that you have in the getting started documentation.
This time, you can create and deploy in 2 steps (and 2 commands)
# create the container with Cloud Build based on the docker file
gcloud builds submit --tag gcr.io/<PROJECT_ID>/<containerName>
# Deploy on Cloud Run
gcloud beta run deploy outreach-dashboard --image=gcr.io/<PROJECT_ID>/<containerName> --platform=managed --region=us-central1 --allow-unauthenticated

As it turns out I have remove public folder from .gitignore
and after that also need to tell GCF to treat public folder as static folder by creating app.yaml file in root folder
content of app.yaml
runtime: nodejs12
handlers:
- url: /static
static_dir: public
- url: /.*
script: auto

Related

How to deploy nodejs + angular app to Google Cloud Platform

I have a nodejs backend and an angular frontend app in the same folder. The angular app outputs the build files to a static folder and nodejs uses the following to load the html file
//Idiomatic expression in express to route and respond to a client request
app.get('/', (req, res) => { //get requests to the root ("/") will route here
res.sendFile(process.cwd()+"/angularApp/static/index.html") //server responds by sending the index.html file to the client's browser
//the .sendFile method needs the absolute path to the file, see: https://expressjs.com/en/4x/api.html#res.sendFile
});
This is my app.yaml for nodejs :
runtime: nodejs16
handlers:
- url: /
static_files: angularApp/static/index.html
upload: angularApp/static/index.html
- url: /
static_dir: angularApp/static
However when I deploy the app to GCP I get the following errors in the console
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
What should the app.yaml file contain?
Tou can take a look of how docker works. Basically, you put your dependencies and source code into an image, then you ca easily deploy it on google cloud platform https://cloud.google.com/run/docs/deploying .

How to deploy a nodejs backend and vuejs frontend to the same Amazon EC2 instance

I have a vuejs frontend and an express nodejs backend. But I don't know how I can deploy both of them to the same Amazon EC2 instance with the same domain name pointing to them. Please can anyone help me with this? Or suggest a better way of doing this?
You can merge two repos and deploy both backend and frontend as follows
Inside your nodejs app, open a folder named client and put all the Vue project inside it.
If you are using Vue CLI, change your vue.config.js as follows to create a dist folder inside the root of the nodejs project like
const path = require('path');
module.exports = {
outputDir: path.resolve(__dirname, '../dist'),
};
Make all the get/post endpoints of nodejs application start with /api/ to not get conflict with the path that redirects all the requests to vue client app other than /api/ paths.
Run npm run build to create a dist folder inside nodejs root backend folder
If you are using express.js, serve dist folder with nodejs express backend like;
index.js
const express = require('express');
const app = express();
// Serve Vue Dist Folder
app.use(express.static(__dirname + '/dist'));
app.get('*', (req, res) => res.sendFile(__dirname + '/dist/index.html'));
nodejs with e.g. express can also serve static content. Just put your vuejs files in a static folder.

How to create Node.js Express app serving a Vue.js SPA?

I'm trying to set up a Node.js project that uses Express to provide a few backend APIs and serve a SPA built with Vue.js.
When I use the Vue cli to initialize a project, I get e.g. src/main.ts main file and commands npm run serve to run a dev server and watch for changes and npm run build to build a production release.
When I use the Express application generator to create a project, I get ./app.js main file and npm start to start the server and watch for changes.
How can I combine these into a single project, both served by the same Express server? Preferably so that a single command would watch + update changes to both server and client? I want to use Vue single file components and TypeScript, which (probably?) require a build step.
(I don't need dynamic server-side rendering of Vue templates, just the static SPA app provided. I prefer TypeScript, but JavaScript answers are fine as well.)
These will be different for your dev and prod environments...
For development look into concurrently - it basically allows you to create a single script in your package.json to start both the client and server concurrently and will watch for changes etc...
For production, you would need something like this in your app.js:
if (process.env.NODE_ENV === 'production') {
app.use(express.static('client/build'));
const path = require('path');
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
(The code above assumes that your directory structure has a client folder with a build folder after having run npm run build I'm more familiar with React than Vue... but the logic should be the same...)

Deploying angular app to AWS Elastic beanstalk

I’m trying to deploy a very basic angular app to elastic beanstalk. The project was created using the angular cli. I have not made any changes to the files in this project.
Here are the steps I took to deploy the app
Executed ’ng build’ inside the root folder of my project
Moved the #angular/cli dependency from devDependencies to dependencies in package.json
Zipped the contents of the dist folder along with package.json
Deployed zip folder to AWS EB configured with the node.js platform, node version 8.11.3, the same as my local environment.
I always end up with a ‘npm install failed’ error when I check eb-activity.log.
Am I missing something trivial here? Would really appreciate any help with deploying angular apps to EB.
While this does not specifically answer your question, I don't think Elastic Beanstalk is the right tool for the job. I strongly suggest hosting on a Static Website on S3, and if you want https and a custom domain name, put a CloudFront distribution in front of it.
Create an S3 bucket, e.g. www.mydomainname.com
Enable Static Website Hosting
Set the Bucket Policy to public read
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "PublicReadForGetBucketObjects",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::www.mydomainname.com/*"
}
]
}
Build the angular app locally, into a dist folder.
Push the files to the website using the aws-cli
aws s3 sync dist s3://www.mydomainname.com/
This solution will cost pennies, much lower than an Elastic Beanstalk solution (EC2, EBS, ELBs). Elastic Beanstalk is great for Monolithic apps, but their existence is numbered, and the wrong paradigm when you are talking SPA, IMO.
I know I'm pushing my luck now, but I would also strongly recommend using the Serverless Framework to build and deploy NodeJS API endpoints for your Angular App to interact with.
Follow the steps:
-- Angular app
Create your Angular App
Build your Angular App using ng build --prod command
This will create a dist folder like 'dist/app-folder' with HTML, js, and CSS
The angular app you just built won’t work as a static website, it has to run on top of a Node.js server
-- Node.js App
Created a new folder and create a Node.js project by running: npm init and follow the instructions
Name entry point: (index.js) js to 'server.js'
Install Express and Path using npm install express path --save command
Create a file named 'server.js' into the project folder
Now check the package.json file for a configuration named “main” the value should be 'server.js'
Copy the Angular dist folder to Node.js app folder
Open 'server.js' file paste below code
var path = require('path');
const port = process.env.PORT ||3000;
const app = express();
//Set the base path to the angular-test dist folder
app.use(express.static(path.join(__dirname, 'dist/yourappfolder')));
//Any routes will be redirected to the angular app
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'dist/yourappfolder/index.html'));
});
//Starting server on port 8081
app.listen(port, () => {
console.log('Server started!');
console.log(port);
});
Run Node.js project locally using 'node server.js' command
The app should work on localhost:3000 port
Take the dist folder, the server.js file, and the package.json file (of the server project) and compress them as a zip. DO NOT include the “node_modules” folder.
Upload the zip to your AWS Elastic Beanstalk environment
Browse your site
Hope this is useful!
Got the deployment issue resolved! I used express to create a server and serve my angular app. I needed to add server.js to my dist/ folder. My server.js file looked like so
const express = require('express');
const http = require('http');
const app = express();
const port = process.env.PORT || 3001;
app.use(express.static(__dirname));
const server = http.createServer(app);
server.listen(port, ()=> console.log("Running..."));

gcloud app deploy fails for my nodejs

I am trying to deploy my little express static app to google cloud. It is failing however I cannot figure out why. There is nothing in the logs. I have deployed by adding the verbosity to debug flag. I have found this json being sent to google app engine
"betaSettings": {
"module_yaml_path": "app.yaml",
"vm_runtime": "nodejs"
},
"env": "flex",
"handlers": [
{
"script": {
"scriptPath": "PLACEHOLDER"
},
"urlRegex": ".*"
}
],
"runtime": "vm"
}"
The thing that bothers me is that the scriptpath is resolved as placeholder. Not sure if it makes sense. Here's my app.yaml
runtime: nodejs
env: flex
My app.js is as follows
var express = require('express')
var app = express()
app.set('port', (process.env.PORT || 8080))
app.use(express.static('public'))
app.listen(app.get('port'))
I have a public folder which I assume is being deployed but cannot verify. Any suggestions?
This simply never worked for me. My options was to create a docker. Later on I decided to google for answers. The answer was to use a constant google cloud storage and deploy the output using gsutil. It works, I am not too happy that the express static does not work for me. The link that explains how to deploy for express static Best practice works for me not express static I tried deploying nodejs on heroku. Deployed perfectly in 5 minutes. Wish google was as simple.

Resources