Next.js Architecture - javascript

I am looking for some Next.js Architecture advise please 🙏
I am in the middle of migrating a very large express NodeJS app which has a custom SSR setup over to a Next.js setup.
For the current NodeJS site I have:
A bunch of routes (which hook up controllers / apis, do fancy redirections etc)
Have a ton of middlewares
Ton of logic in a bunch of express controllers (these controllers do things like API calls, transforming data, validation and the SSR of some React components to form the application)
Most of the time the NodeJS server calls other Microservice APIs (on the same VPC) to fetch data within these controllers (eg: search api, auth api, location api etc - which are all seperate REST api servers) Note: when it fetches from these APIs its done so on an internal api address only
The React Website itself calls the same NodeJS server to fetch data via client side JS when there is a route change eg: The frontend URL would be: www.mywebsite.com.au
And any api call done from the frontend is done with route: www.mywebsite.com.au/api/*
Based on all the docs i have read so far, I figure the best setup is:
To keep my existing express setup for routes / middlewares (for which I have a ton of) this includes the /api/* ones
Migrate controller fetching logic to the publically accessible express apis /api/* (which I kind of already have but need to clean up)
For the existing express controller routes, route these to Next.js instead and use nextApp.render to specific next pages
Use getInitialProps in the Next.js pages to fetch data from those apis I mentioned in 2.
Also add the old prop transform logic that was in the express controllers to getInitialProps
This is so that the server and client share the same logic of whats in getInitialProps - and this will make the architecture clean and give me the ability to have smooth transition to use Link.
The thing im struggling with it is step 4.
It means now on SSR of a page request it needs to call out to the public api (www.mywebsite.com.au/api/*) on getInitialProps to fetch its data.
To me seems like a performance overhead to do this as it requires a network hop to public domain mywebsite.com.au to fetch data it could have got locally on that same request (by calling localhost:3000/api/* for instance)
Any advise on how to avoid the network hop outside for server render?
Can I detect if its a server render and then use an internal URL (eg: use localhost:3000/api/* on the request to the same web server) or is that not best practices when using Next.js?

The server needs to call out to itself to fetch its data, alot of the overhead involved with fetching data is around the delay (I.E Between the client and nearest datacenter) this will be less of a concern when its (datacenter -> datacenter).
If performance is still an issue, your next best bet will be to do SSR caching, of which there are many different methods alot you can find in a quick google search however it will depend on your hosting/setup.

I treat listing-page.jsx and handler for api/listing route to be the same. You may need to write 2 small functions to extract the parameters passed into the request and pass it down to your service module function like ListingService.getSingleListisng(id)

Related

Use NuxtJs on server-side to Hydrate a Cordova client

I'm trying to upgrade an old mobile application written in vanilla Javascript+React hosted on Cordova. This application leverages a simple api on the server-side:
when the app requires a page, sends a request to the server
the server elaborate the request, fetch the resources, and then reply with a complete HTML+JS. The Javascript is a ReactJs view compiled with Gulp/Browserify
the app takes the reply and stores it in a local Sqlite DB, then mount the received code and the view become reactive.
if the user requests a view but has no connectivity, the app search though the Sqlite db wether there is a cached view and uses it instead of requesting a fresh copy from the server.
When developing, the React JSX code is immediately compiled to a vanilla JS so, when in production, the api only needs to merge the vanilla JS with the HTML template. Plus, adding new features and fixing bugs is quite easy, because each user essentially download any updated view, each time he enters in it.
The problems with this approach are:
developing is painful because of the continuous compilation
a "base" part of the application resides on Cordova assets (basically the utilities to fetch from server, caching etc) and fixing this parts needs a new app release or ugly override patches
the caching feature often causes problems to the Sqlite database (which is used also for other stuff on the app); as a result, the DB sometimes corrupts and the user must clear the app data.
we would like to get rid of React
We already used NuxtJs for generating static sites, and it's great, but in this case I cannot leverage the SSG because the app should be almost completely served from the api, so we can keep the easy-feature-and-fix stuff.
I never used NustJs SSR and wonder if could be suitable for my use case, for example, could I spin up a NuxtJs instance on server-side which generates the html output and hydrate a barely empty Javascript client on Cordova? Is there a better way to accomplish this task? Should I use only Vue instead?
Thanks

How should I handle front end routing in webpack?

I am building a website with separated front end and back end via restful api. When I develop the front end UI, I bought a template that uses webpack to generate the bundled production files.
Currently I am using pure javascript to handle the routing. For example, to show different view for logged in users compare to other users, I did the following:
if (window.location.pathname === "/") {
const token = window.localStorage.getItem("token")
// if token exists and it has not expired, show the logged in homepage.
if (token && !jwt_expired(token)) {
window.location.replace("/index-loggedIn.html")
} else {
window.location.replace("/index.html")
}
Here are my questions:
I notice window.location.replace could be pretty slow and it would take half a second to route from index.html to index-loggedIn.html. Is this the right way to do it?
I am planning to deploy the front end static files on Nginx as a web server. I guess this workflow will be like:
User sends a request to the "/" route -> Nginx responds with index.html -> The above javascript code gets ran -> Another request to "/index-loggedIn.html" gets sent to Nginx -> Nginx responds with index-loggedIn.html
Is that what actually will happen? It sounds very inefficient to me since I would like to be able to check user's log in status before serving the home page.
Is there any other frontend server/framework I can use to make the routing easier? Then I can use Nginx simply as a reverse proxy. I checked out Angular but I think it will take too much effort to convert the whole template into Angular's format. Can I use express just for front end routing?
Thanks in advance for your suggestions!
You are asking too many things with too many assumptions. Let us try to uncover them step by step.
Type of Application
Basically, you can build two types of applications: SPA (Single Page Application) or Multiple independent pages application; or the hybrid of two Multi-page SPA application. Typically, we use React/Vue/Angular to build a SPA application.
Routing in SPA application
In a SPA application, the routing is completely done on the client-side. The server plays very little role in it. We use HTML History API to achieve this (This is what you are doing by hand using replace method).
With this setup, you need a UI Server (typically build with Node.js) or a Nginx like Reverse proxy. Your server won't be aware of the routes that client-side code has defined. The server/reverse-proxy needs to do two things. First, when the request is for asset (request ending with .html, .css, .js, .png, etc.), then it should try to serve that asset. When the request is for non asset (request without any file extension https://example.com/users/), then you can safely assume that it is a request that must be handled by the client (your client-side code has defined the routing) and thus you must always and always send index.html page which then will bootstrap your SPA application.
In the initial boot sequence of the SPA, you would read the location and determine if this is a valid route. If this is not a valid route, you can redirect user (client-side only) to some default view or 404 view.
Why you would need to do this? Because initially, your user may just say https://example.com and then navigate to /users route by some action. But, if user does full page refresh after navigation, you back-end server will see the route as https://example.com/users. There you need to handle the fallback route to always serve index.html. In this case, 404 must be handled by using client-side code. All the major UI frameworks provide routing solution. You don't need to do it by hand.
Authentication
Now if you using using index-loggedIn.html for authenticated views and index.html, then from SPA perspective, you have a anti-pattern or code-smell at least. You must have a single index.html view which takes care of both authenticated and un-authenticated views. In routing world, we typically use guards to protect the views from unauthorized access.
What you are doing would currently work but as you mentioned that you see the lag of half seconds before redirect. And, that would happen on every page refresh. But that exactly is the problem with full client-side SPA apps in general. However with proper architecture, you should be able to address this.
Routing in a Multi-page SPA or multiple pages application
If you are building an application like this, then your server needs to be more involved and must handle more routing responsibility. In this case, you should probably use cookie instead of localstorage for managing your token. Browser automatically sends the cookies to the server and your server then can make the decision if it wants to serve index.html or index-loggedIn.html page.
To answer your question:
Is this the right way to do it? - It would work but it is an anti-pattern.
Is that what actually will happen? It sounds very inefficient! - It is not inefficient as long as you are properly loading the views with spinner and doesn't cause awkward UX for the users.
Can I use express just for front end routing? - It is an invalid question. Literally, you cannot use express for front-end routing. But then if you plan to implement UI server using express, then you can use it to define proper routing architecture eventually making it part of your front-end stack.
In the end, note that there are few more consideration that you need to take into account. What happens when user is doing hard refresh when he is on some route that server doesn't recognize? How to properly support bookmarking capability for your users? Also, are you building SPA or traditional server rendered application? If SPA, use client-side framework. If server rendered, then keep all the logic inside Express or equivalent code. If it is hybrid, determine the architectural boundary.
Finally, if this sounds too complex consider using hash-based routing for your SPA. That simplifies many things at the cost of not-so clean URLs.

Next api and backend

In NEXT project, API Routes let you create an API endpoint inside a Next.js app. You can do so by creating a function inside the pages/api directory that has the following format:
// req = HTTP incoming message, res = HTTP server response
export default function handler(req, res) {
// ...
}
Then what is different between express backend and next api.
If I use next api, can I build all backend and frontend?
And how can I get access to database on next api?
Is that possible?
If I use database configuration on next api, then how will it be rendered in SSG?
I can only speak of what I know about the question. In my current project, we use an Express server with Next.js.
Reasons to Use Express With Next
Express has lots of middlewares available and the ecosystem around it is solid. In my case, we already have multiple Express apps in production. Adding the Express layer helps us keep the behaviors of different servers as similar as possible.
Reasons to Use Next API Route Directly
Next API routes are straightforward if you don't have many custom middlewares. Next.js already come with common middlewares to handle many common tasks. I think the decision comes down to where you are going to deploy your application. If you want to use Vercel with serverless functions, you can't use a custom server. You can find more information about serverless here
Can You Build Backend & Frontend with Next and its API Routes
Yes, you can absolutely do it. But you have to decide whether this is a more suitable solution.
Can You Access Database in API Routes
Yes
What About SSG
As far as I know, API routes are part of a server bundle. Next.js will not statically generate page/api/**/*. All your SSG pages should work as expected.
I hope I provided some useful information here.

Understanding how ReactJS and NodeJS app can work

I'm trying to learn React JS, but I have difficulties understanding how it should work with NodeJS, let's say with Express.
So far I understand that ReactJS is "V" in "MVC"
This is easy, I can already write a code using create-react-app
This is how I understand that:
"natural" way of combining React and Express is to simply write frontend in React and api in Express (with Mongo for example).
This way we can simply make ajax calls from React to our /api and show data
there is also a possibility to use React to server side rendering, which requires little more configuration. This way we do not call /api from React, we just use React to write code which can be rendered by Express
My question is Am I thinking right ?
Not sure about all that...
Is Isomorphic JavaScript somehow related to #2 ?
You are mostly correct, but using server side rendering does not mean you do not also issue api requests ever. Server side rendering is a technique used to improve initial load time. Rather than pulling down your javascript bundle, which then makes some api calls to load a bunch of data it needs to render, you instead do that initial rendering and bootstrapping of the app on the server. The resulting html and initial state of the application are then returned to the client so the app can be shown immediately to the user. So when talking about server side rendering with react, it's really about the initial load.
After the initoal load, you still have a dynamic frontend applicatoon. You still end up making api requests as the user interacts woth the app. If I go to a different route in the app (assuming it's a single page app) which requires additional data, I'll still be issuing a GET request to load that data. If I click a button to update a resource, I'll still be issuing a PUT or PATCH request to do so.
So in terms of the question of how express and react fit together, express (or whatever backend language/framework you use) provides the api to interact with data in your data store. And react is allowing you to build views that consume those apis. Server side rendering is just an additional technique you can use, not a totally separate paradigm.

Nodejs API controller for switching between APIs

Is there such thing as an API controller in Nodejs? An API layer that communicates with multiple APIs [that each return the same type of data, but completely different data models] and massaging the data to return to our client-side display? Is there a different term for this?
I have a simple CRUD application.
AngularJS front-end calls my RESTful Nodejs APIs on the back end.
Now, however, there is a 3rd party who has their own APIs and data that I would like my front-end to be able to use if the user wishes.
The data from the 3rd party API's is similar data to ours, but will not follow the same data model. I am trying to wrap my head around how I should begin to write an API the front-end will call that could go to either our API or the 3rd party [and possibly future 3rd parties] and massage the data so either way it is the same to the display.
Any resources or better ways to handle this scenario?
Yes, there are a number of ways this could be accomplished with nodeJS. How you set it up will be dependent on the details of your project, but here are a few ways to get that functionality:
Setup an endpoint that queries other endpoints. For example, all api requests hit /api/1.0/:routing_params, and based off of that routing_param send out requests to various other apis. This data is returned to your backend which then sends the response to the browser.
Use something like expressJS to mount multiple routers, with each router handling the various endpoints for each api. Documentation for express routing can be found here. ExpressRouting
Depending on your scaling/performance requirements you can also consider using something like nginx to handle incoming requests and direct them to separate nodejs processes handling the various api logic. This may be overkill, but is an easy way to keep things modular if you expect the need to run multiple nodejs processes and handle multiple future api endpoints.
That should provide some starting points, what you choose to do and how you implement it will be highly dependent on the specifications of your application.

Categories

Resources