摘要:總體設計具體分析輸入的輸入內容整體上分為兩類。就是需要打包的文件,用于對輸入的內容進行處理。為了解決該問題,通過在中添加字段來制定瀏覽器使用的模塊。
歡迎到個人博客去看看: 戳著里
0. browserify是什么?browserify是目前比較流行的模塊打包工具之一(另外一個webpack)
基于流式(stream)思想設計
可以通過command line,也可以通過API來使用
僅處理javascript
模塊化的逆過程,但是推動著模塊化的更好發展
內置了一些node core module
node模塊可以在瀏覽器端使用,是同構應用的有力武器
1. 從demo說起存在兩個js: square.js、foo.js
// square.js module.exports = function (a) { return a*a; }
// foo.js var sq = require("./square"); console.log(sq(2));
接著通過API進行打包:
var browserify = require("../node-browserify"); var fs = require("fs"); var b = browserify(["./foo.js"]); b.require("./square.js", { expose: "square" }) b.bundle().pipe(fs.createWriteStream("./bundle.js"));
得到一個可以在瀏覽器端使用的bundle.js:
(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接下來分析browserify是如何做到的。
2. 總體設計 3. 具體分析 3.1 輸入(input)browserfiy的輸入內容整體上分為兩類:file、transform function。file就是需要打包的文件,transform function用于對輸入的file內容進行處理。例如:我們需要對coffeeScript文件進行打包,那么打包之前就需要將coffeeScript文件轉換成javascript,然后才能進行打包。
那么輸入的接口都有哪些呢:
b = new Browserify(file, opts): 在實例化的時候,將相關內容輸入進去
b.require(file, opts): 指定可以在瀏覽器端require的文件
b.add(file, opts):實例化時未指定參數的情況下,可以使用該接口
b.external/exclude/ignore: 一些file的特殊配置
b.transform(tr, opts): 指定transform function,用于對module進行轉換
3.2 處理b.pipeline是browserify里面的核心對象。通過這個對象,可以對module進行一系列的處理,這個對象具有如下特點:
由labeled-stream-splicer生成
整合了很多transform stream后,生成一個整體transform stream
帶有label,通過label訪問內部具體的transform stream
write進去的chunk分兩種情況:帶有file的對象,帶有transform function的對象
偽代碼:
// 創建pipeline Browserify.prototype._createPipeline = function (opts) { ... var pipeline = splicer.obj([ "record", [ this._recorder() ], "deps", [ this._mdeps ], "json", [ this._json() ], "unbom", [ this._unbom() ], "unshebang", [ this._unshebang() ], "syntax", [ this._syntax() ], "sort", [ depsSort(dopts) ], "dedupe", [ this._dedupe() ], "label", [ this._label(opts) ], "emit-deps", [ this._emitDeps() ], "debug", [ this._debug(opts) ], "pack", [ this._bpack ], "wrap", [] ]); ... return pipeline; } // pipeline write進去的chunk Browserify.prototype.transform = function (tr, opts) { ... var rec = { transform: tr, options: opts, global: opts.global }; // 帶有transform function的對象 this.pipeline.write(transform); ... } Browserify.prototype.require = function (file, opts) { ... var rec = { source: buf.toString("utf8"), entry: defined(opts.entry, false), file: filename, id: id }; // 帶有file的對象 this.pipeline.write(rec); }接下來針對其中關鍵的deps、pack進行分析。
3.3 模塊依賴的解析面對的問題:
在模塊合并前,首先要做的工作就是找出入口文件(entry file)的依賴以及依賴的依賴,例如在charpter1的demo中,入口文件foo.js僅依賴square.js
考慮要對源代碼進行轉換
browserify通過module-deps來解決上述問題,通過下面的代碼可以看到解析的結果:
var browserify = require("../node-browserify"); var fs = require("fs"); var b = browserify(["./foo.js"], { debug: true, basedir: "./" }); b.require("./square.js", { expose: "square" }) b.on("dep", function (row) { console.log(row); }) b.bundle().pipe(fs.createWriteStream("./bundle.js"));輸出的JSON結果為:
{ "entry":true, "expose":false, "basedir":"./", "file":"/Users/lizhenhua/Documents/france/z-react/foo.js", "id":1, "order":0, "source":""use strict"; var sq = require("./square"); console.log(sq(2)); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZvby5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLElBQUksRUFBRSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztBQUM3QixPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDIiwiZmlsZSI6ImZvby5qcyIsInNvdXJjZXNDb250ZW50IjpbInZhciBzcSA9IHJlcXVpcmUoJy4vc3F1YXJlJyk7XG5jb25zb2xlLmxvZyhzcSgyKSk7XG4iXX0=", "deps":{ "./square":2 }, "index":1, "indexDeps":{ "./square":2 } } { "id":2, "source":""use strict"; module.exports = function (a) { return a * a; }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNxdWFyZS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLE1BQU0sQ0FBQyxPQUFPLEdBQUcsVUFBVSxDQUFDLEVBQUU7QUFDNUIsU0FBTyxDQUFDLEdBQUMsQ0FBQyxDQUFDO0NBQ1osQ0FBQSIsImZpbGUiOiJzcXVhcmUuanMiLCJzb3VyY2VzQ29udGVudCI6WyJtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChhKSB7XG4gIHJldHVybiBhKmE7XG59XG4iXX0=", "deps":{}, "file":"/Users/lizhenhua/Documents/france/z-react/square.js", "index":2, "indexDeps":{} }另外,在node端、browser端可能用到不同的代碼,例如請求發送(參看superagent),node端使用http/https模塊,而瀏覽器端則使用XMLHttpRequest對象。為了解決該問題,browserify通過在package.json中添加browser字段來制定瀏覽器使用的模塊。
{ "name": "mypkg", "version": "1.2.3", "main": "main.js", "browser": "browser.js" }在解析的時候,則需要分別使用resolve、browser-resolve來進行解析。
3.4 模塊的打包利用browser-pack,將上述的json數據打包合并成一個文件,browser-pack具體做了如下工作:
定義瀏覽器端可用的require關鍵詞
到browser-pack中可以看到如下寫好的代碼片段:
(function outer (modules, cache, entry) { // Save the require from previous bundle to this closure if any var previousRequire = typeof require == "function" && require; function newRequire(name, jumped){ if(!cache[name]) { if(!modules[name]) { // if we cannot find the module within our internal map or // cache jump to the current global require ie. the last bundle // that was added to the page. var currentRequire = typeof require == "function" && require; if (!jumped && currentRequire) return currentRequire(name, true); // If there are other bundles on this page the require from the // previous one is saved to "previousRequire". Repeat this as // many times as there are bundles until the module is found or // we exhaust the require chain. if (previousRequire) return previousRequire(name, true); var err = new Error("Cannot find module "" + name + """); err.code = "MODULE_NOT_FOUND"; throw err; } var m = cache[name] = {exports:{}}; modules[name][0].call(m.exports, function(x) { var id = modules[name][1][x]; return newRequire(id ? id : x); },m,m.exports,outer,modules,cache,entry); } return cache[name].exports; } for(var i=0;i2.將json source合并在一起
可以對charpter1的結果進行解析,除了上述的newRequire外,還包含如下結構內容:
(newRequire...)(source, cache, entry); // source 代碼 source = { 1:[ function(require,module,exports){ "use strict"; var sq = require("./square"); console.log(sq(2)); }, {"./square":"square"} ], "square":[ function(require,module,exports){ "use strict"; module.exports = function (a) { return a * a; }; }, {} ] }; // cache cache = {} // entry entry = [1];上述代碼片段中:
source: 是一個map結構,key存在兩種情況(默認為內部數字、顯示expose出來的key)
source元素分為兩部分:源代碼(包含的function(require, module, exports) {...})、代碼中存在的依賴
cache是緩存信息,避免再次讀取souce
entry: 是打包代碼入口文件的key
4. browserify的使用在ES6沒有全面支持以前,browserify還會存在很長一段時間,還會有很強的生命力。相比較webpack,個人更喜歡browserify,webpack給人的感覺是一直在配置、使用plugin,并且代碼結構很復雜,里面涉及大量事件,源碼不容易閱讀。而使用browserify給人感覺是在開發,使用起來也較為靈活,同時browserify的stream設計思路給人更多啟發,可以向其他方向(例如css合并)遷移。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78284.html
摘要:它的關鍵能力,是模塊及依賴管理。其次,保持局部變量風格。我們很習慣通過和這樣的全局變量來訪問這樣的庫,但如果使用,它們都應只作為局部變量這里的就只存在于這個文件的代碼范圍內獨立的作用域。 引言 1. manually 以前,我新開一個網頁項目,然后想到要用jQuery,我會打開瀏覽器,然后找到jQuery的官方網站,點擊那個醒目的Download jQuery按鈕,下載到.js文件,然...
摘要:以前一直對前端構建工具的理解不深,經過幾天的研究特意來總結一下,第一次寫博客,有寫錯的請多多見諒,該文章我也從其他博客拷了一些內容,如果有冒犯之處,請指出。強大的設計使得它更像是一個構建平臺,而不只是一個打包工具。 以前一直對前端構建工具的理解不深,經過幾天的研究特意來總結一下,第一次寫博客,有寫錯的請多多見諒,該文章我也從其他博客拷了一些內容,如果有冒犯之處,請指出。 如今,網頁不再...
摘要:在講解之前先回顧一下筆者在項目開發中的工作流變化時代此時工作流大致為結合插件處理視圖處理樣式等庫此時由于依賴少手動引入各種標簽結合調試界面時代利用指令服務控制器將邏輯拆分為多個文件利用編譯會將分為全局樣式和組件樣式下載各種依賴此時任需要手動 在講解 webpack 之前先回顧一下筆者在項目開發中的工作流變化. jquery 時代 此時工作流大致為 jquery 結合插件處理視圖 bo...
摘要:但是最終,我們會為模塊化帶來的好處而開心模塊將作用域限制于組件中,從而避免了全局作用域的問題。但這是因為模塊將樣式和組件相綁定,從而不會發生全局樣式的沖突。先從版本的模塊化開始。我認為模塊化背后的思想是正確的。 原文鏈接: https://www.sitepoint.com/und... 在瞬息萬變的前端開發世界中,很難找到一個真正有意義的概念,并且將其清晰明了的向廣大人民群眾普及。 ...
摘要:承接前一篇做一個合格的前端,自動化構建工具入門教程故而整理了如下插件資源大全。接下來我會逐一開源觀點網開發過程中的前后端技術,如全文索引自定義富文本編輯器圖片上傳壓縮水印等等。 承接前一篇《做一個合格的前端,gulp自動化構建工具入門教程》故而整理了如下gulp插件資源大全。**【我的新作觀點網:http://www.guandn.com (觀點網是一個獵獲新奇、收獲知識、重在獨立思考...
閱讀 2833·2021-11-25 09:43
閱讀 2477·2021-10-09 09:44
閱讀 2801·2021-09-22 15:49
閱讀 2568·2021-09-01 11:43
閱讀 2542·2019-08-30 14:16
閱讀 465·2019-08-29 17:24
閱讀 3020·2019-08-29 14:00
閱讀 1384·2019-08-29 13:05