How to do server side rendering with Feathers.js and Next.js
Feathers.js
is the most impressive back-end framework that I’ve seen in the node.js world. Like Django
and Django rest framework
in the python world. Similar API to express.js
. And very productive as you can generate rest CRUD API in seconds while still highly customizable. And has a unique concept called service
and hook
which distinguish it from the others. Next.js
is a library that you could use to do the react
server-side rendering easily along with all the toolings. Previously I set up a project which uses these 2 to do SSR, I thought it should be very easy. But to my surprise, it took me a while. I think it worths to write a blog here to share what I learned. We will use feathers-cli
to generate a fresh new codebase and start from there.
1. Overall idea
Instead of feathers.js
which sits in front of your front end app. Now it’s the next.js
‘s responsibility to handle all the related requests. So you need to:
- set it up in the
feathers middleware
, which just like theexpress middleware
. - And you need to filter the
feathers
request and pass it back to feathers, otherwise, yourfeathers service
request will be hijacked bynext.js
. - Modify some setup generated by
feathers generator
if you use it. Likestatic
folder.
2. Set up environment and next.js
2.1 Generate a feathers app
- Install the generator if you haven’t
npm install @feathersjs/cli -g
. It’s like the Cli forruby on rails
andsails.js
which focuses on generating boilerplate code and project structure for you. - Create the project folder:
mkdir my-app
. - Go to the folder:
cd my-app
- Then use
feathers generator my-app
to create your app.- When it asks for the source folder name, instead of the default
src
, I recommend usingserver
, because we will have some conventions here which will make things more clear.
- When it asks for the source folder name, instead of the default
2.2 Add the next.js support
- Install dependencies:
npm install next react react-dom
- Create folder for client-side code:
mkdir client
- Create the
pages
sub folder insideclient
:mkdir client/pages
Why we want to have different folders?
- Well, first, it’s clear, so all back-end code in
server
and front-end code inclient
. - Later on, you can have an extra
ESLint
settings in yourclient
sub-folder. WhileESLint
could lint your node and front-end code, their rules are different, at least I prefer this way.
2.3 Create the index page
This file should be at ./client/pages/index.js
.
1 | export default () => <div>Welcome to next.js!</div>; |
Later on, when you want to access /index
, next.js
will render /pages/index.js
. Just that easy.
2.4 First run
- Add a new NPM script in
package.json
:"dev": "next ./client"
- Run
npm run dev
, and you should able to see yourindex.js
athttp://localhost:3000/index
3. Setup next.js middleware in feathers
3.1 Setup next.js base
In the my-app/server
folder, create a new file named nextApp.js
with the following code:
1 | const next = require("next"); |
3.2 Start next.js when starting the server
Open index.js
, update its code to the following:
1 | const logger = require("winston"); |
We start the nextApp
first then start the feathers
server. The main benefit of this is that, later on, you could enjoy the hot module reloading while developing without any problem.
3.3 Add the next.js middleware
- In the
my-app
folder. Add a newfeathers middleware
:feathers generate middleware
:- Its name is
next
- The mount path is the default: ‘*‘ which means it will handle ALL request.
- Its name is
- Open
/server/middleware/index.js
, update the code to this:
1 | const next = require("./next"); |
The only line we changed is from app.use
to app.get
, still handle all requests, but only concern about the GET request now.
3.4 Handle the request in the new middleware
Update the file /server/middleware/next.js
with the code:
1 | const handle = require("../nextApp").handle; |
3.5 Try it
npm run start
, this time, we start thefeathers
server rather thenext.js
dev server.- Open
http://localhost:3030/index
4. Enhance the logic
Just like the typical problem in SPA, you still have the routing problem. Now as your next middleware
will hijack all the GET request, it will hijack all the GET request for feathers services
too. These are problems like this which we need to handle.
4.1 Remove the static folder support from feathers
In the /server/app.js
, comment out or remove the following line:
1 | app.use("/", express.static(app.get("public"))); |
As now all the static files should be handled in next.js
, we don’t need it anymore.
4.2 Add a filter function in nextApp.js
1 | const feathersServices = ["/users"]; |
And don’t forget to export it:
1 | module.exports = { |
So, here, in that feathersServices
array, you need to add the feathers service
endpoint into it every time you add a feathers service
like the above example.
And we use the isFeathersService
function to check whether the path
belongs to a feathers service
or not.
Why filter service rather than next.js route path
- It’s because there are other requests other than the page rendering which needs
next.js
to handle, things like all the assets on the page: theimage
file, the generatedjs
file. Filtering outfeathers services
will be a more convenient way.
4.3 Use the filter function in next middleware
Open the /server/middleware/next.js
, update the file to the following code:
1 | const handle = require("../nextApp").handle; |
5. End
You can check the whole code in my github repo.
That’s all. Hope it helps. :)
Thanks for reading!
Follow me (albertgao) on twitter, if you want to hear more about my interesting ideas.