Further discussion on separation development and deployment of front end and back end

Time:2020-6-4

The separation of front and back end development has become a consensus in the industry, but at the same time, it also brings deployment problems. In the traditional web mode, the front end and the back end belong to the same project, and the template rendering is naturally done by the back end. However, with the popularity of node and the modular packaging scheme of webpack, the front-end isDevelopment stageCompletely capable of breaking away from the back-end environment: start a server through the local node, match with mock data, and business development can be carried out immediately.

But here we areDeployment phase, and the problems will appear: JS, CSS and index.html , where exactly? Static files JS, CSS or pictures can also be uploaded to CDN server in CI stage, but the final HTML templateindex.htmlIt must be on a server, but is the server maintained by the front end or the back end?

Front end maintenance HTML

If the HTML template is maintained by the front end, the front end needs to use a static server of its own: provideHTMLRendering andAPIInterface forwarding. The common single page application is also recommended to use nginx for deployment.

Using nginx deployment, there are two situations:

  • Static resources are fully hosted by nginx, that is, JS, CSS and index.html Put it in the same placedistIn the catalogue. In this case, thepublicPathGenerally, no special settings are needed, and the default/Just.
  • Static resource upload CDN, nginx only providesindex.html。 In this case, thepublicPathAddress to set as CDN, for example://static.demo.cn/activity/share/。 But this will cause another problem, because the CDN addresses of QA environment, validation environment and production environment are usually different, in order toindex.htmlYou can import the correct static file path. You need to package three times, just to generate three HTML references to different paths (even if the content of JS packaged three times is exactly the same)

Nginx configuration

server {
    listen       80;
    server_name  localhost;

    location / {
        Root / APP / dist; ා path to package
        index  index.html index.htm;
        try_ files $uri $uri// index.html ; ා single page application prevents re refreshing and returns 404. If it is a multi page application, this command is not required
    }

    location /api {
        proxy_ pass  https://anata.me;  #Background forwarding address
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_set_header   X-Real-IP         $remote_addr;
    }
}

Theoretically, the interface forwarding addresses of QA, YZ and prod environments are also different, so you need three more copiesnginx.confto configure

Back end maintenance HTML

In many cases, we need to render the page with the dynamic data injected from the back end, or the page needs to support SEO. In this case, we can only give the template to the back end for rendering. So how can the HTML template maintained by the backend get the packaged hash value?

  • Packaged front endindex.htmlDirect to back end (simple and crude, not recommended)
  • Plug in for front-end packagingwebpack-manifest-pluginGenerate amanifest.jsonThe file is actually a key value pair. The key represents the resource name and the value records the hash of the resource
{
  "common.css": "/css/common/common-bundle.804a717f.css",
  "common.js": "/js/common/common-bundle.fcb76db9.js",
  "manifest.js": "/js/manifest/manifest-bundle.551ff423.js",
  "vendor.js": "/js/vendor/vendor-bundle.d99dc0e4.js",
  "page1.css": "/css/demo/demo-bundle.795bbee4.css",
  "page1.js": "/js/demo/demo-bundle.e382801f.js",
}

Back endindex.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>demo</title>
  <link href="<%= manifest['page1.css']%>" rel="stylesheet">
</head>

<body>
  <h1>demo</h1>
  <script></script>
</body>
</html>

The backend reads thisjsonFile, you can dynamically render the reference path of the file.

If you have ever used Baidu’s packing tool FIS, it will finally pack and produce map.json This is a similar list of resource files.

There is another advantage of using this method: as we mentioned earlier, if a file is uploaded to CDN, the HTML maintained by the front end may need to be packaged three times, because the CDN addresses of different environments are different. Now the html is handed over to the back-end for maintenance, so this problem can be solved very well. The front-end only needs to be packaged once, and the CDN addresses of different environments can make the back-end dynamically spliced and generated.

Of course, using this method will also bring a problem. How to get the JSON file from the backend?

  • Package and upload the JSON file together with other static resources to the CDN. Each time the backend server starts, it first gets the JSON file from the CDN, and then saves it in memory
wget --tries=3 --quiet -O  manifest.json  http://static.demo.cn/demo/manifest.json? `Date +% s' -- prevent caching

Advantages of the scheme: simple and convenient, each front-end packaging,manifest.jsonIt will automatically update, upload to CDN and overwrite the previous version.
Disadvantages of the scheme: ifmanifest.jsonIf it is updated, the backend needs to restart the service to get new configuration. When there are many clusters, the cost of restarting may be very high.

  • takemanifest.jsonThe content ofConfiguration centerThe back end needs to access the configuration center. After each CI packaging, the configuration center is called to update the interface, and the backend can automatically obtain the latest configuration.

In my usual work projects, both of these two schemes are implemented.

Node middle layer

When using nginx deployment, in order to solve cross domain problems, we usually need to configureproxy_passPoint to the back-end service that provides the API.

When the back end adopts SOA, micro service architecture,proxy_passThe pointed API server is actually a forwarding service.

Front end Ajax requests

//Get product list
ajax.get('/api/queryProductList')

//Get price list
ajax.get('/api/queryPriceList')

Nginx forwarding

location /api {
    proxy_ pass  https://demo.com;  #Background forwarding address
    proxy_set_header   X-Forwarded-Proto $scheme;
    proxy_set_header   X-Real-IP         $remote_addr;
}

Interface forwarding to
https://demo.com/api/queryProductList
https://demo.com/api/queryPriceList

The query commodity list and the query price list are actually provided by two different SOA services:

Query product:product.soa.neko.com
Query price:price.soa.neko.com

So essentiallyhttps://demo.comThis service is only used to forward the interface, and also to partially assemble the data. Then this service can be replaced by the node middle tier. With the node middle layer, the rendering of the template can also be transferred from nginx to node.

Of course, with one more layer of nodes, the comprehensive requirements for the front-end will also be improved, and the deployment, monitoring, logging, performance and other problems of the back-end will followStackEngineers came into being.

Work status

Most of our company’s front-end projects of to C adopt the development mode of node layer rendering template plus forwarding interface, and a few projects use Java Tomcat to render HTML template.

Most pages are multi page applications, not typical single page applications.

Node layer rendering template is divided into two situations:

  • To support SEO, traditional template rendering is used to fill in display data. But the business code of JS is still separated from the front and back end, not in the node project. This kind of page is usually packaged with jQuery + webpack module.
  • No need to support SEO, then node only renders an empty HTML template, and the page content is completely generated by JS. This kind of page generally adopts the latest front-end MVC framework, such as Vue and react.

Of course, in recent years, the more popular SSR scheme allows node to directly use the isomorphic components of Vue and react when rendering templates. After going straight out of the page, the user’s interaction experience is as smooth as a single page application. It can only be said that the history is always surprisingly similar.

To some extent, SSR is a return to the traditional model, but this return is not retrogression, but a spiral development.

actual combat

We have talked so much about theoretical knowledge. Now let’s practice. In the last article, I introduced the principle of multi page packaging of Web pack, and built a simple web pack 4-boilerplate. This template is just a front-end development template, in fact, it also corresponds to a node back-end template, koa2 multipage boilerplate.

The most important thing of this node project is to implement the above-mentioned: how to readmanifest.jsonFile, dynamically rendering the reference path of static files, so as to separate development and deployment at the front and back ends.

For details, see chunkmap.js The source code of this koa2 middleware.

const chunkmap = require('./chunkmap');
app.use(chunkmap({
  staticServer: '//0.0.0.0:9001',
  staticResourceMappingPath: './mainfest.json'
}));

This middleware accepts two parameters

  • Static server: static resource server address. When developing locally, fill inwebpack4-boilerplateThe server that this front-end project started. When it comes to QA and production line, fill in the real CDN address
  • Staticresourcemappingpath: resource mapping file path, that ismanifest.jsonfile

Local developmentmanifest.json, without hash value

{
  "home.css": "/css/home/home-bundle.css",
  "home.js": "/js/home/home-bundle.js",
}

Packedmanifest.jsonWith hash value

{
  "home.css": "/css/home/home-bundle.d2378378.css",
  "home.js": "/js/home/home-bundle.cb49dfaf.js",
}

After using this middleware, KOA’sctx.stateThe global variable has abundleProperty, which contains:

{
  "home.css": "//0.0.0.0:9001/css/home/home-bundle.d2378378.css",
  "home.js": "//0.0.0.0:9001/js/home/home-bundle.cb49dfaf.js",
}

Then through the template engine, the actual page is dynamically rendered. Of course, you can also dynamically generate presentation content in the page to support SEO.

<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <title><%= title %></title>
  <link href="<%= bundle['home.css']%>" rel="stylesheet">
</head>

<body>
  <div id="app"></div>
  <script></script>
</body>
</html>

summary

The separation of front end and back end brings about the improvement of work efficiency, and the middle layer of node opens a way for the front end to enter the back end. Of course, opportunities always coexist with challenges. In today’s rapidly changing front-end technology, I really want to say:I can’t learn!

reference resources

How to develop and deploy front-end code in large companies?

Recommended Today

Front end interview daily 3 + 1 – day 375

Today’s knowledge points (April 25, 2020) – day 375 [HTML] how to make the layout of the page not disordered after zooming in or out? [CSS] how to use CSS to add a diagonal slash to a square? [JS] how to automatically submit a form by pressing enter [soft skills] please explain the meaning and […]