摘要:當發現該路徑為文件夾時則,則依次查找如下文件字段擴展名文件解析文件可以定位之后,則是解析定位下來的文件了,本文用的是,文檔如規范文檔解析文件返回一個語法樹。對語法樹進行遍歷對遇到為且其為為的節點將該節點的以及下標包裝成對象儲存起來。
前言
自動化打包工具webpack,相信很多人和我一樣嘗試著研究下它,但是繁雜的功能以及高度抽象的代碼實在是很難理解,所以筆者只能通過github的webpack的第一次提交進行分析,實現,并將實現的一些心得分享一下。
功能分析對于node端來講,有commonjs來規范模塊的標識,定義,引用。而瀏覽器端由于缺乏原生對象支持就需要通過自我實現來模擬commonjs規范。
webpack是通過一個IIFE立即調用函數表達式去實現這個規范的。簡要的去注釋,去除內部運行的代碼,其格式如下:
(function(module){})([function(){},function(){}]);
簡單點說就是各個模塊代碼以數組的形式傳遞給運行函數,在進行存儲。詳細分析可以參考簡要分析webpack打包后代碼
所以實現以上的功能需求點如下:
文件路徑分析與定位resolve
文件編譯&解析,分析出依賴文件parse
生成需要打包的文件樹depTree
將依賴文件寫入輸出文件內writeChunk
文件分析與定位本功能和node的require類似,故有參考node require源碼
文件分析,將文件為兩種類型
以 "./","../","/" 標識符開頭的路徑文件模塊
該類文件會通過path.join 轉化為真實的路徑而定位。
自定義的文件模塊
這類相對比較麻煩,他在當前目錄下面的node_modules,查找文件,未找到則一路向上查找,最終查找到或者拋出異常。如:
[ "/Users/zhujian/Documents/workspace/webpack/simple-webpack/node_modules", "/Users/zhujian/Documents/workspace/webpack/node_modules", "/Users/zhujian/Documents/workspace/node_modules", "/Users/zhujian/Documents/node_modules", "/Users/zhujian/node_modules", "/Users/node_modules", "/node_modules" ]
文件定位
對于部分文件并沒有帶擴展名,此時有默認的擴展名依次以.js,.jsx為后綴依次補充。當然我們可以用傳入extensions,修改默認的擴展名。
{extensions:["js","jsx","jpg"]}
當發現該路徑為文件夾時則,則依次查找如下文件
package.json(main字段)
index+(擴展名)
文件解析
文件可以定位之后,則是解析定位下來的文件了,本文用的是exprima,文檔如parser規范文檔
esprima解析文件,返回一個語法樹。
對語法樹進行遍歷,對遇到type 為CallExpression,且其callee為name為require的節點,將該節點的value,以及下標包裝成對象儲存起來。
比如
const b = require("./b");
解析后
.... "init": { "type": "CallExpression", "callee": { "type": "Identifier", "name": "require", "range": [ 10, 17 ] }, "arguments": [ { "type": "Literal", "value": "./b", "raw": ""./b"", "range": [ 18, 23 ] } ], "range": [ 10, 24 ] }, ....
我們要做的就是提取value "./b",以及該字符串在文件所處的位置range。
文件樹生成主要是從入口文件開始,將所有依賴的js,以及其內容,分配的id組成一個可操作的扁平化的對象和存儲著name與id對應的map對象。
實現手法上也是遞歸resolve函數,獲取到各個文件的依賴,文件,id的信息,最后得到depTree對象
舉個例子:
{ modules: { "/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/a.js": { filename: "/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/a.js", id: 0, requires: [Array], rangeRequires: [Array], source: "const b = require("./b"); const c = require("c"); const {e, f, g} = require("./m"); }, "/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/b.js": { filename: "/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/b.js", id: 1, requires: [], rangeRequires: [], source: "const b = "b"; module.exports = b; " }, "/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/node_modules/c.js": { filename: "/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/node_modules/c.js", id: 2, requires: [], rangeRequires: [], source: "const c = "c"; module.exports = c; " }, "/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/m.js": { filename: "/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/m.js", id: 3, requires: [], rangeRequires: [], source: "http:// const core = require("./core"); const a = 1; }, nextModuleId: 4, mapNameToId: { "/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/a.js": 0, "/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/b.js": 1, "/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/node_modules/c.js": 2, "/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/m.js": 3 } }文件寫入
寫入主函數,替換入口的執行函數。這塊會用到之前的path和id關系的map對象,通過路口文件的絕對路徑,找出入口文件的mainId,并進行替換。
寫入參數數組。遍歷文件樹,將文件節點的source內容替換掉
大致如下:
require("module") 替換為__webpack_require__(0)
這個地方要考慮的點是
如果用replace替換的話,會影響source帶部分關鍵字的內容,不可取。
用索引替換的字符串的話,一旦第一個替換成功,整個字符串長度發生變化,原先的索引下標就失效了。
官方實現
const result = [source]; replaces.forEach(replace => { const {from, value, end} = replace; const source = result.shift(); result.unshift(source.substr(0, from), value, source.substr(end)) });代碼實現
本人的簡易版webpack實現simple-webpack
(完)
參考資料webpack早期源碼
require源碼解讀
node require源碼
parser規范文檔
簡要分析webpack打包后代碼
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107753.html
摘要:模仿實現簡單的打包工具是一款前端項目構建工具,隨著現在前端生態的發展,已經成為前端開發人員必備的技能之一,很多開發人員開始使用和的時候,都會使用默認的單頁應該創建指令來創建一個工程化項目,實際上,這些工程化的項目都是基于來搭建的當我們熟悉使 模仿webpack實現簡單的打包工具 webpack是一款前端項目構建工具,隨著現在前端生態的發展,webpack已經成為前端開發人員必備的技能之...
摘要:模仿實現簡單的打包工具是一款前端項目構建工具,隨著現在前端生態的發展,已經成為前端開發人員必備的技能之一,很多開發人員開始使用和的時候,都會使用默認的單頁應該創建指令來創建一個工程化項目,實際上,這些工程化的項目都是基于來搭建的當我們熟悉使 模仿webpack實現簡單的打包工具 webpack是一款前端項目構建工具,隨著現在前端生態的發展,webpack已經成為前端開發人員必備的技能之...
摘要:模仿實現簡單的打包工具是一款前端項目構建工具,隨著現在前端生態的發展,已經成為前端開發人員必備的技能之一,很多開發人員開始使用和的時候,都會使用默認的單頁應該創建指令來創建一個工程化項目,實際上,這些工程化的項目都是基于來搭建的當我們熟悉使 模仿webpack實現簡單的打包工具 webpack是一款前端項目構建工具,隨著現在前端生態的發展,webpack已經成為前端開發人員必備的技能之...
摘要:先看下官方文檔中對模塊的描述在模塊化編程中,開發者將程序分解成離散功能塊,并稱之為模塊。每個模塊具有比完整程序更小的接觸面,使得校驗調試測試輕而易舉。 先看下webpack官方文檔中對模塊的描述: 在模塊化編程中,開發者將程序分解成離散功能塊(discrete chunks of functionality),并稱之為模塊。每個模塊具有比完整程序更小的接觸面,使得校驗、調試、測試輕而易...
閱讀 2986·2021-11-23 09:51
閱讀 2798·2021-11-11 16:55
閱讀 2907·2021-10-14 09:43
閱讀 1394·2021-09-23 11:22
閱讀 1034·2019-08-30 11:04
閱讀 1663·2019-08-29 11:10
閱讀 955·2019-08-27 10:56
閱讀 3102·2019-08-26 12:01