vercel not running build and instal commands and not creating Serverless functions - node.js

I am trying to move my application's API to Vercel. It is written in Typescript and uses Express.
The index.ts is located in <root>/src. The npm run build compiles it into <root>/dist directory. The file contains the following:
const app = express();
app.use((req: Request, res: Response, next: NextFunction) => {
//blah, blah, there is a lot going on here
})
app.use('/', common);
//... other app.use(s)
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server running on ${port}, http://localhost:${port}`));
module.exports = app;
I've got the following in the vercel.json file which is located in the root directory where the package.json also is:
{
"version": 2,
"installCommand": "npm install",
"buildCommand": "npm run build",
"outputDirectory": "dist",
"builds": [
{
"src": "dist/index.js",
"use": "#vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "dist/index.js"
}
]
}
When locally I run npm run build, then vercel dev --listen 5000 I get Ready! Available at http://localhost:5000 and can go to http://localhost:5000/ping and get a response.
Now I commit the files to git, the deployment runs, but judging by the logs the npm install and npm run build commands are not running. No functions are created my /ping endpoint returns "Page not found".
Here is the deployment log:
This is what Build & Development Settings look like (the Root Directory is left blank):
I followed several recommendations I found online and according to them everything should work. I probably miss some setting somewhere. What is it?
If more information is needed, please let me know, I'll update my question.
Thank you.
--- UPDATE ---
I have set the Root Directory to src and checked the "Include source files outside of the Root Directory in the Build Step" checkbox. Now the npm install and npm run build are executing. As you can see some static files are deployed, but there are still no serverless functions and my /ping route returns 404 and "home" page, i.e. / route returns the content of the index.js file. In addition the local is not working either anymore, also returning 404 now.
Without that checkbox I was getting
Warning: The vercel.json file should exist inside the provided root directory
and still no install or build running.
Also worth noting that I had to change my tsconfig.json to have "outDir": "src/dist" instead of "outDir": "dist", otherwise I was getting
Error: No Output Directory named "dist" found after the Build completed. You can configure the Output Directory in your Project Settings.
Removed the Root directory and back to square one, no npm commands running but local is working with / route returning Cannot GET / and /ping returning correct response.

For everyone out there who's looking for an answer, maybe this will help you.
In my case, what I needed is to create a folder, called api in my src folder, i.e. the folder that is specified as Root Directory in Build & Development Settings in Vercel. Within this directory, each serverless function needs a file named the same as the path of the route. For example, the file named "my-route.js" will be accessible via https://my-app-name.vercel.com/api/my-route.
All this file needs is an import of index.js file and module.exports. For example:
import app from '../index';
module.exports = app;
The index.js should also live the Root and contain your express setup.
If you want to have dynamic path parameters, the files' names in the api directory should be wrapped in square brakets, like [my-param.js]. You can also have sub-directories in the api foler.
Here are a few links that helped me figure this out:
https://dev.to/andrewbaisden/how-to-deploy-a-node-express-app-to-vercel-2aa
https://medium.com/geekculture/deploy-express-project-with-multiple-routes-to-vercel-as-multiple-serverless-functions-567c6ea9eb36
https://ryanccn.dev/posts/vercel-framework/#path-segments
No changes were needed in my existing Express setup and routes files.
Hope this will help someone. Took me quite a while to figure it all out :)

Related

Firebase and Node.js application results in the requested URL was not found on this server for the firebase serve command

I have created a Node.js application and trying to deploy in the Firebase for hosting. Before deploying, I am making sure that it will work properly using the command firebase serve --only hosting,function. This command creates the server and I am able to access the Home page of the application using the URL (localhost:5000) provided by Firebase but for some reason, my Angularjs HTTP request is unable to find the Node.js controller due to which I am getting the 404 URL not found error in the brwoser.
As soon as the index.html is accessed using the localhost:5000 I am trying to populate various dropdown options in my frontend. These options are present within the Node.js controller file populator.js. Hence I am making an HTTP request from angularjs to my node.js controller but I get the 404 URL not found error. I am guessing there is some issue with folder structure or the firebase.json file due to which the code is unable to find my Node.js controller.
My firebase.json file:
{
"hosting": {
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"function": "app"
}
]
}
}
My index.js file:
const functions = require("firebase-functions");
const express = require('express');
const app = express();
//call function to popultae the fields
app.get('/populateFields', function(req,res){
populateFields.BusinessStep(function(data){
res.send(data);
});
});
exports.app = functions.https.onRequest(app);
Here is my folder structure
Firebase Hosting (root)
|--functions
|---index.js
|---package.json
|
--public
|---index.html
|
--firebase.json
--.firebaserc
I tried running the command firebase serve --only hosting,function in both the root directory and within the functions folder but none worked and still getting the error The requested URL was not found on this server.
I found many post related to this issue but could not find there solution after trying the methods mentioned there hence posting this question.
I was running the command wrongly so I was getting that issue the actual command is
firebase serve --only functions,hosting
If anyone is facing the issue then run the command correctly.
"I was running the command wrongly so I was getting that issue the actual command is
firebase serve --only functions,hosting"
I guess that the error was for specifying function instead of functions

NOde.js/Express App can't find some node_modules

I use several Node/Express modules in my app, and everything works fine for every module as long as I do const module = require('module');. I don't need to define a static path for these modules as app.use(express.static(path.join(__dirname, 'public')));.
However, for the sweetalert module, if I define in my layout.pug (base pug file) script(src="/node_modules/sweetalert/dist/sweetalert.min.js"), I get a 404 Error (not found) unless I include in app.js the following static path: app.use("/node_modules", express.static(__dirname + "/node_modules"));.
My question is: is this the normal behaviour or is it something I'm not doing right? (I'm kinda confused why I have to define a static path just for one of several modules I use.
Here's whats going on:
app.use(express.static(path.join(__dirname, 'public'))); is declaring that the public directory is accessible to the browser. You should put all your front end resources in that folder. This will help separate what can be accessed from the server and what can be accessed from the client.
When you reference script(src="/node_modules/sweetalert/dist/sweetalert.min.js") the browser throws a 404 because that file is not located in the public directory, therefore off limits to the browser.
Adding this line app.use("/node_modules", express.static(__dirname + "/node_modules")); "fixes" your issue but now exposes all your node_modules to the browser. This probably isn't a good idea and I'm sure a security expert could elaborate why this shouldn't be done.
How I would resolve this issue: Go through your .pug code and look at any resources your front end requires. Then copy them over to the public folder and fix your references to use the copy of the resource.
Here's an example of a script I use to move resources from the node_module directory to a public/assets directory:
build.js:
const path = require('path');
var fs = require('fs');
const ASSETS = [
'jquery/dist/jquery.min.js',
'sweetalert/dist/sweetalert.min.js'
];
if (!fs.existsSync('./public/assets')){
fs.mkdirSync('./public/assets');
}
ASSETS.map(asset => {
let filename = asset.substring(asset.lastIndexOf("/") + 1);
let from = path.resolve(__dirname, `./node_modules/${asset}`)
let to = path.resolve(__dirname, `./public/assets/${filename}`)
if (fs.existsSync(from)) {
fs.createReadStream(from).pipe(fs.createWriteStream(to));
} else {
console.log(`${from} does not exist.\nUpdate the build.js script with the correct file paths.`)
process.exit(1)
}
});
then I update my package.json to include this in the scripts:
package.json:
"scripts": {
"build": "node ./build.js || true",
"start": "node ./bin/www"
}
then in any of my views pages I reference the resource by using the new path
random.pug:
script(src="/assets/jquery.min.js")
script(src="/assets/sweetalert.min.js")
Finally before you deploy your app you now must run the following command:
npm run build then npm start
You will only need to run the build command if your front end resources change. So if you only ever use sweetalert.min.js you will only need to run the build the first time you run your app. If later on you add another resource aNewResource.js you will need to update the build.js file and run npm run build again.

Images uploaded with Node server cannot be found by Angular 2

I have an app in Angular 2, decided to add real server, Node JS, to upload documents and do other things.
Browser => Angular [localhost:4200/api/documents] => Node [localhost:3000/documents]
This is how I start them together using scripts in package.json
"scripts": {
"server-start": "gulp",
"client-start": "ng serve --verbose --proxy-config server.conf.json",
"start": "npm-run-all -p client-start server-start"
}
So, when I run npm start it starts 2 parallel processes - Node JS using Gulp and Angular using ng serve. Angular is a front end, but all URLs that start with /api get redirected to Node. Here is how it's done with server.config.js
{
"/api": {
"target": "http://localhost:3000",
"secure": false
}
}
Node JS receives stream from Angular with image and saves it in Angular assets folder, so uploaded image should be available in Angular, but when I try to open uploaded image in browser it returns me 404, not found. Just in case, this is part of my .angular-cli.json
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico",
"service-worker.js"
],
"index": "index.html",
"main": "main.ts"
Example, I have existing image that was there before ng serve
F:\Node\cms\src\assets\uploads\1.jpg
available at, it works
http://localhost:4200/assets/uploads/1.jpg
I upload new one to the same location
F:\Node\cms\src\assets\uploads\5.jpg
but it's NOT available at
http://localhost:4200/assets/uploads/5.jpg
When I restart my servers image becomes available. According to this discussion ng serve performs deployment of Angular app in the background, and folder dist is empty, all images are taken from memory, and any new images dropped into assets won't be available, correct me if I am wronng.
Question #1: is built-in Angular server able to handle dynamic images if they were added when application is already running in memory?
Question #2: looks like in complex apps ng serve brings more troubles than benefits, is it worth to try to make it working or you'd recommend to start using ng build instead?
when running your application, everything points to build folder. Not "src"
You probably are wiping out the images each time you run my serve or need to store them in a different location.
You are technically storing images on a "server" so I recommend using node to retrieve the paths to these files.
You should use ng build instead of ng serve. ng serve is meant for dev purposes. See https://github.com/angular/angular-cli/wiki/serve
Additionally after running ng build you will need to have the dist folder on an actual server. Here's an example from the Angular wiki
https://github.com/angular/angular-cli/wiki/stories-disk-serve
ng build --watch
lite-server --baseDir="dist"
You could also have node serving the dist folder using the static method that is built into node.
The line to add would be either
app.use(express.static('dist'))
or
app.use(express.static(path.join(__dirname, 'dist')))
See https://expressjs.com/en/starter/static-files.html
I prefer to do ng build -aot to get the bundle size as small as possible and then serve the dist folder with nginx.

Cannot get correct static files after refreshing except index page

When I refresh page on index route (/) and login page (/login), it works fine.
However, my website gets error as I refresh on other routes, for example /user/123456.
Because no matter what the request is, the browser always gets HTML file.
Thus, both of the content in main.css and main.js are HTML, and the browser error.
I have already read the README of create-react-app.
Whether I use serve package ($serve -s build -p 80) or express, it will produce the strange bug.
Following is my server code:
//server.js
const express = require('express');
const path = require('path');
app.use(express.static(path.join(__dirname, 'build')));
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
const PORT = process.env.PORT || 80;
app.listen(PORT, () => {
console.log(`Production Express server running at localhost:${PORT}`);
});
Edit: I have figured out where caused the problem.
I created a new project, and compared it to mine. The path of static files in the new project is absolute, but in my project is relative.
As a result, I delete "homepage": "." in the package.json.
//package.json
{ ....
dependencies:{....},
....,
- "homepage": "."
}
Everything works as expected now. How am I careless...
I have figured out where caused the problem.
I created a new project, and compared it to mine. The path of static files in the new project is absolute, but in my project is relative.
As a result, I delete "homepage": "." in the package.json.
//package.json
{ ....
dependencies:{....},
....,
- "homepage": "."
}
Everything works as expected now. How am I careless...
If your route /user/** is defined after app.get('/*', ... it might not match because /* gets all the requests and returns you index.html.
Try without the * or declare the other routes before.
First, I thought you misunderstood the server part. In your case, you use serve as your server. This is a static server provided by [serve]. If you want to use your own server.js, you should run node server.js or node server.
I also did the same things with you and have no this issue. The followings are what I did:
create-react-app my-app
npm run build
sudo serve -s build -p 80 (sudo for port under 1024)
And I got the results:
/user/321
I guessed you might forget to build the script. You can try the followings:
remove build/ folder
run npm run build again
Advise: If you want to focus on front-end, you can just use [serve]. It will be easy for you to focus on what you need.

Unexpected token import - using react and node

I'm getting an error when running my react app: Uncaught SyntaxError: Unexpected token import
I know that there are a plethora of similar issues on here, but I think mine is a little different. First of all, here is the repository, since I'm not sure where exactly the error is: repo
I'm using create-react-app, and in a seperate backend directory I'm using babel (with a .babelrc file containing the preset es2015). The app worked fine until I added another file in a new directory in the backend folder (/backend/shared/validations/signup.js).
I was using es6 before that too, and it was working perfectly fine. First I thought it was some problem with windows, but I cloned the repo on my Ubuntu laptop and I'm getting the same error there.
Some things I tried already:
Move the entire folder from /backend to the root folder
Move just the file (signup.js) just about everywhere
So no matter where the file is, the error stays the same. If I remove the entire file and all references to it the app works again.
I think this error is pretty weird, considering I'm using es6 everywhere else in the app without trouble. It would be great if anyone could help me with this error.
edit: If you want to test this on your own machine just clone the repo and run npm start in the root folder (and also npm start in the backend folder, but that isn't required for the app to run, or for the error to show up).
That's what's happening:
Your webpack is set to run babel loader only in the src folder (include directive).
To change that, one approach is:
1) extract webpack configuration with npm run eject (don't know if there is another way to override settings in react-create-app). From the docs:
Running npm run eject copies all the configuration files and the
transitive dependencies (Webpack, Babel, ESLint, etc) right into your
project so you have full control over them.
2) in config/paths.js, add an appShared key, like that:
module.exports = {
/* ... */
appSrc: resolveApp('src'),
appShared: resolveApp('backend/shared'),
/* ... */
};
3) in config/webpack.config.dev.js, add the path to the babel loader, like that:
{
test: /\.(js|jsx)$/,
include: [ paths.appSrc, paths.appShared ],
loader: 'babel',
/* ... */
},
It works now!

Resources