Hi, Habr!
A long time ago we released a pilot
project about the MEAN stack (Mongo, Express, Angular, Node), which in general did not disappoint us, however, we decided not to do reprints and updates in due time, unlike the publishing house Manning, which
updated this book. . Nevertheless, we continue to search in this direction and today we would like to talk to you about the related MERN stack, where React is located not on the client Angular. The
floor is given to
Tim Smith .
Pre-notification: all the code for this article is
here .
')
In this tutorial on the MERN stack, we’ll write a simple blog using React.js, Node.js, Express.js, and MongoDB to expand our full-stack arsenal.
What is a “stack”?
Perhaps the first thing to discuss is the idea of ​​a “stack” as such. There are many different stacks, and all of them are just different ways to achieve the same goal. Creating a full-stack application, we envisage in it the client part with which the user will interact, and the same client part will mediate work with the server and the database - making the whole process as simple and manageable as possible.
We can say that the stack is a certain set of technologies used to solve this problem.
Although there are a lot of stacks, which would be worth talking about, some of them are more popular today than others. One of these popular stacks is called MEAN, and it consists of:
- M ongoDb
- E xpress.js
- A ngular.js
- N ode.js
Today we’ll talk about the MERN stack, which is very similar to MEAN with the exception that Angular.js is replaced by React.js. Thus, we will be able to use MongoDB as a database, Node.js and Express respectively for the server and routing, and React.js - to create the client part with which the user will interact.
How is development done using this stack?
Before turning to all the subtleties, let's take a general look at how all these elements work together. Personally, it took me some time to understand this, because my background is related to PHP, where the client and server parts are somewhat mixed up.
1. Server side (Node and Express.js) and client side (React.js)
First of all, you need to understand that the server part and the client part are separate entities. The client part can be in the same repository with the server, and maybe in a completely different one.
2. Used for communication terminals API
If you are already thinking about how to make friends client and server part - I will answer: this is done through the API. The API (application program interface) is created on the server, where we will have “terminals” through which the application located in the client side can interact with the server.
Let me explain on the fingers: imagine that your left hand is the server part, and the right hand is the client part.
Now fold your arms and twist your fingers as if you were shaking hands with yourself. This is exactly how templating languages ​​work. They allow you to simply display some markup along with the data dropped from the servers - and in them the client and server components largely overlap each other.
Now open your hands. Spread your fingers as wide as possible and make sure that your left and right hands touch only with your fingertips. This is how the MERN stack works. The server side provides terminals (fingertips with the left hand) for access to the server, to which the client side sends calls (through the fingertips of the right hand) and communicates with these servers (left hand) through these points of contact.
I hope it has become a little clearer, and if not, forget the whole metaphor, as if I didn’t mention it.
Our backend from Node.js and Express.js
Although I am not going to give here step-by-step instructions on how to build this stack (this is a topic for a separate article), I would like to consider the various elements of the stack that are commonly used or can be used in it. I read several manuals myself, telling how to set up a server, but it did not explain why these particular libraries are used for this purpose.
After we create the app.js file, we need to install a number of packages. Below are the most common packages that I used to use in my projects with Express.js - perhaps they will be useful to you.
- Express.js is a framework for creating web applications. It has built-in functionality to solve many problems, in particular, to establish routing.
- Mongoose is an object data manager (ODM) that provides interactions between the express.js application and the MongoDB database.
- BodyParser is a library that allows the express.js application to read the body (that is, the content) of incoming requests.
- DotENV - allows you to use files with the .env extension to work with confidential data.
- Passport.js - provides authentication in our application, and provides several different authentication methods.
- Validator - simple validation of many data types
- bCrypt - encrypt sensitive data, such as passwords
- Nodemon - “hot reboot” for our node-server in case the situation changes; thanks to Nodemon, you can not stop or restart the server after making any changes.
Of course, there are many other packages, but in my experience, these libraries are used most often.
So, having dealt with some of the most actively used packages, let's look at the code. To begin with - our server:
This is a simple API server. As you can see, it is equipped with the basic CRUD (Create-Read-Update-Delete) functionality - nothing supernatural. Looking closely at it, we’ll see that
res.json()
is used here to provide output data for a specific URL — that is, no HTML or other template is used for output. This is how we build our APIs by opening data access for React.js.
You may also have noticed that I just pointed mongoose to my own mongodb server installed on my computer. For this mechanism to work properly, MongoDB must be installed on your computer and work. If it doesn't work, just open a console window and enter the following command:
It will start the MongoDB server on your local machine. Since all this is done locally, you will not be able to see my posts if you run the code from the repository. We'll have to write new content ourselves. If you need a content-stub, I recommend the excellent
Fillerama.io generator,
chopping text from some of my favorite movies and TV shows.
If you are interested in testing the server yourself, you can run it with the following command:
After the server starts up and tells us that it is working on port 3333, and that it has connected to MongoDB, you can open
Postman and test our routes there. As for the GET options, you can simply insert the route and click “Send”. In the case of POST, you will have to select “Body” and fill in the fields for the title and main content.
Note about the client part
Now that we have configured and launched our server, we can start working on a client with which our users will interact. The client will be written in React.js, and this can be done in several different ways.
The first is to simply add all the necessary libraries for the client part (react, react-dom, react-router, etc.) all in the same
package.json
file where we wrote the server libraries. In this project, I did just that, but I must note that I do not consider this option the best. I think that as our project grows, the code base will become increasingly confusing, and if we use exactly this method, then in the future work with it will become more complicated. I preferred this path in the application being described precisely because I know for sure: it will not grow and in general will not change at all. This application is written solely for demonstration purposes.
The second and (in my opinion) more optimal approach is to create a separate repository for the server part and a separate one for the client part. We still can easily clone the client-side repository into the directory with our project, just to make sure that the client part is specified in our
.gitignore
file. For example, in the file structure for this application there is a
client
directory, where all the client-side code resides. We could put it in a completely separate repository, and then just add the following entry to our server’s repository
.gitignore
file:
By adding the
client
folder to the
.gitignore
file, we guarantee that the system will not take this folder as the second repository in the project. In addition, this approach facilitates the work of redesigning or replacing the client part, since the server part is completely unaffected.
How exactly your full-stack application will be designed depends solely on you. It just seems to me that if you keep separate repositories for the client and server parts, the structure of the application will be a bit more accurate.
We create client part on React.js
Now, having dealt with the organization of the project, let's talk, actually, about the client code. Below is my
app.js
file for an application on React.js, and I will not embed the code for each component in this post, but simply leave a
link to the repository and explain what each React component is doing.
This is how the screenshot of the main page of our application will look like:
As you can see,
app.js
absolutely nothing complicated in
app.js
There is a <Router>, which allows you to set routes in React.js, which display the various components based on their URL. And here are the other components that will be used in our React.js application:
- Header - Navigation bar located at the top of the screen
- Index - Lists of available blog entries
- New - The form through which the user can create a new post
- Single - Displays a specific blog entry based on its
id
- Edit - A form through which a user can update a blog entry found by
id
We use Axios to make http calls to API terminals, and then launch React.js to display the data as we please. In this post I will give the Index.js code to make it clearer how it all works together.
The above code involves a class component that allows us to use the state and methods of the life cycle. This is necessary because Axios calls must be made in the
componentDidMount()
life cycle method. It should be noted that I received a CORS error when I tried to make calls to my local API. To solve this problem, I added several headers to the server.js file in my Express server - and it all worked. This code is noted in the server.js comments.
Let's make sure that search robots read our React.js application normally.
Rounding out, I would like to talk briefly about rendering. If you run our site and go directly to any blog post, then there may be some problems with the display of content. In this case, it will be inconvenient to browse the site, not only for users, but also for search engine robots indexing content. To work around this problem, I recommend using tools like Gatsby js or Next js. The two solutions are different, but both can be useful, depending on what you need.
Gatsby js is a static site generator. You can write a site on React.js, and then Gatsby will turn it into static files during the build process, as a result of which the site will become super-fast. Gatsby comes with many useful plug-ins, thanks to which the tool becomes almost universal. By the way, my site is made using Gatsby.js! Since static files are created at build time, the site needs to be rebuilt whenever the source content changes.
Next.js , in turn, is a server component for displaying React.js sites. It has many useful features built in, such as routing, code splitting, styled components, and more. Server rendering means that the data will be updated automatically, as is done on the server, but, before being displayed in a browser window, the rendering phase will be performed. That is why no problems with the display of data to the user should not be, and the search engines will also do their job without problems.
There are many other solutions of this kind, but I have heard about these two most of all, and during the work on this project I used them. Both are perfectly documented, so it’s easy to quickly deal with both and get down to business.
Final thoughts on the MERN stack
I hope this article has helped you a little more accurately imagine how the MERN stack works. In it, we just take MongoDB, Express.js and Node.js and create from them a server that already provides API terminals, through which our React.js application can access data. So now you understand a lot, it’s time to do great things!