• browerify初步了解


    之前在写Signature Request Warnings & eth_sign学习的时候在里的signing examples时了解到browserify工具,可以通过这个例子学习如何使用browserify,下面就学习了一下这个工具该怎么使用。

    参考https://www.cnblogs.com/xiaohuochai/p/6850977.html

    Nodejs的模块是基于CommonJS规范实现的,可不可以应用在浏览器环境中呢?

    var math = require('math');
    math.add(2, 3);

      第二行math.add(2, 3),在第一行require('math')之后运行,因此必须等math.js加载完成。也就是说,如果加载时间很长,整个应用就会停在那里等。这对服务器端不是一个问题,因为所有的模块都存放在本地硬盘,可以同步加载完成,等待时间就是硬盘的读取时间。但是,对于浏览器,这却是一个大问题,因为模块都放在服务器端,等待时间取决于网速的快慢,可能要等很长时间,浏览器处于"假死"状态

      而browserify这样的一个工具,可以把nodejs的模块编译成浏览器可用的模块,解决上面提到的问题。本文将详细介绍Browserify

    实现

      Browserify是目前最常用的CommonJS格式转换的工具

      请看一个例子,b.js模块加载a.js模块

    // a.js
    var a = 100;
    module.exports.a = a;
    
    // b.js
    var result = require('./a');
    console.log(result.a);

      index.html直接引用b.js会报错,提示require没有被定义

    //index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
    <script src="b.js"></script>    
    </body>
    </html>

     

      这时,就要使用Browserify了

    【安装】

      使用下列命令安装browserify

    npm install -g browserify

    【转换】

      使用下面的命令,就能将b.js转为浏览器可用的格式bb.js

    $ browserify b.js > bb.js

      查看bb.js,browserify将a.js和b.js这两个文件打包为bb.js,使其在浏览器端可以运行

    (function e(t,n,r){
        function s(o,u){
            if(!n[o]){//从缓存区域中找模块,如果没有则向下
                if(!t[o]){//从未加载区域去找模块,如果未加载区域中什么都没有,那么你转换成浏览器格式的js文件中什么内容都没有
                    var a=typeof require=="function"&&require;//判断是否存在自行构造的require
                    if(!u&&a)return a(o,!0);//如果存在自行构造,尝试用自行构造的require加载模块
                    if(i)return i(o,!0);//否则,判断外部环境中的require是否存在
                    var f=new Error("Cannot find module '"+o+"'");//如果还是没有,那么会报找不到模块错误
                    throw f.code="MODULE_NOT_FOUND",f
                }
           //在上面的过程中,如果没有报错,那么下面将会将从未加载区域t[o]中找到的模块加载并缓存到缓存区n[o]中,供其他模块调用 var l=n[o]={//声明一个module.exports为空的缓冲区l=n[o]
              exports:{}
           }; t[o][0].call(l.exports,function(e){//有递归调用,运行到 t[o][0].call,说明有模块在未加载区域,然后将function(e)当作require传入,进行递归调用 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]);// 2 从按序加载区域一个一个加载模块,运行函数s(2,undefined) return s })({// 1 这里()内的值就是输入到函数e的参数(t,n,r)中的值,运行函数e 1:[function(require,module,exports){ //a.js var a = 100; module.exports.a = a; },{}], 2:[function(require,module,exports){ //b.js var result = require('./a'); console.log(result.a); },
         {"./a":1}// 缓存区域,缓存已加载的模块a.js,其id为1
        ] },// 未加载区域, 存放未运行的模块,即参数t {},// 缓存区域,缓存已加载的模块,即参数n [2]);// 按序加载区域,从哪里开始加载,按照数组中的顺序加载过去,这里首先是调用2的b.js,即参数r


     

    上面代码的难点就是call的调用,参考https://cnodejs.org/topic/557bbbab16839d2d53936265

    call的用法

    function Man(name){
        this.name = name;
        this.fav = 'charming lady';
        this.love = function(){
            console.log(this.name, 'love', this.fav);
        }
    }
     
    var jinceon = new Man('jinceon');
    jinceon.love(); //jinceon love charming lady
     
    var love = jinceon.love;
    love.call(jinceon); //jinceon love charming lady
     
    //可以看到 jinceon.love() 和 love.call(jinceon) 是等价的
     

    再次回到正文,看这段代码,继续代入变量

    function s(o, u) {
        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 o = 1;
    var yourModule = t[o][0] = function(require,module,exports){ //b.js
                var result = require('./a');
                console.log(result.a);
            }
        
    var r = function (e) {
            var n = t[o][1][e];//t[o][1]的值为{"./a":1},所以t[o][1][e]的值为1,所以这里的作用是将b.js加载的a.js也读取处理
            return s(n ? n : e)
        }
        
    function s(o, u) {
        var l = n[o] = {exports: {}};
        yourModule.call(l.exports, r, l, l.exports, e, t, n, r)
        return n[o].exports //返回整个模块n[o]的接口,即module。exports
    }
     
    
    
    //然后实际上yourModule只用到了3个形参,我们把传入的其他参数先无视
    function s(o, u) {
        var l = n[o] = {exports: {}};
        yourModule.call(l.exports, r, l, l.exports)
        //yourModule(r, l, l.exports); //this->l.exports,上下文环境为n[o]=l
        return n[o].exports
    }
     
    
    
    //最后替换掉call
    function s(o, u) {
    //r即require,require('./a'),则'./a'为上面r函数的参数e的值,往上看 function yourModule(require, module, exports) { var result = require('./a');//得到a.js的n[o].exports console.log(result.a); } var l = n[o] = {exports: {}}; yourModule(r, l, l.exports); //this->l.exports,这里就将b.js模块中的内容放入yourModule函数中,运行来将需要的模块都放入缓存区域中 return n[o].exports }

         然后就是浏览器的调用了

      index.html引用bb.js,控制台显示100

    //index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
    <script src="bb.js"></script>    
    </body>
    </html>

    原理

      Browserify到底做了什么?安装一下browser-unpack,就能清楚原理了

    $ npm install browser-unpack -g

      然后,使用下列命令,将前面生成的bb.js解包

    $ browser-unpack < bb.js

      可以看到,browerify将所有模块放入一个数组,id属性是模块的编号,source属性是模块的源码,deps属性是模块的依赖

      因为b.js里面加载了a.js,所以deps属性就指定./a对应1号模块。执行的时候,浏览器遇到require('./a')语句,就自动执行1号模块的source属性,并将执行后的module.exports属性值输出

      browerify将a.js和b.js打包,并生成bb.js,browser-unpack将bb.js解包,是一个逆向的过程。但实际上,bb.js依然存在

    本地实现了一下:

    userdeMacBook-Pro:stream-learning user$ npm install -g browserify
    /usr/local/bin/browserify -> /usr/local/lib/node_modules/browserify/bin/cmd.js
    + browserify@16.2.3
    added 136 packages from 109 contributors in 49.572s
    userdeMacBook-Pro:stream-learning user$ browserify main.js > bundle.js
    userdeMacBook-Pro:stream-learning user$ ls
    bundle.js        node_modules        public
    index.js        package-lock.json    test.js
    main.js            package.json        views
    userdeMacBook-Pro:stream-learning user$ npm install browser-unpack -g
    /usr/local/bin/browser-unpack -> /usr/local/lib/node_modules/browser-unpack/bin/cmd.js
    + browser-unpack@1.3.0
    added 14 packages from 84 contributors in 31.748s
    userdeMacBook-Pro:stream-learning user$ browser-unpack < bundle.js
    [
    {"id":1,"source":"(function (__dirname){
    const express = require('express');
    const app = new express();
    const ejs = require('ejs');
    const path = require('path');
    app.set('views',path.join(__dirname,'views'));
    app.engine('.html',ejs.__express);
    app.set('view engine','html');
    
    app.use(express.static(path.join(__dirname,'public')));//放css\js等文件
    
    var server = app.listen(8081,function(){
    	var host = server.address().address;
    	var port = server.address().port;
    	console.log("应用实例,访问地址为  %s:%s",host,port);
    });
    
    app.get('/', function(req, res){
      	res.render('index');
    });
    
    
    
    // var browserify = require('browserify');
    // var http = require('http');
    
    // http.createServer(function (req, res) {
    //   if (req.url === '/bundle.js') {
    //     res.setHeader('content-type', 'application/javascript');
    //     var b = browserify(__dirname + '/main.js').bundle();
    //     b.on('error', console.error);
    //     b.pipe(res);
    //   }
    //   else res.writeHead(404, 'not found')
    // });
    
    
    // var browserify = require('browserify-middleware');
    
    // app.get('/bundle1.js', browserify('./index1.js'));
    
    
    }).call(this,"/")","deps":{"ejs":25,"express":31,"path":228},"entry":true}
    ,
    {"id":2,"source":"'use strict'
    
    /**
     * Module dependencies.
     * @private
     */
    
    var Negotiato
  • 相关阅读:
    四年的积分数据,反映了信息化的复杂
    Python判断实例对象真与假
    ParameterizedType及其方法详解
    BootStrap的学习
    HTML标签
    CSS样式常见样式
    jQuery的使用
    DOS命令详解
    JavaScript学习
    CSS样式
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/9767989.html
Copyright © 2020-2023  润新知