Use Grunt-contrib-connect and grunt-connect-proxy to build a development environment for front-end separation

Source: Internet
Author: User

Separation of the front and rear end of the word is not fresh, full front-end separation in the post collaboration, the front end does not write any background, the background does not write any page, the two sides through the interface to pass data to complete the various functions of the software implementation. In this case, both the front and back projects are independently developed and deployed independently, with 2 issues unavoidable during development: the first is the cross-domain issue when the front-end invokes the backend interface (because the front and back ends are deployed separately), and the second is that the front end is detached from the background service and cannot be run independently. This paper summarizes the work experience of a recent project, and introduces the practical process of using grunt-contrib-connect and grunt-connect-proxy to build the development environment of front and rear end separation, hoping to help you.

Note:

(1) The relevant content of this article needs to know about the front-end build tool Grunt: http://www.gruntjs.net/getting-started, this tool can complete all the engineering work of front end, including code and picture compress, file merge, static resource substitution, JS confusion, less and sass compiled into CSS and so on, it is recommended not to use similar tools for front-end developers to understand.

(2) Grunt-contrib-connect and Grunt-connect-proxy are the grunt provided by the two plug-in, the former can start a Nodejs-based static server, This way the front-end can be separated from the backend through Web services to access their own development of things, the latter can be the front-end project some special requests to other servers, which can be forwarded to other servers through the proxy, this rule is configurable, so that some background interaction with the request through the proxy way , which is forwarded to the backend service for processing during development, thus avoiding cross-domain issues.

Code download

1. Effect Demo

In the code provided earlier, there are two folders:

Represents two projects that run independently of the front and back ends, the client represents the front end, and the server represents the service side. Before actually running the client and server services, please make sure that GRUNT-CLI is installed, and if not, follow the grunt documentation to install the GRUNT-CLI NPM package first. If you have installed the GRUNT-CLI, then go to the client or the server folder, you can directly use the grunt command to start the service, no need to run NPM installed to install dependencies, Because the client and server folders are already included in the download good dependencies. in the actual front-end project, the server side can be any project of any schema type, Java Web, PHP, ASP. In order to simply simulate a background service, the grunt starts a static service to act as server side, but it actually works the same as a traditional backend project like Java Web.

In order to see the effect of the request being forwarded by the agent, start the service under the server folder first, the command is: Grunt Staticserver:

As long as you see a similar result with a run, the server-side service starts successfully. The access address of the server-side service from which you can see it is: http://localhost:9002/.

Then, under the Client folder, start the service configured with the agent, the command is: Grunt ProxyServer:

As long as you see a similar result with a run, the client side of the service starts successfully. The access address from which you can see the client side service is: http://localhost:9001/, and you can also see the configuration of the service proxy:

The result of this operation shows that the client's request that begins with/provider will be forwarded by the agent and handled by the agent to Http://localhost:9002/provider. For example, if a request is initiated on the client side, the URL of the request is: Http://localhost:9001/provider/query/json/language/list, The service address that eventually handles the request is actually: Http://localhost:9002/provider/query/json/language/list.

After the client starts, it should automatically open the browser and access the HTTP://LOCALHOST:9001/, which shows the home page of the client side. After opening the homepage, press F12 to open the developer tool, if you see a similar message in the console, it means that the request from the home page is correctly requested by the proxy to the server data:

In the home page of the client, I initiated an AJAX request with the address http://localhost:9001/provider/query/json/language/list, In the Client folder there is no provider folder, so if there is no proxy, this request will certainly report 404 error, it is able to load correctly, because through the proxy, the request to the server folder corresponding files:

If not through the proxy, in the LOCALHOST:9001/service, the request localhost:9002/data is sure to have cross-domain problem, and the agent can solve the problem perfectly.

This small section demonstrates how the demo can solve cross-domain problems through a proxy, and the following section shows how to run the front-end project in the case of a back-end service, first close the client service and server-side service that you opened and the client page that the browser opens. Then open the Client/gruntfile.js file and locate the following section:

Change the provider to the API and change the false to true;

Then in the client folder, run the non-agent static service, the service does not configure the proxy, the start command is: Grunt Staticserver:

Open the browser's developer tool and you should see the following message in the console:

This process is: the original through the proxy request address is: http://localhost:9001/provider/query/json/language/list, in the absence of agents, I will put http://localhost:9001/ Provider/query/json/language/list this request changed to request Http://localhost:9001/api/query/json/language/list.json, The JSON file exists under my Client folder:

That is to say I will be all the interface with the server to return the data are the same path, in the form of a JSON file in the local API folder, in the absence of agents, as long as the request of these JSON files, can ensure that all my operations can correctly request data, The front-end project will be able to run away from the agent, of course, the data in this mode is static.

Next I will introduce how the above content implementation details, only to introduce the main points in the client, the contents of the server is very simple, as long as the understanding of the Client,server can understand:)

2. Grunt Configuration

Before you understand the configuration, familiarize yourself with the folder structure of your project:

Just to complete the demo, so the project folder structure and grunt configuration have done a maximum simplification, the purpose is to facilitate understanding, this article is not a solution, but a thought, when you need to refer to improve the application to their own projects, in front of the engineering this piece, You need to use more plug-ins than the demo, you have to configure on-demand. In the case of demo, the most core plug-ins are grunt-contrib-connect and Grunt-connect-proxy, but to complete the demo, you can not do without some other plugins:

Load-grunt-tasks: I use it to load all the plugins in the Package.json at once:

Grunt-contrib-copy: I use it to copy the contents of SRC and paste it into the dist directory:

As soon as you run the Grunt copy task, you'll see that the project structure has one more Dist folder:

Grunt-contrib-watch: I use it to listen for changes to the file and automate the definition of the grunt task, as well as automatically refresh the browser page via Livereload:

Grunt-replace: I use it to replace some special strings in the file so that I can change the code without manually changing the source code. The reason that non-proxy mode can request local static JSON data is not because I changed the request address manually, but instead changed the processing rule in the request address handler, the change of the rule is actually done by Grunt-replace:

The rule of substitution is configured by getreplaceoptions this function:

Note the comment section of the description, so-called local mode, in fact, is running grunt staticserver, the proxy mode is running grunt ProxyServer, this comment requires grunt Staticserver before running Api_ Name changed to the API, the Develop_mode to true, only then those who need the proxy request will request the local JSON file, before running grunt ProxyServer must first change api_name to provider, DEVELOP_ Mode to False, the only way to correctly forward requests that require a proxy.

3. Focus: Configuration of Grunt-contrib-connect and Grunt-connect-proxy

In the grunt task configuration, typically each plug-in is configured as a task, but Grunt-connect-proxy is not, and it is configured with Grunt-contrib-connect:

Connect: {options: {port:' 9001 ', hostname:' localhost ', protocol:' HTTP ', open:true, Base: {path:‘./‘, Options: {index:' Html/index.html '}}, Livereload:true}, proxies: [{context:'/' +Api_name, Host:' localhost ', Port:' 9002 ', https:false, Changeorigin:true, Rewrite:proxyrewrite}],default: {}, Proxy: {options: {middleware:function(Connect, options) {if(!Array.isarray (options.base)) {Options.base=[Options.base]; }                //Setup the proxy                varMiddlewares = [Require (' grunt-connect-proxy/lib/utils ')). Proxyrequest]; //Serve static files.Options.base.forEach (function(Base) {Middlewares.push (Servestatic (Base.path, base.options));                }); //Make directory browse-able.                /*var directory = Options.directory | | options.base[options.base.length-1];                 Middlewares.push (connect.directory (directory)); */                returnMiddlewares; }        }    }}

In the above configuration:

The options section is a generic configuration for configuring static server information to be started, port for ports, hostname for host addresses, protocol for protocols such as HTTP,HTTPS, Open indicates whether the static service starts with the default browser to open the first page base.options.index specified pages, Base.path used to configure the root directory of the site, the demo root directory is configured as the current project folder (./);

The above configuration is in the configuration Grunt-contrib-connect task, but the above configuration of the proxies section is actually grunt-connect-proxy needed to configure proxy information: The context configuration needs to be proxy request prefix, usually configured to /Start a string, such as/provider, so that the relative site root and start with provider requests will be proxied to, Host,port,https used to configure the service address to be proxied, port and the protocol used Changeorigin is configured to True, rewrite is used to configure proxy rules, proxyrewrite this variable is defined before the configuration file:

The meaning is the client side in the beginning of the provider, replace the agent service/provider/directory to handle, note/provider/This string the last slash can not be omitted! For example, there is a request in the client http://localhost:9001/provider/query/json/language/list, will be agent to http://localhost:9002/provider/ Query/json/language/list to deal with;

Default is the target of a connect task, which starts the static service;

Proxy is also a connect task target, use it to start the agent service, because in the demo, watch task and connect task are enabled Livereload, so in the proxy task to add a middleware middleware configuration, To ensure the correct start of the agent, this code is provided by the official website, direct use can be. There is a servestatic module, which has been introduced in front of the configuration file:

This is necessary for grunt to start the static service, just use it.

Finally, we look at the related task definitions for static services and proxy services:

function () {    grunt.task.run ([        ' Copy ',        ' replace        ', ' Connect:default ',        ' watch '    );}); Grunt.registertask (function  () {    grunt.task.run ([        ' Copy ')        , ' Replace ',        ' Configureproxies:proxy ',        ' Connect:proxy ',        ' watch '     ]);});

In the configuration Agent service, ' configureproxies:proxy ' must add, and to add in Connect:proxy before, otherwise the agent configuration has not registered successfully, the static service is started, Configureproxies This task is not configured in the configuration file, but is defined in the Grunt-connect-proxy plug-in, as long as Grunt-connect-proxy is loaded in, this task can be used.

4. How to send a request

This section to see how to send a request, open the home page, you will see the bottom reference 4 JS files:

Where Util.js encapsulates the ability to process request addresses:

varDevelop_mode = ' @ @DEVELOP_MODE ';varUtil = (function(){    varBase_url = Location.protocol + '//' + Location.hostname +(Location.port= = '? ': (': ' + location.port ') + '/' + ' @ @CONTEXT_PATH '; return{API:function(Requestpath) {varPathparts = Requestpath.split ('? ')); pathparts[0] = Pathparts[0] + (Develop_mode = = ' true '?) '. JSON ': '); returnBase_url + ' @ @API_NAME/' + pathparts.join ('? ')); }    }})();

This is the source code, remember that replace the task, its replacement rule is

The Replace task will start with @@ in the file and replace the matched string with the corresponding strings according to the configuration in the patterns. In local mode, Api_name is Api,develop_mode is True,context_path is always empty, and after the replace task is processed, the Util.js code becomes:

varDevelop_mode = ' true ';varUtil = (function(){    varBase_url = Location.protocol + '//' + Location.hostname +(Location.port= = '? ": (': ' + location.port)") + '/' + '; return{API:function(Requestpath) {varPathparts = Requestpath.split ('? ')); pathparts[0] = Pathparts[0] + (Develop_mode = = ' true '?) '. JSON ': '); returnBase_url + ' api/' + pathparts.join ('? ')); }    }})();

In proxy mode, Api_name is Provider,develop_mode is false,util.js after replace will become:

varDevelop_mode = ' false ';varUtil = (function(){    varBase_url = Location.protocol + '//' + Location.hostname +(Location.port= = '? ": (': ' + location.port)") + '/' + '; return{API:function(Requestpath) {varPathparts = Requestpath.split ('? ')); pathparts[0] = Pathparts[0] + (Develop_mode = = ' true '?) '. JSON ': '); returnBase_url + ' provider/' + pathparts.join ('? ')); }    }})();

This same request address, such as query/json/language/list, is processed after UTIL.API:

Util.api (' query/json/language/list ')

In local mode, it will return: Http://localhost:9001/api/query/json/language/list.json

Returned in proxy mode: http://localhost:9001/provider/query/json/language/list

Ajax.js the Ajax package for jquery:

varAjax = (function(){    functionCreate (_url, _method, _data, _async, _datatype) {//Add random number        if(_url.indexof ('? ') >-1) {_url= _url + ' &rnd= ' +Math.random (); } Else{_url= _url + '? rnd= ' +Math.random (); }        //add Ajax identities to requests to facilitate background-sensitive Ajax and non-AJAX requests_url + = ' &_ajax=true '; return$.ajax ({url: _url, DataType: _datatype, Async: _async, Method: (Develop_ MODE= = ' true '? ' Get ': _method), data: _data}); }    varAjax ={}, Methods=[{name:' HTML ', Method:' Get ', Async:true, DataType:' HTML '}, {name:' Get ', Method:' Get ', Async:true, DataType:' JSON '}, {name:' Post ', Method:' Post ', Async:true, DataType:' JSON '}, {name:' Syncget ', Method:' Get ', Async:false, DataType:' JSON '}, {name:' Syncpost ', Method:' Post ', Async:false, DataType:' JSON '            }        ];  for(vari = 0, L = methods.length; I < L; i++) {Ajax[methods[i].name]= (function(i) {return function(){                var_url = Arguments[0], _data= Arguments[1], _datatype= Arguments[2] | |Methods[i].datatype; returnCreate (_url, Methods[i].method, _data, Methods[i].async, _datatype);    }}) (i); }    //window. Ajax = Ajax;    returnAjax;}) ();

The five methods of Ajax.get,ajax.post,ajax.syncget,ajax.syncpost and ajax.html are provided, and there are 2 reasons to encapsulate them:

The first is the unification plus the identification of the random number and the AJAX request:

Second, the static service initiated by Grunt-contrib-connect can only send a GET request and cannot send a POST request, so if there is a write $.post call in the code that cannot be run from the backend service, it will be reported 405 Method not Allowed error, and this encapsulation can be ajax.post such a request, in the local mode when all replaced by get mode to handle:

This is actually the work of the Replace task!

Index.js is the homepage of the request JS, you can see:

Ajax.get (Util.api (' query/json/language/list ')). Done (function(response) {    Console.log ( Response.data);}). Fail (function() {    console.log (' request failed ');});

In combination with Util.js and ajax.js, I'm sure you'll soon be able to understand the process.

5. How to deploy front-end services on the wire

The answer is still an agent. During development, the front end through the grunt-connect-proxy to all the requests under a namespace to the backend services to deal with, online deployment when the backend to deploy the project to the Tomcat Web server, the front-end to deploy the project to the Nginx server, Then the OPS staff according to the agent rules during development, on the Nginx server with the reverse proxy configuration, the browser request front-end of those requiring back-end support requests, all agents to the Tomcat server under the back-end service to handle. This means that online deployment is the same as the principle of interaction during development, except that the provider of the agent becomes Nginx.

6. Summary

This article summarizes oneself this time to do a front-end separation project Some environment preparation aspect experience, the method mentioned in the article has helped us to solve the cross-domain and the front end independent operation two big problems, now the project development situation is very smooth, therefore from my own practice, this article's content is the comparison has the reference value, Hope to be able to help people in need, thank you for reading:)

Code download

Use Grunt-contrib-connect and grunt-connect-proxy to build a development environment for front-end separation

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.