Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules/
.env
.DS_Store
*.log
.vercel
121 changes: 121 additions & 0 deletions PROPOSED_CHANGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Proposed Changes for Vercel Deployment

## Summary
This PR adds Vercel serverless adapter configuration to enable deployment of the Express/EJS blog application on Vercel's serverless platform.

## Changes Made

### 1. Added `api/index.js`
- Serverless wrapper that uses `serverless-http` to adapt the Express app
- Attempts to require the app from common locations: `../app`, `../server`, `../src/app`, `../src/server`
- Returns helpful error message if app cannot be found

### 2. Added `vercel.json`
- Configures Node.js 18 runtime for the serverless function
- Routes all requests to `/api/index.js` to handle client-side routing
- Uses `@vercel/node` builder for the API route

### 3. Updated `package.json`
- Added `serverless-http@^3.0.0` dependency

### 4. Added `.gitignore`
- Excludes `node_modules`, `.env`, logs, and `.vercel` directory from git

## Required Changes for Maintainers

### Update: app.js has been modified
The `app.js` file has been updated to export the app instance while maintaining local development compatibility. The changes include:

1. **Mongoose connection moved to end**: The connection is now established after all middleware and routes are configured
2. **Conditional server start**: The app only calls `listen()` when run directly (not when imported as a module)
3. **App export**: The app is now exported for use by the serverless adapter

The current structure:
```javascript
// ... (Express app setup, middleware, routes)

// Connect to MongoDB
mongoose
.connect(dbURI)
.then((result) => {
console.log("Connected to MongoDB");
// Only start server if not in serverless environment
if (require.main === module) {
app.listen(3000, () => {
console.log("Server running on port 3000");
});
}
})
.catch((err) => console.error(err));

// Export the app for serverless deployment
module.exports = app;
```

### For Local Development
The app works the same way as before:
```bash
npm start # or node app.js
```

The server will listen on port 3000 as usual.

## Deployment Steps

1. Merge this PR (all necessary changes are included)
2. Run `npm install` to install `serverless-http`
3. **IMPORTANT**: Move the MongoDB connection string to environment variables (see Security section below)
4. Deploy or redeploy on Vercel
5. Vercel will automatically install dependencies and run the serverless function

## Security Considerations

### Critical: MongoDB Connection String
The MongoDB connection string is currently hardcoded in `app.js` with credentials exposed:
```javascript
const dbURI = "mongodb+srv://netninja:test1234@nodeproject.62tovra.mongodb.net/...";
```

**This is a security vulnerability and must be addressed before deployment.**

To fix this:
1. Create a `.env` file locally (already in .gitignore):
```
MONGODB_URI=mongodb+srv://netninja:test1234@nodeproject.62tovra.mongodb.net/NodeProject?retryWrites=true&w=majority&appName=NodeProject
```

2. Update `app.js` to use environment variable:
```javascript
const dbURI = process.env.MONGODB_URI || "mongodb://localhost:27017/fallback";
```

3. Add the `MONGODB_URI` environment variable in Vercel dashboard:
- Go to Project Settings > Environment Variables
- Add `MONGODB_URI` with your connection string
- The value will be securely stored and not exposed in your code

## Environment Variables

Make sure to add all required environment variables in the Vercel dashboard:
- Go to Project Settings > Environment Variables
- Add `MONGODB_URI` with your connection string (see Security section above)
- Add any other environment variables your app needs

**Do not commit sensitive credentials to your repository.**

## Testing Locally

To test locally before deploying:
```bash
npm install
npm start # Test with regular server
# Or use Vercel CLI:
vercel dev
```

## Notes

- **Security**: The MongoDB connection string with credentials is currently hardcoded in `app.js`. This should be moved to environment variables before deployment (see Security Considerations section above).
- Serverless functions have cold start times, so the first request after a period of inactivity may be slower.
- Static files in the `public` directory will be served correctly through the Express middleware.
- EJS views will work as expected since they're rendered server-side.
34 changes: 34 additions & 0 deletions api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const serverless = require('serverless-http');

// Attempt to require the Express app from common locations
let app;
const possiblePaths = [
'../app',
'../server',
'../src/app',
'../src/server'
];

for (const path of possiblePaths) {
try {
app = require(path);
console.log(`Successfully loaded app from: ${path}`);
break;
} catch (err) {
// Continue to next path
}
}

if (!app) {
// If no app is found, return a helpful error
module.exports = (req, res) => {
res.status(500).json({
error: 'Express app not found',
message: 'Could not locate the Express app. Please ensure your app is exported from one of: app.js, server.js, src/app.js, or src/server.js',
triedPaths: possiblePaths
});
};
} else {
// Wrap the Express app with serverless-http
module.exports = serverless(app);
}
22 changes: 17 additions & 5 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,6 @@ const app = express();
const dbURI =
"mongodb+srv://netninja:test1234@nodeproject.62tovra.mongodb.net/NodeProject?retryWrites=true&w=majority&appName=NodeProject";

mongoose
.connect(dbURI)
.then((result) => app.listen(3000))
.catch((err) => console.error(err));

//register view engine
app.set("view engine", "ejs");
// app.set('views', 'myViews')//making a new folder as the ejs view
Expand Down Expand Up @@ -44,3 +39,20 @@ app.use("/blogs", blogRoutes);
app.use((req, res) => {
res.status(404).render("404", { title: "404" });
});

// Connect to MongoDB
mongoose
.connect(dbURI)
.then((result) => {
console.log("Connected to MongoDB");
// Only start server if not in serverless environment
if (require.main === module) {
app.listen(3000, () => {
console.log("Server running on port 3000");
});
}
})
.catch((err) => console.error(err));

// Export the app for serverless deployment
module.exports = app;
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node server.js"
"start": "node app.js"
},
"author": "",
"license": "ISC",
Expand All @@ -19,6 +19,7 @@
"method-override": "^3.0.0",
"mongodb": "^6.5.0",
"mongoose": "^8.3.2",
"morgan": "^1.10.0"
"morgan": "^1.10.0",
"serverless-http": "^3.0.0"
}
}
18 changes: 18 additions & 0 deletions vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"version": 2,
"builds": [
{
"src": "api/index.js",
"use": "@vercel/node",
"config": {
"runtime": "nodejs18.x"
}
}
],
"routes": [
{
"src": "/(.*)",
"dest": "/api/index.js"
}
]
}