Project introduction

Almost every programmer has a blog dream. Take a month or so to complete this personal project with the mindset of learning the front and back end techniques. This is a vue2 front-end framework, KOA2 back-end, mongodb database, set up a single page application. The site features a showcase of my own technology sharing, and a background editor to write a blog that supports Markdown syntax. This project borrows a lot from BUPT-HJM’s blog, from UI to code details. I really appreciate the open source gods. Code address github, personal website address

Project structures,

Because the front-end selection uses VUE, I want to use VUE – CLI all the way flat push to save trouble and effort, but in order to further learn Webpack, I decided to manually write from scratch. I’ll write a separate blog about the implementation details of WebPack, because it’s too much to cover, so I’ll just explain what’s implemented here.

The development environment

At present, front-end development still attaches great importance to development experience. When I worked in the front-end development of my previous company, the development environment was in a mess, thinking that this was the case in the industry (later I realized that it was the irresponsible of the front-end leader). The previous company’s development environment is really comfortable, not too much consideration of compatibility, code style mandatory uniform, hot updates and everything. So WebPack was built with hot updates, using PostCSS to get ahead of new CSS features and automatic prefixes. It should be noted that webpack hot update relies on Node. We all know that webpack-dev-server uses express framework as hot update service. However, considering that node is also the background of this development, With KOA2, it is possible to start only one Node service during development to meet front-end and back-end node requirements. So INSTEAD of using the webpack plugin webpack-dev-server, I implemented it myself. The code will be covered in detail in the Webpack blog post.

The production environment

Production environment construction, also very common some implementation. Examples include code compression, CSS prefixes, resource file path handling, image compression. Open multithreaded packaging function, here a joke that the beginning of the packaging time is about 7 seconds, according to the online packaging optimization advice of a flashy toss, the result of the packaging time rose to 9 seconds… It uses an important feature that WebPack prides itself on, splitting vue files into chunks and importing them on demand with vue-Router

// vue-router const HelloWorld = () => import('.. /components/HelloWorld.vue');Copy the code

When packaging, break up JS and bring in as needed. The advantage is that JS is not too bulky. It should be noted that this syntax is a new feature in ES7, and there are a lot of holes in configuring Babel.

conclusion

Webpack is updated too fast, most of the time there is no Chinese document, we can only vaguely check Github, but as WebPack becomes more and more mature and stable, the syntax is also fixed, the only place we need to pay attention to is dazzling plug-ins, according to their own needs.

Details of the front

The front-end is the most familiar part of the project development, and VUE, as a front-end framework, is suitable for such small and medium-sized projects. Writing blog site is also for learning, simply use vue bucket. Vue-router, Vuex, they’re all in use. Because my aesthetic and UI design is really limited, a lot of borrowing (copying) BUPT-HJM.

Home page and blog details page

The home page includes a header component, an information display component, a blog list page, and a pagination component. The only slightly more complex components are the information presentation component and the paging component. The information presentation component uses vUE slots, slots, and the default is self-introduction. The same is true for props, which passes in data, while the slot passes in HTML. The same is true for props, which passes in HTML. The paging component is actually written in conjunction with VUEX. State in VUex records the current number of pages that are paginated, and clicking to change the page number triggers mutations in VUex to load the page data. The loading source of blog details page data is also combined with VUEX, obtaining the article ID from state and requesting blog details from GET. There are two problems in the blog details page: 1. The data taken out from the back end is the original Markdown data, which needs to be analyzed. I found a good parsing plug-in from the Internet and marked it up for use, styling the code block. Look at the code if you’re interested. 2. After rendering with vue’s this.$nextTick and other DOM elements, extract h1 to H6 tags from the blog. To make a menu bar.

Array.from(this.$refs.post.querySelectorAll("h1,h2,h3,h4,h5,h6")).forEach(
       (item, index) = > {
         item.id = item.localName + "-" + index
         this.category.push({
           tagName: item.localName,
           text: item.innerText,
           href: "#" + item.localName + "-" + index
         })
       }
     );

Copy the code

The above is the core code, but also a reference to the source of daishen. Reassembled as a menu bar, which uses the slot function of the previous information presentation component. CSS uses PostCSS directly. Postcss has a syntax similar to SCSS and a rich set of plugins that make it possible to use a lot of advanced CSS syntax, although I rarely use it. Postcss plugins and Webpack configurations are not complicated and are quite routine. See the code for details. It was not intended to be compatible with mobile blogging, considering that people generally browse blogs more often on mobile. So mobile compatible processing, and PostCSS for media query syntax is very friendly

@custom-media --small-viewport (max-width: 850px);

@media (--small-viewport) {
 .ArticlePage .articleDate{
   margin-left: 0;
   width: 100%;
 }
 .ArticlePage .articleDate .time{
   margin-left: 0;
 }
 .abstract {
   width: 100%; }}Copy the code

The above is the media query done on the mobile terminal

The above is a demonstration of the different UI between mobile and PC, also borrowed a lot from other people’s blogs

Login page and blog edit page

Login authentication

Since this blog is purely for its own use, it is very simple to write a login page using elementUI, which involves a front-end authentication function. Upon successful login, it will obtain a token value valid for 24 hours. After the token is received by the front-end, it is written to the request header. Some back-end requests (such as going to the admin page) need to validate the token.

// from vuex/mutations. Js is used to store the obtained token in storage
   	 [types.CREATE_TOKEN]: (state, res) = > {
   			state.token = res.token
   			state.userInfo = res.name
   			sessionStorage.setItem('vue-blog-token', res.token)
   			sessionStorage.setItem('vue-blog-userName', res.name)
   		},

   		// The js/http.js from the wrapper writes the token to the headers header
   	const createToken = () = >{
   		if(store.state.token){
   		// Global set header token validation, note Bearer with a blank
   			axios.defaults.headers.common['Authorization'] = 'Bearer ' + store.state.token
   		}
   	}
   	// Axios interception returns, and the interception token expires
   	axios.interceptors.response.use(function (response) {
   		return response
   	}, function (error) {
   		if (error.response.data.error.indexOf('token')! = = -1) {
   				store.commit('DELETE_TOKEN')}return Promise.reject(error)
   	});
Copy the code

The above is the core code of front-end authentication.

Blog editing

Blog background consists of two parts: 1. Blog list page, including public and non-public blogs, and 2. Markdown editor.

It was a bit of a hassle to find the Markdown editor. We started with vue-Simplemde, but the babel-loader compiler for Webpack failed. For a long time I pulled out the vue file involved in the editor in this NPM package, vue-simp. Vue file directly referenced, but can be used, it is really a mystery. The second difficulty is the development of blog editing function, which involves new creation, update, deletion and whether to publish. It is also the place with the most bugs. Blog background screenshot

The front-end summary

Vue and VUex are more proficient, webpack can not say proficient, but at least the processing and configuration of various resource files is more convenient than before. How much also exercise their front-end packaging component ability. The problems we have, others have, too. Google and Github always work it out. Here is a brief talk about my thoughts on front-end componentization. I have written three front-end frameworks: Vue, React and applets. There is a growing acceptance of componentization as container components and presentation components. Container components are components that participate in the project logic and respond to user instructions. The paging component, for example, handles complex paging logic internally. A presentation component is a component that is only responsible for rendering, such as a blog list component that only accepts data and renders. After receiving user instructions, such as parent-child component values or state management tools such as VUex and Redux, they are passed to the container component for processing. Often presentation components can be used multiple times and extracted as common components. However, according to different projects, components extract different particles, components also have different functions.

The back-end details

This is the first time for me to use KOA2 completely. At the beginning, I was not sure what to do. I still believe that programmers’ learning and progress start from learning Daishen code, and the server code is divided into the following parts by referring to Daishen code:

Entrance to the file

Because OF the use of ES6 and some of the new ES7 features in KOA, Babel compilation was added to the entry file

/ / from the server/start. Js
require('babel-register') ({presets: [ 'env']})// Import the rest of our application.
module.exports = require('./index.js')

Copy the code

So the real entry file is index.js. As webpack explained, the front and back ends use the same Node service. Decide whether to develop the environment, and then execute the function directly, passing koA as an argument, to start the WebPack service, which will be covered in more detail in the WebPack blog.

const app = new koa()
const isDeve = process.env.NODE_ENV === 'development'
if (isDeve) {
  require('.. /build/server')(app)
}
Copy the code

The file introduced by require is the WebPack configuration file, which is the core code for combining WebPack and KOA. So far, the entry file is just the usual app.use() and mongoodb connection. One thing I missed was how Node pointed to the packed home page. In development mode, the compiled files were not visible in the target folder. The real-time compiled files were stored in memory. This mode injects clients into bundles. In a production environment, you need to specify the home page.

import serve  from 'koa-static'
const home  = serve(path.join(__dirname+".. /.. /dist/"))
app.use(home)
Copy the code

The dist folder is the front-end code generated by the package, and KO2 will specify index.html as the home page by default.

routing

The koA-router interface is designed to contain controllers and controllers. The koA-router interface is designed to contain controllers and controllers.

  import * as $ from '.. /.. /controllers/articles_controller'
   import verify from '.. /.. /middleware/verify'
   export default async(router) => {
   	router.get('/getArticles',$.getAllPublishArticles)
   	router.post('/saveArticle',verify,$.saveArticle)
   	router.get('/articleDetails',$.articleDetails)
   	router.post('/changeArticle',verify,$.changeArticle)
   	router.post('/deletaArticle',verify,$.deletaArticle)
   }
Copy the code

Verify is the authentication, through koA middleware, to realize whether the interface needs authentication to call. This allows the separation of business logic and routing to be much better than what I wrote together before.

Controllers and middleware

The most core part of the back-end code is the Controller, including the storage of website data, modification, deletion, administrator login. It’s the most core code, but it’s also the simplest. Add, delete, change and check. If you are interested in github, you can check github for yourself.

The authentication function is implemented in the middleware, and koA-BodyParser is also used in the middleware to obtain POST submission data. This middleware is the most used for KOA.

import jwt from 'jsonwebtoken'
import config from '.. /serverConfig/index'
export default async(ctx, next) => {
    // console.log(ctx.get('Authorization'))
    const authorization = ctx.get('Authorization')
    if (authorization === ' ') {
        ctx.throw(401.'no token detected in http header \'Authorization\'')}const token = authorization.split(' ') [1]
    let tokenContent
    try {
        tokenContent = await jwt.verify(token, config.jwt.secret)
    } catch (err) {
        if ('TokenExpiredError' === err.name) {
            ctx.throw(401.'Token expired, please save data locally in time! ')
        }
        ctx.throw(401.'invalid token')}console.log('Authentication successful')
    await next()
};

Copy the code

The above code is the authentication code written in the middleware, using JWT. It is also very simple to use. The function is to check whether the header carries a token and whether the token is expired. On the koA middleware advanced use and source code and so on, please forgive my weak chicken, later will slowly fill up.

mongodb

Let’s talk about mongodb alone. There are a lot of articles about the deployment of mongodb on the server. It will not be explained here that the operation of mongodb in the code is also using conventional Mongoose. The database design of this website is divided into two collections, one is the collection of blogs, the other is the collection of users.

In business logic code, frequent query modifications are required. Fortunately, Mongoose’s grammar is simple enough.

export async function articleDetails(ctx) {
  const articleID = ctx.query.articleID
  const articleDetail = await Article.findOne({
    _id: articleID
  }).catch(err= > {
    ctx.throw(500, ERRMESG)
  });
  ctx.body = {
    success: true,
    articleDetail,
  };
}
Copy the code

The findOne statement used in the above code is a type of Mongoose query, and the parameter is the query condition. Other query statement encountered go to the official website to check the line.

The back-end summary

For the study of KOA is the entry, but far from reaching a qualified standard, not pretend force, but write more, found themselves weaker. The middleware is simple to use, and koA has no obvious advantage over Express. There’s still a lot to learn.

The online process

The server of the website is purchased from Ali Cloud, and the domain name sxywzg is the abbreviation of my girlfriend and I’s name, (feeding the dog food branch quest is completed). I bought the server date is the end of October, bought a few days ali cloud push told me the server double 11 discount… Installing Nodes, databases, and configuration clutter on the server won’t go into detail. There are also many tutorials on the web, focusing on nginx configuration.

Upstream vue {server 127.0.0.1:3000; } server { listen 80; server_name www.sxywzg.cn; location / { proxy_set_header X-real-ip $remote_addr; proxy_set_header X-Forward-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_set_header X-Nginx-Proxy true; proxy_pass http://vue; proxy_redirect off; }}Copy the code

All sites have port 80. Forward port 3000 to 80. Server_name is the domain name. Such a simple configuration I toss for a long time, or in the help of colleagues to come out. Nginx installation is also very simple, search tutorials yourself.

pm2

Pm2 I used to be a simple tool to get The Node service running on the server, but it’s much more than that. My code is hosted on Github, to which I submit every update, and PM2 helps me pull the code from the Git repository and restart the service.

{
  "apps": [{"name": "vue-blog"."script": "server/start.js"."error_file": "server/logs/app-err.log"."out_file": "server/logs/app-out.log"."env_dev": {
        "NODE_ENV": "development"
      },
      "env_production": {
        "NODE_ENV": "production"}}]."deploy": {
    "production": {
		// My server user name
      "user": "zhigang"./// Server address
      "host": ["47.95. * * *. * * *"]."port": "22".// Code branch
      "ref": "origin/master".// Code repository
      "repo": "[email protected]:463755120/vue-blog.git".// The server store code address
      "path": "/home/zhigang/vue-blog"."ssh_options": "StrictHostKeyChecking=no".// The command executed each time
      "post-deploy":"cnpm i && npm run build && pm2 start pm2.json --env production"."env": {
        "NODE_ENV": "production"}}}}Copy the code

Json configuration, the function is to line up the code in one click, do not need to manually pull the code down in the server, and then run the command. Pm2 does the heavy lifting for you. At the beginning, IT was amazing to use this function and such an considerate tool, but I do not know whether it is my fault or the defect of PM2. When the project was launched for the first time, the download package of CNPM I executed by PM2 was incomplete, so I had to manually download it in the server, and it will work well in the future. So when I need to update my website, I submit the code to git repository and execute NPM run pm2 to save time and effort.

Write in the last

There are two reasons for writing a blog website. The first is to test whether I can write a complete and on-line project, and the second is for the convenience of writing a blog in the future. If you don’t summarize your skills, you’ll soon forget them. The front end leader of my last company told me to forget that you are a front end developer, you are just a programmer to solve problems. I strongly believe that companies can divide us into front-end development and back-end development. But I think it’s important to know at heart that programmers are problem solvers, and that just because it’s front-end development doesn’t mean you’re stuck in your own corner. Don’t settle for developing in someone else’s configured environment. Knowing a little about the project architecture and going live, server configuration is not a bad thing. Next year will be basic algorithms, design patterns, typescript and React. In the future, my blog will also increase my study notes irregularly. Hope big guys give more advice, the way to contact me is very simple, the home page has my zhihu account, send private letter can.