How to serve static files in AppEngine Standard and nodejs - node.js

The documentation says that you simply must update your app.yaml - like you would for any language within AppEngine. It also states later on that for local development, you probably want your server to respond to static requests as well. However, when I update my very simple app.yaml to be as such:
runtime: nodejs8
handlers:
- url: /apiEndPoint
script: auto
- url: /.*
static_dir: public
It seems all requests still end up coming in to my script - which will return a 404 in the prod instance, since those files won't be uploaded. I can force them to be uploaded, and then my nodejs server responds to the static requests - but I thought the idea of this app.yaml was to configure it so static files are served outside of my app logic?

So to be clear - you can host static files in production Nodejs Standard AppEngine without needing to use a JS server. However, for local development, you must find a way to serve those files locally when running on your machine. For this reason, you put the handler in Express, for static files, which should never be touched in production - since the app.yaml handler is the first-pass.
If you want to be positive Express.js is not serving up static files in production, you can do so by doing something like this:
// Production instances automatically have this environment variable.
const isLocal = (process.env.NODE_ENV !== "production");
if(isLocal) {
app.use(express.static('public'));
}

The static files are uploaded during deployment, but not in the same place as the app's code. They're uploaded in Google's infra dedicated for directly serving static content. This could be confirmed by increasing the log verbosity of the deployment command.
When a request URL matches one of the static handlers it should be directed to this dedicated infra, it shouldn't reach your app code. It should be relatively easy to confirm with an actual deployment.
As for the local development, I'm not exactly sure how the Node.Js server behaves (indeed, the docs appear to suggest Express may be needed to handle static files), but the Python one serves itself the static files based solely on the app.yaml static handler configs, without hitting any of the app code. Could be because of the still very new Node.JS standard environment support.

The static files that you want to serve need to be deployed along your application code with gcloud app deploy.
Your app.yaml file says:
Any request that matches /apiEndPoint will be routed to your Node.js app
Any other request URL will serve a static file from your public folder and not arrive to your application (once deployed).
For example: /index.html will serve public/index.html if this file has not been deployed, then it will return a 404 page.

Related

How can I connect my NodeJS/Express backend to my VueJS frontend using only one port on my local machine?

My Vue app is set up using Vue CLI (Webpack) and it's working as it should. My NodeJS/Express REST API is also working properly. However, to run them simultaneously I now start a local server for each of them -- each with its own port. I would like to have both of them communicate over one port.
Localhost:8080 should point to the home page of my Vue App and the API requests should follow localhost:8080/api/...
In my production environment I use one and the same port/URL by serving the Vue App as a set of static files ('dist' folder). In my development environment I don't know how to set this up, however.
I looked around for answers online, but feel lost among all the different terms I have come across (.env, crossenv, nginx, cors) and that I am running in circles.
What would be a good way of setting this up?
Thank you
Edit:
I ended up creating three modes to run my application:
Development
I use one script in a package.json to start the frontend and backend server on different ports, using pm2 to run the servers in the 'background' rather than blocking further commands in the terminal/cmd. I use configured a proxy inside my vue.config.js to redirect my API calls made in the frontend to the right base URL and used cors as middleware to allow requests to my API from other domains/ports.
Staging
I use one script in a package.json to build the Vue app into a folder ('dist' folder inside my backend folder) that is a collection of static files and start the backend server. My backend is set up to know when I want to go into staging mode and then serve the static files in the 'dist' folder.
Production
I use one script in a package.json to build the Vue app into a folder ('dist' folder inside my backend folder) that is a collection of static files and push my backend (incl. the built static files) to Heroku.
Well if you need to run both on the same port you could first build your app so that you receive a dist directory or whatever your output directory is named and set up an express server that serves that app and otherwise handles your api requests
const express = require("express");
const path = __dirname + '/app/views/';
const app = express();
app.use(express.static(path));
app.get('/', function (req,res) {
res.sendFile(path + "index.html");
});
app.get('/api', function (req,res) {
// your api handler
}
app.listen(8080)
Assuming that node and the 'app' will always run on the same server you can just use a template library like ejs.
You would then just bundle the app and api together, assuming that the front-end is tied to the backend, realistically you would not even need to hit the API as you could just return the records as part of the view, however if dynamic elements are needed you could still hit the API.
Now, with that said, if the API is something used by many applications then it would probably make sense to build that out as its own microservice, running on its own server and your frontend would be on its own. This way you have separation of concerns with the API and Vue app.

how to use proxy in react build?

this is the api call i want to make
http://localhost:3000/api/getUserName
but i am using it in proxy in package.json. i tried to build the app but then call goes to
http://localhost:5000/api/getUserName
i am serving on 5000 so its taking api call also on 5000. so i want to mention 3000 om build. also i have check on google and it says mention it in .ENV cause proxy is not for production, but can anyone provide me .ENV structure that can show to me how to use it from env?
During development, the practice is to use to two servers; one server for the client side, generally localhost:3000, and a second one for the server, generally localhost:5000. When you build for production, reactjs compiles and builds such that it becomes a static resource for the server and the server serves these files.So, your app will be served, wherever you host your server. The production config will depend on what you folder structure looks like. If you are using CRA for your application, you can use this piece of code:
I am assuming that you have your client directory inside your server directory.
if(process.env.NODE_ENV === 'production'){
app.use(express.static('client/build') //path to your build directory
const path = require('path');
app.get('*', (req, res)=>{
res.sendFile(path.resolve(__dirname, 'build','public','index.html');
}
}
Again, I am assuming that you are using CRA to bootstrap your react application and have your client directory inside your server directory. If you are using webpack, then the config will change to indicate the path of the build directory.

Can't reach backend when url base is set

I have an application built using Express, Mongoose, React and Node. My application is hosted on a location which looks like the following: https://example.com/app_name which means that app_name is the base path for all of the static assets.
I'm using Webpack and setting publicPath to https://example.com/app_name. I can reach my static assets just fine, but when I attempt to do a call to my back-end, my requests are being routed to https://example.com/api/... instead of https://example.com/app_name/api/....
Is there a way to prefix my endpoint calls so that they use https://example.com/app_name/api/... instead of https://example.com/api/...through webpack or any other means?

Getting 503 status code when index.html tries to load css and scripts [nodejs + express]

I'm using static middleware to serve stylesheets and scripts
app.use(express.static(path.join(__dirname, 'public')));
Everything works on localhost, but once I deploy the app to openshift I get 503 code for each static file the page tries to load.
If I open another browser tab and directly past the URL of one of those files I actually get the file.
P.S.: I am using express-react-views as a view engine.
Basically, I'm using express-react-views as a view engine and it includes Babel.js which uses cache for transpilation optimization. The problem is that it tries to write the cache files in a directory that requires higher permission. To solve I disabled the cache.
process.env.BABEL_DISABLE_CACHE = 1;
I hope this can help other people having the same issue.

Frontend content with a backend API - how to avoid hard-coding where the backend API is?

I have frontend content that needs backend REST APIs to function. The APIs allow for cross-origin resource sharing (CORS). Typically we run the complete stack locally, including a user-mode Nginx instance tailored for development use which serves the frontend content. The full stack however is a bit too much to expect part time contractors to wrangle. So I'd like an approach very basic they can use to be effective and get stuff done.
Their current solution is horrible:
var port = location.port;
// base url of backend API
var url = window.location['origin'];
if (port != '443') {
// assume we're running in "development" mode against a staging server
url = "https://staging-server.somewhere.com";
}
Apart from the fact that this is furthering frontend content that is a bit kludgey as it is - it precludes the static content from being hosted in a variety of other ways, including a suite of functional and integration tests.
I have some ideas, like having them run a small web server that proxies to the backend APIs, but what I would really like is something simpler that allows me to default url in a less kludgey way. Ideally, there would be some manner of configuring url from a file ignored by version control (e.g., .gitignore).
I was able to create a solution that works for all manner of local development as well as production releases.
I created some JavaScript, apiurl.js, that sits alongside all of our other JavaScript content. If the apiurl.jsfile is present, I read its responseText into eval(). The frontend can therefore change the URL based on the content of that file.
E.g., apiurl.js has:
var apiurl = "https://staging-server.somewhere.com";
And the JavaScript to handle the content:
eval(responseText);
if (typeof(apiurl) != undefined) {
url = apiurl;
}
The apiurl.js file is untracked by version control and not used in production.

Resources