NextJS cookie-parser middleware absent from production build - node.js

I'm developing a NextJS application and have been using npm run dev during the development process. Now I'm trying to do a production build as described on the GitHub page.
My app blows up in production mode; it seems the cookie-parser node middleware is not installed in the production build? Here is how I set it up:
server.js
const express = require('express');
const next = require('next');
const cookieParser = require('cookie-parser'); // require cookie-parser
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare()
.then(() => {
const server = express();
server.use(cookieParser()); // use cookieParser
server.get('*', (req, res) => {
return handle(req, res);
});
server.listen(3000, (err) => {
if (err) throw err;
console.log('> Ready on http://localhost:3000');
});
})
.catch((ex) => {
console.error(ex.stack);
process.exit(1);
})
Later in the code I access the node req object. In development mode req.cookies is present as I would expect. In production mode it's absent.
It looks like there is no server.js file in the production build directory. What's more, grepping for cookie-parser and cookieParser in said production build directory yields empty results.
Any idea what's going on and how to get cookie-parser working in a production NextJS build?

Found the answer on the same GitHub page.
When using a custom server with a server file, for example called
server.js, make sure you update the scripts key in package.json to:
{
"scripts": {
"dev": "node server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js"
}
}
One problem with the production build down!

Related

How can I deploy next js app on an ubuntu vps

I'm working on project. where I have created the rest api with node / express.
I have deployed the rest api on my vps with nginx and pm2.
http://umer.pawnhost.com/
I have created the front-end with next js. I'm not using the api folder of next js.
I am using .env.local and next.config.js
I have looked at the next js documentation but they're saying either deploy on vercel or create a custom server.
I didn't get the custom server part
here's how my folder structure looks like:
client (Next JS)
------
.env.local
next.config.js
...
server (Node / Express)
------
...
package.json
.env
.gitignore
How can I deploy my next js app on the same vps?
You can add a frontend express server that handles routing for your nextjs app.
Create a server.js and add the following
const express = require('express');
const next = require('next');
const port = 3000;
const dev = process.env.APP_ENV === 'local';
const app = next({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.get('*', (req, res) => {
return handle(req, res);
});
server.listen(port, err => {
if (err) throw err;
});
});
build and start the server
"build": "next build",
"start": "NODE_ENV=production node server.js",
This will start a server at the configured port

Routing error when using express generator

I tried using express generator by using express --ejs command.
All is good when I typed npm start in the terminal and went to http://localhost:3000/.
Now I tried adding a new route '/shop' like so:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
/*GET Shop page */
router.get('/shop', (req, res) => {
res.render('shop');
});
module.exports = router;
and add a file inside "view folder" called shop.ejs.
now, when I go to http://localhost:3000/shop there is a 404 error.
Did I miss something? I tried reading the express docs and other guides and I'm sure I didn't miss something.
Could you re-start your server.. The default npm start command doesn't automatically watch for changes.
To automatically watch for changes so you don't have to restart your server everytime, you can use nodemon
In your package.json
Add a new script/command. I'll call it dev in this case..
"scripts": {
"start": "node ./bin/www",
"dev": "nodemon ./bin/www"
},
Then start your app using
npm run dev
# or
yarn dev

How to transpile node cli app using babel

I am writing mt first cli app with node and I am facing some issues using babel to transpile my code.
Basically, the app should start an express server which does ssr for react (similar to what next does).
Somewhere in the process I use jsx syntax to render react component, so I need to transpile my code with babel.
I am familiar on how to do this with babel cli or with webpack,
howevere, I`m still facing issues implementing it for cli app.
In my package.json file I have:
"bin": {
"ssr": "./cli/ssr.js"
},
and my ssr.js file:
#!/usr/bin/env node
const server = require('../server');
const routes = require('../../routes.js');
const createStore = require('redux').createStore;
const port = process.env.PORT || 3000;
const args = process.argv;
const defReducer = function(state={}, action){
return state;
}
const configureStore = createStore(defReducer);
const instance = server(routes, configureStore, {}, {});
instance.listen(port, ()=>{
console.log(`ssr server runs on localhost://${port}`);
});
and my server.js file is just a regular express server:
const express = require('express');
const cors = require('cors');
const renderer = require('./renderer');
module.exports = (Routes, createStore=()=>null, renderOpts={}, routerContext={})=>{
const app = express();
app.use(express.static('public'));
app.use(cors());
const port = process.env.PORT || 3000;
app.get('*.js', (req, res, next) => {
req.url = req.url + '.gz';
res.set('Content-Encoding', 'gzip');
next();
});
app.all('*', (req, res) => {
const store = createStore();
const promises = matchRoutes(Routes, req.path).map(( { route } ) => {
if (typeof route.path === 'undefined') { return null; }
let ctx = {store, module:route.module, req, res}
return route.loadData ? route.loadData(ctx) : null;
});
Promise.all(promises).then(() => {
const content = renderer(Routes, req, store, renderOpts, routerContext);
if (context.url) {
return res.redirect(301, context.url);
}
if (context.notFound) {
res.status(404);
}
res.send(content);
});
});
return app;
}
inside server.js file I call renderer which does:
const content = renderToString(
<Provider store={store}>
<StaticRouter location={req.url} context={routerContext} basename= {opts.baseName || ''}>
<div>{renderRoutes(Routes)}</div>
</StaticRouter>
</Provider>
);
and this is where I get my syntax errors...
I also tried to precompile my server.js file using webpack and babel
and than link the bin command to the bundle.js output but it didn`t work
I get this error popping on the screen:
What is the correct way of using babel with cli app?
I followed a few steps here which you can find by going here https://babeljs.io/setup and clicking "CLI". I was able to transpile your server.js JSX following those steps, plus a couple extra in a fresh new folder. In order to transpile your code, here's what I did:
Created a package.json by running (used all default values)
npm init
Created src\server.js file with your small <Provider> excerpt above
Ran the following commands to install babel and the react libraries:
npm install --save-dev #babel/core #babel/cli
npm install --save-dev #babel/preset-env
npm install --save-dev #babel/preset-react
Created a .babelrc file with this single line:
{ "presets": ["#babel/preset-env", "#babel/preset-react"] }
Created build script in package.json
scripts: { "build": "babel src -d lib" }
Ran the build:
npm run-script build
And it successfully ran and transpiled the js into a new file within the lib folder. Try it out in a brand new folder and let me know how goes works for you

How run in same port Angular and Node.JS Express?

This is might be possible to duplicate question but not able to understand how to configure FE and BE together run them both.
I've gone through this and this questions, but couldn't understand.
My Node+Express running on 4300
app.post('/postData', function(req, res) {
//some worst logics here :)
});
And
Angular 5 running on 4200. Below is my FE service that calling post endpoint
postData(feData) {
console.log(feData);
this.http.post('/postData', feData, this.httpHeader).subscribe((data) => {
});
}
What I tried is opened two cmd Windows: one to run server.js by node server.js and another one with ng serve.
Result:
404 not fount(cannot post)
What am I doing wrong.
What you need to do on this case is move your Angular 5 application to run under express process. You can achieve this following this tutorial - See item 2
I removed some complications but I really recommend you to take a look on the tutorial.
npm install --save express body-parser
Create a file to run your node app like server.js and add following code:
var app = require('app.js');
var debug = require('debug')('mean-app:server');
var http = require('http');
var port = normalizePort(process.env.PORT || '4300');
app.set('port', port);
var server = http.createServer(app);
server.listen(port);
server.on('listening', onListening);
function onListening() {
var addr = server.address();
debug('Listening on ' + port);
}
Edit "package.json" to specify how you app will start:
"scripts": {
"ng": "ng",
"start": "ng build && node server.js",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
Now, create app.js which will run express:
var express = require('express');
var path = require('path');
var bodyParser = require('body-parser');
var sample = require('./routes/sample.js');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({'extended':'false'}));
//Put your angular dist folder here
app.use(express.static(path.join(__dirname, 'dist')));
app.use('/samples', express.static(path.join(__dirname, 'dist')));
app.use('/sample', sample);
module.exports = app;
It's a good practice to create routes folder for your elements. Create a file routes/sample.js with following content:
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.send('RESTful API');
});
module.exports = router;
Run the server using node command:
npm start
By Experience, Keep the Backend or Microservices separate from your frontend applications.

Angular 2 cli with Express js

I want to use express js w/ node js to be my server for an angular 2 project. I was looking at tutorials for integrating express js w/ the angular cli (I followed this and this) and I had no luck. Does anyone have any suggestions on how to do this? Currently I have a new project up w/ cli just something that says "app works!" and want to try to do it using express as opposed to using the lite server. any help is appreciated!
this link works for me, but with some changes.
I install angular-cli and create new project, then I follow the tutorial of the link but with this changes:
I create a folder called node_server
In run npm install express --save in root folder of my project. This add server like dependencie in your package.json without create new on node_server.
I create a new file in node_server called server.js, with a basic express server. This server only returns the index.html of dist folder.
Added the scripts to the package.json, the scripts are the same in the link tutorial, but with one change, the filename is server.js not index.js
This is my server.js file :
const express = require('express');
var app = express();
var staticRoot = __dirname;
app.set('port', (process.env.PORT || 3000));
app.use(express.static(staticRoot));
app.get('/', function(req, res) {
res.sendFile('index.html');
});
app.listen(app.get('port'), function() {
console.log('app running on port', app.get('port'));
});
I hope this works for you.
The above comment worked pretty well for me,
just needed to make some adjustments to the scripts in package.json suggested in that link.
"build:nodeserver": "ng build && cp node-server/* dist",
"build:nodeserver-prod": "ng build -prod && cp node-server/* dist",
"serve-build" : "npm run build:nodeserver && nodemon dist/index.js",
"serve-build-prod": "npm run build:nodeserver-prod && nodemon dist/index.js"
I have a folder called node-server
which has my server.js file like above with routes for angular2 app as above,
and some api routes in there too, and some other folders in the node-server like mysql-requests and some files like config.json file
What I do create 2 folder on is your express server (I am using
Express-generator) and 1 is Angular 2 project (Angular cli )
root folder
--->server
--->ng4
---> gulpfile.js
gulp will build your app and move build files
var gulp = require('gulp')
var rename = require("gulp-rename");
var deletefile = require('gulp-delete-file');
var exec = require('child_process').exec;
var runSequence = require('run-sequence');
gulp.task('build', function (cb) {
exec('cd ng4/ && ng build', function (err, stdout, stderr) {
cb(err);
});
})
gulp.task('rename', () => {
return gulp.src("./ng4/dist/index.html")
.pipe(rename("ng4.html"))
.pipe(gulp.dest("./server/views"));
})
gulp.task('deletefile', function () {
var regexp = /\w*(\-\w{8}\.js){1}$|\w*(\-\w{8}\.html){1}$/;
gulp.src(['./server/public/index.html',
'./ng4/dist/**/*.*'])
.pipe(deletefile({reg: regexp,deleteMatch: false}));
});
gulp.task('move', function () {
return gulp.src(["./ng4/dist/**/*.*"])
.pipe(gulp.dest("./server/public"));
});
gulp.task('default', function(callback) {
runSequence('build','rename','move','deletefile',callback)
});
In this way you can developed in ng4 app and run gulp command on root .
I have this scenario; however, I want to be able to:
run my angular CLI project using ng serve instead of modifying any gulp tasks/ processes and without having to run ng build every time
have a server-side API responding on its own port independently of the frontend -- this way the microservice architecture pattern is used and concerns between frontend and backend are separated.
To accomplish this, I used concurrently with the below package.json script modifications
"scripts": {
"start": "concurrently \"npm run-script start-frontend\" \"npm run-script start-backend\"",
"start-frontend": "ng serve",
"start-backend": "node index.js",
...
My backend index.js file is boilerplate but looks like this...
const express = require('express');
const router = express.Router();
const app = express();
const PORT = process.env.PORT || 3000;
router.get('/', (req, res) => {
res.json({ Hello: 'World' });
});
app.use('/api', router);
app.listen(PORT, function() {
console.log(`API running on port ${PORT}`);
});
Now, when I want to run the app, I can type npm start to get everything running. Then, I can go to...
http://localhost:3000/api/ to access the backend
http://localhost:4200/ to access the frontend

Resources