之前在写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.
added packages from contributors in .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.
added packages from contributors in .748s
userdeMacBook-Pro:stream-learning user$ browser-unpack < bundle.js
[
{"id":,"source":"(function (__dirname){\nconst express = require('express');\nconst app = new express();\nconst ejs = require('ejs');\nconst path = require('path');\napp.set('views',path.join(__dirname,'views'));\napp.engine('.html',ejs.__express);\napp.set('view engine','html');\n\napp.use(express.static(path.join(__dirname,'public')));//放css\\js等文件\n\nvar server = app.listen(8081,function(){\n\tvar host = server.address().address;\n\tvar port = server.address().port;\n\tconsole.log(\"应用实例,访问地址为 %s:%s\",host,port);\n});\n\napp.get('/', function(req, res){\n \tres.render('index');\n});\n\n\n\n// var browserify = require('browserify');\n// var http = require('http');\n\n// http.createServer(function (req, res) {\n// if (req.url === '/bundle.js') {\n// res.setHeader('content-type', 'application/javascript');\n// var b = browserify(__dirname + '/main.js').bundle();\n// b.on('error', console.error);\n// b.pipe(res);\n// }\n// else res.writeHead(404, 'not found')\n// });\n\n\n// var browserify = require('browserify-middleware');\n\n// app.get('/bundle1.js', browserify('./index1.js'));\n\n\n}).call(this,\"/\")","deps":{"ejs":,"express":,"path":},"entry":true}
,
{"id":,"source":"'use strict'\n\n/**\n * Module dependencies.\n * @private\n */\n\nvar Negotiato

browerify初步了解的更多相关文章

  1. 移动端之Android开发的几种方式的初步体验

    目前越来越多的移动端混合开发方式,下面列举的大多数我都略微的尝试过,就初步的认识写个简单的心得: 开发方式 开发环境 是否需要AndroidSDK 支持跨平台 开发语言&技能 MUI Win+ ...

  2. CSharpGL(29)初步封装Texture和Framebuffer

    +BIT祝威+悄悄在此留下版了个权的信息说: CSharpGL(29)初步封装Texture和Framebuffer +BIT祝威+悄悄在此留下版了个权的信息说: Texture和Framebuffe ...

  3. Android自定义View初步

    经过上一篇的介绍,大家对于自定义View一定有了一定的认识,接下来我们就以实现一个图片下显示文字的自定义View来练习一下.废话不多说,下面进入我们的正题,首先看一下我们的思路,1.我们需要通过在va ...

  4. 初步认识Node 之Node为何物

    很多人即便是在使用了Node之后也不知道它到底是什么,阅读完本文你应该会有一个初步的.具体的概念了.    Node的目标 提供一种简单的构建可伸缩网络程序的方法.那么,什么是可伸缩网络程序呢?可伸缩 ...

  5. [入门级] 基于 visual studio 2010 mvc4 的图书管理系统开发初步 (二)

    [入门级] 基于 visual studio 2010 mvc4 的图书管理系统开发初步 (二) Date  周六 10 一月 2015 By 钟谢伟 Category website develop ...

  6. 基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  7. Azure底层架构的初步分析

    之所以要写这样的一篇博文的目的是对于大多数搞IT的人来说,一般都会对这个topic很感兴趣,因为底层架构直接关乎到一个公有云平台的performance,其实最主要的原因是我们的客户对此也非常感兴趣, ...

  8. CozyRSS开发记录14-RSS源管理初步完工

    CozyRSS开发记录14-RSS源管理初步完工 1.添加源的响应 DialogHost.Show有几个版本的重载,加一个DialogClosingEventHandler参数.我们让添加源对话框的添 ...

  9. 初步了解CPU

    了解CPU By JackKing_defier 首先说明一下,本文内容主要是简单说明CPU的大致原理,所需要的前提知识我会提出,但是由于篇幅我不会再详细讲解需要的其他基础知识.默认学过工科基础课. ...

随机推荐

  1. [android] 看博客学习hashCode()和equals()

    equals()是Object类提供的一个方法,众所周知,每一个java类都继承自Object,所以说每一个对象都有一个equals()方法,我们在用这个方法时却一般重写这个方法 Object类中eq ...

  2. js弹窗 js弹出DIV,并使整个页面背景变暗

    1.首先写一个遮罩层div,然后再写一个弹窗的div <!-- 遮罩层 --> <div id="cover" style="background: # ...

  3. linux下使用sublime-text写coffee遇到的编译问题

    Traceback (most recent call last): File "/opt/sublime_text/sublime_plugin.py", line 556, i ...

  4. [bug]解决chrome浏览器不支持所有媒体音乐不自动播放问题

    声音无法自动播放这个在 IOS/Android 上面一直是个惯例,桌面版的 Safari 在 2017 年的 11 版本也宣布禁掉带有声音的多媒体自动播放功能,紧接着在 2018 年 4 月份发布的 ...

  5. CentOS7添加入windows2008的AD域

    采用域控对用户权限进行限制的时候,经常会出现需要将linux加入windows域,毕竟windows的AD域超级强大.用户名可以由windows进行统一管理,方便办公使用.下面简单介绍如何进行配置. ...

  6. .net中反射与IOC容器实现

    反射还是很有用的,比如IOC容器基本上都是通过反射实现的. IOC是什么 IOC:Inversion of Control 控制反转是一种是面向对象编程中的一种设计原则,用来减低计算机代码之间的耦合度 ...

  7. 《Spring实战》-- 'cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element' 错误的解决办法

    在Eclipse中新建了一个maven项目学习Spring,在 service.xml 中配置 Spring,想要学习'面向切面的Spring',service.xml 内容如下: <beans ...

  8. 2018-10-23 23:29:54 clanguage

    2018-10-23   23:29:54 clanguage 在 32 位环境以及 Win64 环境下的运行结果为: short=2, int=4, long=4, char=1 在 64 位 Li ...

  9. 【转】vs2010打开qt的.pro文件时错误解决办法

    注意:qt creator工程中一般都已经存在*.pro文件,里面存放着一些自己配置的包含头文件和lib库文的信息,最好不要再重新使用qmake -project生成,若重新生成,则可能要重新增加配置 ...

  10. Java 注解用法详解——@SuppressWarnings

    转自: https://www.cnblogs.com/fsjohnhuang/p/4040785.html Java魔法堂:注解用法详解——@SuppressWarnings   一.前言 编码时我 ...