研究了一下 Webpack 打包原理绪钥,順手掙了個(gè) AirPods Pro

這些年灿里,Webpack 基本成了前端項(xiàng)目打包構(gòu)建的標(biāo)配。關(guān)于它的原理和用法的文章在網(wǎng)上汗牛充棟程腹,大家或多或少都看過一些匣吊。我也一樣,大概了解過它的構(gòu)建過程以及常用 loader 和 plugin 的配置寸潦、性能優(yōu)化方法等等色鸳,僅限于“面試夠用”的程度。在實(shí)際工作中见转,往往是配置好后就放一邊了命雀,沒有遇到問題是不會(huì)再碰它的。

我一直有個(gè)習(xí)慣(或者叫毛舱扼铩)吏砂,就是不太愿意花時(shí)間去研究暫時(shí)用不上的技術(shù)撵儿。我稱其為“屠龍之技”:學(xué)會(huì)了屠龍的技術(shù),可是找不到龍啊赊抖。這樣的技術(shù)沒有實(shí)際應(yīng)用來強(qiáng)化统倒,過不了多久就會(huì)荒廢的。也因?yàn)檫@個(gè)氛雪,之前面試吃過很多虧,畢竟由于平臺(tái)所限耸成,工作中根本接觸不到某些方面的技術(shù)报亩。不過話又說回來,為了面試也要去學(xué)井氢,硬著頭皮的那種弦追。

扯遠(yuǎn)了,說回正題花竞。前不久劲件,網(wǎng)上有個(gè)哥們通過我的一篇博客找到我,讓我?guī)退鉀Q一個(gè)問題约急。這篇博客是關(guān)于如何在現(xiàn)有 Vue.js 項(xiàng)目里快速實(shí)現(xiàn)多語言切換的零远。他的項(xiàng)目也遇到同樣的問題,但是他不懂代碼厌蔽,想付費(fèi)求助牵辣。


image.png

按照我的方法,應(yīng)該能很快完成需求奴饮。我大概估算了下工作量纬向,報(bào)了個(gè)價(jià)。但是后面了解到的情況讓我大跌眼鏡:他的項(xiàng)目是打包好的戴卜,沒有源碼逾条!說原來的開發(fā)不在了,都聯(lián)系不上投剥,找不到源碼师脂。要在沒有源碼的已有項(xiàng)目上加功能,寫代碼這么多年薇缅,還是第一次碰到危彩。

我那篇文章的方案,是重寫 Vue.prototype.__patch__ 方法泳桦,攔截 DOM 渲染過程汤徽,將翻譯后的文本替換上去。面對(duì)一坨可讀性極差的壓縮代碼灸撰,還怎么寫下去谒府?當(dāng)時(shí)他還沒付款拼坎,我本打算放棄了。直到晚上睡覺前完疫,這個(gè)問題一直盤旋在腦海里泰鸡,揮之不去。難道我的方案有這么大的局限性壳鹤?很不服氣笆⒘洹!

沒想到第二天芳誓,突然開竅了余舶。這個(gè)問題的核心,不就是從壓縮代碼里找到 Vue 的引用嗎锹淌?剩下的邏輯匿值,都可以通過注入自己的 JS 代碼來完成。

明確了這個(gè)思路赂摆,就開始了壓縮代碼挖掘之旅挟憔。我們都知道,Vue 項(xiàng)目在打包構(gòu)建后烟号,會(huì)在 HTML 文件里注入幾個(gè) JS 文件绊谭,大概像這樣:


image.png

其中的 vendor.xxx.js 就包含了 Vue.js 框架代碼。但我們知道褥符,這樣構(gòu)建出來的代碼肯定是用了閉包龙誊,各個(gè)模塊都被作用域屏蔽了,window下是訪問不到這些模塊的喷楣√舜螅可以試試在控制臺(tái)輸入 Vue ,會(huì)提示Uncaught ReferenceError: Vue is not defined铣焊。

這個(gè)時(shí)候就需要研究 Webpack 是怎么打包的了逊朽。這里的關(guān)鍵在 manifest.js 文件,它是 Webpack 的運(yùn)行時(shí)代碼曲伊,定義了一個(gè)webpackJsonp函數(shù)叽讳,代碼簡(jiǎn)化后是這樣的:

(function(modules) {
  window["webpackJsonp"] = function webpackJsonpCallback(chunkIds, moreModules, executeModules) {
    var moduleId, result;
    for (moduleId in moreModules) {
      if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
        modules[moduleId] = moreModules[moduleId];
      }
    }
    if (executeModules) {
      for (i = 0; i < executeModules.length; i++) {
        result = __webpack_require__(executeModules[i]);
      }
    }
    return result;
  };
  var installedModules = {};

  function __webpack_require__(moduleId) {
    if (installedModules[moduleId]) {
      return installedModules[moduleId].exports;
    }
    var module = installedModules[moduleId] = {
      exports: {}
    };
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    return module.exports;
  }
})([]);

打包后就是通過這個(gè)函數(shù)來加載各個(gè)模塊的。因此坟募,只要找到 Vue 這個(gè)模塊被打包后的 ID岛蚤,就能通過它來獲取。再看看vendor.xxx.js這個(gè)文件內(nèi)容:

webpackJsonp([38], {
    "+abY": function(t, e, n) {
        "use strict";
        n("DmDj")("sup", function(t) {
            return function() {
                return t(this, "sup", "", "")
            }
        })
    },
    "+fX/": function(t, e, n) {
        var r = n("awYD")
          , i = n("JE6n")
          , o = n("0U5H")("match");
        t.exports = function(t) {
            var e;
            return r(t) && (void 0 !== (e = t[o]) ? !!e : "RegExp" == i(t))
        }
    },
  "IvJb": function(t, e, n) {
      // 這就是 Vue 框架代碼
  }
)

可以看到各個(gè)模塊就是一個(gè)個(gè)的function懈糯。通過 Vue 框架里的一些關(guān)鍵字搜索涤妒,找到了 Vue 打包后的 ID 是IvJb。因此只要調(diào)用webpackJsonp函數(shù)就能獲取 Vue變量:

var vue = webpackJsonp([], {}, ['IvJb']);
var __patch__ = vue.default.prototype.__patch__;
vue.default.prototype.__patch__ = function () {
var elm = __patch__.apply(this, arguments);
  var lang = getUrlParam('lang')
  if (lang) {
    //翻譯DOM里的文本
    translate(elm, lang);
  }
  return elm;
};

關(guān)鍵問題解決了赚哗!通過同樣的辦法她紫,還可以獲取 axios 硅堆,把 axiosbaseUrl 改成了完整路徑方便本地調(diào)試。剩下的工作就簡(jiǎn)單了贿讹,一是多語言文件文字翻譯渐逃,那都是體力活,就交給那哥們自己干了民褂。二是加一個(gè)語言切換菜單茄菊,這個(gè)也不難,原生 DOM 操作而已赊堪,再稍微調(diào)下樣式就搞定了买羞。

前前后后花了不到一天時(shí)間,完成了這個(gè)看似不可能的任務(wù)雹食。由此可見,了解工具和框架的底層原理期丰,對(duì)于解決特定問題有著決定性的作用群叶。當(dāng)然,Webpack 功能非常強(qiáng)大钝荡,底層邏輯比這里說的復(fù)雜多了街立,我也沒有繼續(xù)深入研究〔和ǎ或許下次碰到問題時(shí)又是一次契機(jī)赎离。

關(guān)于多語言切換的方案,參考我之前寫的博客:現(xiàn)有 Vue.js 項(xiàng)目快速實(shí)現(xiàn)多語言切換的一種思路端辱。

本文首發(fā)于公眾號(hào) 1024譯站梁剔,這里不讓發(fā)二維碼。簡(jiǎn)書的未來舞蔽,肉眼可見荣病。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市渗柿,隨后出現(xiàn)的幾起案子个盆,更是在濱河造成了極大的恐慌,老刑警劉巖朵栖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颊亮,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡陨溅,警方通過查閱死者的電腦和手機(jī)终惑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來声登,“玉大人狠鸳,你說我怎么就攤上這事揣苏。” “怎么了件舵?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵卸察,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我铅祸,道長(zhǎng)坑质,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任临梗,我火速辦了婚禮涡扼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘盟庞。我一直安慰自己吃沪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布什猖。 她就那樣靜靜地躺著票彪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪不狮。 梳的紋絲不亂的頭發(fā)上降铸,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音摇零,去河邊找鬼推掸。 笑死,一個(gè)胖子當(dāng)著我的面吹牛驻仅,可吹牛的內(nèi)容都是我干的谅畅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼雾家,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼铃彰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起芯咧,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤牙捉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后敬飒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體邪铲,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年无拗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了带到。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡英染,死狀恐怖揽惹,靈堂內(nèi)的尸體忽然破棺而出被饿,到底是詐尸還是另有隱情,我是刑警寧澤搪搏,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布狭握,位于F島的核電站,受9級(jí)特大地震影響疯溺,放射性物質(zhì)發(fā)生泄漏论颅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一囱嫩、第九天 我趴在偏房一處隱蔽的房頂上張望恃疯。 院中可真熱鬧,春花似錦墨闲、人聲如沸今妄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛙奖。三九已至,卻和暖如春杆兵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仔夺。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工琐脏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缸兔。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓日裙,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親惰蜜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子昂拂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容