Analysis on the running principle of browserify

Source: Internet
Author: User

Currently, for front-end engineers, if you only write code for the browser, it is very simple. You only need to introduce the JS used in the Script script of the page.

However, in some cases, we may need to run a set of similar logic code on the server. Consider the following scenarios (taking node as the backend ):

1. for spa applications, you must also support direct-output pages on the server and Data Rendering by pjax on the client. The client and server share a set of rendering templates and execute most similar logics.

2. In a websocket-based game, the client and server may need to perform similar logic computing. The two sets of code are used to display the user's client and calculate the actual value of the server.

 

In these cases, it is very likely that the logic of our client code can run seamlessly on the server at the same time.

 

Solution 1: UMD

One solution is to use UMD. The front end uses requirejs and is compatible with nodejs. For example:

(function (window, factory) {    if (typeod exports === ‘object‘) {             module.exports = factory();    } else if (typeof define === ‘function‘ && define.amd) {             define(factory);    } else {             window.eventUtil = factory();    }})(this, function () {    //module ...});

 

Solution 2: Use browerify to enable code to run on both the server and browser.

 

What is browserify?

Browserify allows you to organize JavaScript code on the browser side in a way similar to node's require (). Through pre-compilation, browser javascript can directly use some libraries installed on node NPM.

 

For example, we can write Js in this way and run it on both the server and the browser:

Mo2.js:

exports.write2 = function(){    //write2}

Mo. JS:

var t = require("./mo2.js");exports.write = function(){    t.write2();}

Test. JS:

var mo = require("./mo.js");mo.write();

 

The code can be fully written in the form of node.

 

Principle Analysis:

The overall process can be divided into the following steps:

 

Phase 1: Pre-compilation phase

1. Analyze the call of the require function in the code from the entry module

2. Generate AST

3. Find the require Module name for each module based on AST

4. Obtain the dependency between each module and generate a dependency dictionary.

5. Package each module (input dependency dictionary and self-implemented export and require functions) to generate the JS

 

Phase 2: execution phase

Execute from the entry module and recursively execute the require module to obtain the dependent object.

 

Detailed steps:

 

1. Analyze the call of the require function in the code from the entry module

Because the browser does not have the native require function, all the require functions need to be implemented by ourselves. Therefore, in the first step, we need to know where the require function is used in the code of a module and which modules are depended on.

The principle of browerify is to generate an AST for the code file, and then find the module on which the require function depends Based on the ast.

 

2. Generate AST

File Code:

var t = require("b");t.write();

 

The ast of the generated JS description is:

{    "type": "Program",    "body": [        {            "type": "VariableDeclaration",            "declarations": [                {                    "type": "VariableDeclarator",                    "id": {                        "type": "Identifier",                        "name": "t"                    },                    "init": {                        "type": "CallExpression",                        "callee": {                            "type": "Identifier",                            "name": "require"                        },                        "arguments": [                            {                                "type": "Literal",                                "value": "b",                                "raw": "\"b\""                            }                        ]                    }                }            ],            "kind": "var"        },        {            "type": "ExpressionStatement",            "expression": {                "type": "CallExpression",                "callee": {                    "type": "MemberExpression",                    "computed": false,                    "object": {                        "type": "Identifier",                        "name": "t"                    },                    "property": {                        "type": "Identifier",                        "name": "write"                    }                },                "arguments": []            }        }    ]}

 

We can see the require function called in our code. The object in the AST is the red part above.

 

3. Find the require Module name for each module based on AST

After the AST is generated, we need to find the module name of the require dependency based on the AST in the next part. Let's take a look at the ast object generated above. To find the require Module name, it is essentially:

Find the value of the first argument corresponding to require, whose type is callexpression, and callee's name is require.

 

For details about how to generate AST for JS descriptions and parse ast objects, refer:

Https://github.com/ariya/esprima code generation AST

Https://github.com/substack/node-detective extracts reqiure from AST

Https://github.com/Constellation/escodegen ast Generation Code

 

4. Obtain the dependency between each module and generate a dependency dictionary.

From the above steps, we can obtain the dependencies of each module, so we can generate a module dependency dictionary with ID as the key, browerify generates the following dictionary example (based on the previous sample code ):

{    1:[    function(require,module,exports){        var t = require("./mo2.js");        exports.write = function(){            document.write("test1");            t.write2();        }    },    {"./mo2.js":2}    ],    2:[    function(require,module,exports){        exports.write2 = function(){            document.write("=2=");        }    },    {}    ],    3:[    function(require,module,exports){        var mo = require("./mo.js");        mo.write();    },    {"./mo.js":1}    ]}

 

The dictionary records the modules that have them and their dependencies.

 

5. Package each module (input dependency dictionary and self-implemented export and require functions) to generate the JS

With the dependency dictionary above, we know the dependencies in the code. To make the code executable, The last step is to implement export and require that are not supported in the browser. Therefore, we need to wrap the original module code. Just like the above Code, the outer layer will pass in its own export and require functions.

However, how should we implement export and require?

Export is simple. We only need to create an object as the export of this module.

For require, we already have a dependency dictionary, so it's easy to do. You just need to find the dependent module function based on the input module name and the dependency dictionary, and then execute it, keep repeating (Recursive Execution of this process ).

In the JS generated by browerify, the following require implementation code is added and passed to each module function:

(function e(t,n,r){    function s(o,u){        if(!n[o]){            if(!t[o]){                var a=typeof require=="function"&&require;                if(!u&&a)                    return a(o,!0);                if(i)                    return i(o,!0);                var f=new Error("Cannot find module ‘"+o+"‘");                throw f.code="MODULE_NOT_FOUND",f            }            var l=n[o]={exports:{}};            t[o][0].call(l.exports,function(e){                var n=t[o][1][e];                return s(n?n:e)            },l,l.exports,e,t,n,r)        }        return n[o].exports    }    var i=typeof require=="function"&&require;    for(var o=0;o<r.length;o++)        s(r[o]);    return s})

 

We mainly focus on the red part, where T is the passed-in dependency Dictionary (the Code mentioned earlier), n is an empty object, it is used to save all newly created modules (export objects). It is clearer than the previous dependency dictionary:

First, we create a module object (including an empty object export), and pass module and export into the module function as the module and export implemented by the browser respectively. Then, we implement a require function by ourselves, this function retrieves the module name, recursively searches for the dependent module execution, and finally obtains all the dependent module objects. This is also the entire execution process of the JS generated by browerify during running.

 

Thanks to onlookers, reprinted please indicate the source: http://www.cnblogs.com/Cson/p/4039144.html

 

Analysis on the running principle of browserify

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.