Server Side Rendering in React with no configuration

Creating a React application is simple, but especially those who are beginners (included me) in this world of programming, sometimes we let slip certain terms, for example, Server Side Rendering (SSR).

There are many articles dedicated to this topic and certain professions dedicated to this area, for example SEO. But quickly, to place ourselves in this context; our pages/applications have labels with information that allows browsers such as Google to define the theme, category, type of content, among other parameters, which is our focus on the web or where we want to go (target market).

With good practices in the SEO trade, the “crawlers” will give the information to Google, and after a certain analysis the search engine will define the position of our website among the search results.

But React, by default, does not perform this type of task or at least does not offer us the possibility of doing it.

A few months ago we shared with you a blog dedicated to the creation of a React application but with the SSR feature (here). In the small demonstration application we use a small framework called Next JS, who makes SSR work accurate in Javascript applications.

We’ve been working with Next JS, and we can say that it is very good, however it has some characteristics unrelated to React (because Next JS can be added to any JS application) that makes us configure some files in a slightly more complex way; as technology lovers we know that every resource is being improved with the passage of time, and with that comes practicality and ease of use.

Now, we met a new tool called Razzle. It is simply the same work that is done with Next, but Razzle tries to deviate as little as possible from React, as well as configuring as little as possible and therefore brings some of the libraries by default.

For example and perhaps the most valuable thing for those of us who have dealt with the use, is the navigation and Razzle allows you to use react-router-dom already integrated.

Also Razzle is useful with Reason, Vue, Elm and Angular according to their own documentation.

To create the Razzle project just type in your terminal:

npx create-razzle-app app-name

The above command will create the necessary files to start working, start by modifying your App.js in the same way you do with a React project. You can see the configuration of server.js and check the use of express, as well as react-router-dom and react-dom for your backend and frontend work.

yarn start

In conclusion, I am really fascinated by Razzle, the use has been little, we are still in full investigation of the tool, we write this according to the experience we have obtained, therefore if you have something to share about this tool we thank you participate in the comments section to help the community.

It can be simply your appreciation to Razzle or some problem or error that you are getting, so we can help you or someone could also contribute to that solution you need.

We are willing to learn with each contribution assuring us of the benefit of all of us who are in this beautiful and great world of programming.

Deploying a ReactJS and NextJS project to Firebase

We are in one of the best moments as developers, living among wide range of technologies, tools and trends that every day only grows and grows, and if you are passionated about learning and applying technologies during your spare time, today is the time.

Today we will focus precisely on ReactJS and the performance we can provide to our applications using the scalability of Firebase with Cloud Functions itself.

In addition, we will use the NextJS framework to server rendering, which will help us to easily configure and solve SEO issues but, more importantly, the lower degree of latency between server and client to offer the users the best experience.

Let’s start!

We need first to install Next.js in our work environment:

npm install -g create-next-app

Followed We create a project named “firebase-nextjs”:

create-next-app firebase-nextjs: this command will create the project but it will also install the react and react-dom dependencies, which can be seen in the package.json file.

We run yarn dev and our project will run, by default, on port 3000 (localhost:3000).

NextJS will search the corresponding file in the pages folder for each route, for example: the path “/” indicates that the file pages/index.js will be searched.

The framework is built on React, it maintains a structure appropriate to it, which is why we can see a folder called “components”, where each component we want to use for our views will be store.

So, if we use NextJS and React, why not to add Material-UI?

Let’s install locally Material-UI: npm install @material-ui/core.

We will create two very simple pages to observe the behavior of these three frameworks made to make life easier!

In the folder pages we create “page1.js” and “page2.js”.

We add the following code to pages/page1.js:

import Card1 from ‘../components/card1’

 

const Page1 = () => (

 <div>

   <Card1 />

 </div>

)

 

export default Page1

In the folder components we create “card1.js” and add any of the examples in Material-UI in the cards section and personalize it in our own way.

To see the content of the page page1.js we can go to “http://localhost:3000/page1” or use Link of NextJS to redirect us.

We do the same steps for “page2” and “card2”.

Up to this point, we should have a NextJS application working perfectly with React components.

We are ready to enter the most interesting part of this post. We are going to structure our project according to the guide of James Hegedus.

Therefore, at the root of our project we create a folder called “src”, inside this folder you will find another another called “app”, where our entire application files will be stored, we might move all the files to the “app” folder.

We will go to the firebase console and create our project.

We will be presented the general panel of the project, as you can see, Firebase gives us Authentication, Database, Storage, Hosting, Functions and ML Kit, each of them very interesting, but we will focus on Functions.

Why Functions? If we do not use NextJS, and it is enough that in our source code of the application we see only some ‘<script>’ tags then the option would be Hosting, but we want to get the server rendering and the magic of NextJS that is really amazing.

Next we run the following commands in the root of our project:

  • yarn global add firebase-tools
  • firebase login
  • firebase init

When we run firebase init, a series of questions will be displayed:

  • Which Firebase CLI features do you want to setup for this folder? | Select “Functions” and “Hosting”.
  • Select a default Firebase project for this directory: | Select the project that you created earlier in the firebase console.
  • What language would you like to use to write Cloud Functions? | In my case is “Javascript”.
  • Do you want to use ESLint to catch probable bugs and enforce style? | Write “N”.
  • Do you want to install dependencies with npm now? | At this time it is not necessary, write “n”.
  • What do you want to use as your public directory? | Write “src/public”, two files will be created that will be created to show the first view in case of not finding any and the other in case of error.
  • Configure as a single-page app (rewrite all urls to /index.html)? Write “N”, in our case it should be a more complex application.

Ready!

We will find in the root of our project a folder called “functions”, just move it inside “src” folder.

In our file firebase.json we remove the existing code and update it by the following:

{

 “hosting”: {

   “public”: “src/public”,

   “rewrites”: [

     {

       “source”: “**/**”,

       “function”: “next”

     }

   ],

   “ignore”: [

     “firebase.json”,

     “**/.*”,

     “**/node_modules/**”

   ]

 },

 “functions”: {

   “source”: “src/functions”

 }

}

In the package.json of the functions folder we add the following dependencies (after several tests I consider that they are the versions that present fewer errors):

“@material-ui/core”: “^1.4.3”,

   “classnames”: “^2.2.6”,

   “firebase-admin”: “~6.0.0”,

   “firebase-functions”: “^2.0.0”,

   “next”: “^6.1.1”,

   “prop-types”: “^15.6.2”,

   “react”: “^16.4.2”,

   “react-dom”: “^16.4.2”

In the case of dependencies “classnames” and “prop-types”, they are needed for this example that we are developing, also as a tip, each dependency we need for our project must go in this file as well as src/app/package.json , therefore, also add the dependencies to src/app/package.json.

To make sure that NextJS runs successfully in Cloud Functions, we remove the contents of functions/index.js by:

const functions = require(“firebase-functions”)

const next = require(“next”)

 

var dev = process.env.NODE_ENV !== “production”

var app = next({ dev, conf: { distDir: “next” } })

var handle = app.getRequestHandler()

 

exports.next = functions.https.onRequest((req, res) => {

 console.log(“File: ” + req.originalUrl) // log the page.js file that is being requested

 return app.prepare().then(() => handle(req, res))

})

Now we proceed to install the dependencies in functions and in app, within src/functions and src/app run yarn or npm install depending on the manager you use.

We create a .gitignore inside the functions folder and add only “next”.

We need our material-ui components to be displayed correctly, thanks to NextJS we should only add the following to src/app/next.config.js:

const path = require(‘path’)

const glob = require(‘glob’)

 

module.exports = {

 distDir: “../functions/next”,

 webpack: (config, { dev }) => {

   config.module.rules.push(

     {

       test: /\.(ico|gif|png|jpg|jpeg|svg|webp)$/,

       use: [

         {

           loader: ’emit-file-loader’,

           options: {

             name: ‘dist/[path][name].[ext]’

           }

         },

         {

           loader: ‘file-loader’,

           options: {

             name: ‘dist/[path][name].[ext]’

           }

         }

       ]

     },

     {

       test: /\.(css|scss)/,

       loader: ’emit-file-loader’,

       options: {

         name: ‘dist/[path][name].[ext]’

       }

     },

     {

       test: /\.css$/,

       use: [‘babel-loader’, ‘raw-loader’, ‘postcss-loader’]

     },

     {

       test: /\.s(a|c)ss$/,

       use: [‘babel-loader’, ‘raw-loader’, ‘postcss-loader’,

         { loader: ‘sass-loader’,

           options: {

             includePaths: [‘styles’, ‘node_modules’]

               .map((d) => path.join(__dirname, d))

               .map((g) => glob.sync(g))

               .reduce((a, c) => a.concat(c), [])

           }

         }

       ]

     }

   )

   return config

 }

}

Let’s update our package.json that is in the root of the project with the scripts with which we will handle the application:

{

 “name”: “firebase-nextjs”,

 “version”: “1.0.0”,

 “license”: “MIT”,

 “scripts”: {

   “install”: “yarn build-all”,

   “next”: “yarn build-firebase && cd \”src/app\” && yarn && yarn dev”,

   “preserve”: “yarn build-all”,

   “serve”: “firebase serve”,

   “predeploy”: “yarn build-all”,

   “deploy”: “firebase deploy”,

   “build-all”: “yarn build-next && yarn build-firebase”,

   “build-next”: “cd \”src/app\” && yarn && yarn build”,

   “build-firebase”: “cd \”src/functions\” && yarn”

 }

}

Now, in the root project run yarn init and then you have the next options:

yarn next: We run the project locally by port 3000 by default.

yarn build-all && firebase deploy –only functions: we build our project for production and deploy to firebase.

With all the steps above the application must run successfully, the test project is available in github, so you can compare, to get a better guide and understanding of the code.

Conclusion

This is a contribution that is made from the same learning obtained, so we are willing to feedback and/or answer your concerns about the technology and the project as such.

We try to be aware of the frameworks and tools of the moment to get the most out of each one, so you can expect more from this type of blogs.

Enjoy it!

Support:

Resources we used:

  • NextJS: 6.1.1
  • React: 16.4.2
  • Firebase functions: 2.0.0
  • Material-UI: v1.5.0

References:

[30% off] Detect missed growth opportunities for your productGet a Growth Audit
+