webpack解惑

1、webpack的模塊化原理

webpack 本身維護了一套模塊系統(tǒng)魔慷,這套模塊系統(tǒng)兼容了所有前端歷史進程下的模塊規(guī)范逞敷,包括 amd commonjs es6 等

(function(modules) {
  function __webpack_require__(moduleId) {
    var module =  {
      i: moduleId,
      l: false,
      exports: {}
    };
    modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
    return module.exports;
  }
  return __webpack_require__(0);
})([(function (module, __webpack_exports__, __webpack_require__) {
    // 模塊的邏輯代碼
    ...
  })]

原理的關(guān)鍵有兩點:
1必怜、所有的模塊都被封裝成function (module, webpack_exports, webpack_require){}的形式养涮,
2、webpack_require函數(shù)罐监,該函數(shù)內(nèi)部有一個module對象吴藻,該對象有兩個重要屬性:i代表模塊id,exports代表要暴露給外面的對象弓柱。每次調(diào)用webpack_require時都會傳入一個數(shù)字作為模塊id沟堡,這樣不同模塊就能被區(qū)分,另外該函數(shù)將module.exports作為返回值吆你。每個模塊的導出值都會被記錄在module.exports對象里弦叶,其他依賴該模塊的模塊就能取到對應數(shù)據(jù)

2俊犯、webpack2是如何支持import和require兩種引入模塊的方式

首先webpack是基于node的妇多,node的模塊規(guī)范是commonjs,該規(guī)范就是使用require和module.exports來引入和導出模塊的燕侠;其次者祖,es6 module是靜態(tài)的依賴,所以可以在運行前進行代碼轉(zhuǎn)換绢彤。import的本質(zhì)其實就是require七问,webpack在進行靜態(tài)分析時會將其轉(zhuǎn)為require。這也說明了在webpack中可以混用import和require茫舶,因為二者本質(zhì)上都是require

3械巡、如何使用 webpack 的 tree-shaking 技術(shù)

webpack 的 tree-shaking 基于ES6的模塊靜態(tài)依賴機制,babel也是可以將ES6模塊轉(zhuǎn)換為commenjs模塊的饶氏,但是你一旦這樣做了就會失去tree-shaking技術(shù)讥耗。所以在使用babel轉(zhuǎn)換ES6時一般會如下配置,即只使用bable的ES6語法轉(zhuǎn)換能力疹启,不使用它的模塊處理古程,而是使用webpack2自己的模塊處理。

presets: [['babel-preset-es2015', {modules: false}]]

需要說明的是喊崖,即使在 引入模塊時使用了 es6 挣磨,但是引入的那個模塊卻是使用 commonjs 進行輸出雇逞,這也無法使用tree-shaking。
而第三方庫大多是遵循 commonjs 規(guī)范的茁裙,這也造成了引入第三方庫無法減少不必要的引入塘砸。
所以對于未來來說第三方庫要同時發(fā)布 commonjs 格式和 es6 格式的模塊。es6 模塊的入口由 package.json 的字段 module 指定晤锥。而 commonjs 則還是在 main 字段指定谣蠢。

4、import及export轉(zhuǎn)換為require和module.exports的規(guī)則是啥樣的

  • es6 的 export default 都會被轉(zhuǎn)換成 exports.default
  • export 的所有輸出都會添加到module.exports對象上
  • 使用require去引用ES6模塊的export default輸出時查近,注意用require('**').default
  • 導出
// ES6
export default 123;
export const a = 123;
const b = 3;
const c = 4;
export { b, c };
// 轉(zhuǎn)換后
exports.default = 123;
exports.a = 123;
exports.b = 3;
exports.c = 4;
exports.__esModule = true;

babel 轉(zhuǎn)換 es6 的模塊輸出邏輯非常簡單眉踱,即將所有輸出都賦值給 exports,并帶上一個標志 __esModule 表明這是個由 es6 轉(zhuǎn)換來的 commonjs 輸出霜威。

  • 導入
// 1谈喳、普通導入
import a from './a.js'     //引入一個 es6 模塊中的 default 輸出
// babel會這么轉(zhuǎn)
function _interopRequireDefault(obj) {
    return obj && obj.__esModule
        ? obj
        : { 'default': obj };
}
var _a = require('./a.js');
var _a2 = _interopRequireDefault(_a);
var a = _a2['default'];
// 2、通配符引入
import * as a from './a.js'  //將 es6 模塊的所有命名輸出以及defalut輸出打包成一個對象賦值給a變量
// Babel內(nèi)部這么轉(zhuǎn)
function _interopRequireWildcard(obj) {
    if (obj && obj.__esModule) {
        return obj;
    }
    else {
        var newObj = {}; // (A)
        if (obj != null) {
            for (var key in obj) {
                if (Object.prototype.hasOwnProperty.call(obj, key))
                    newObj[key] = obj[key];
            }
        }
        newObj.default = obj;
        return newObj;
    }
}
// 3戈泼、具名引入
import { a } from './a.js'  // 將 es6 模塊的a引入
//babel這樣轉(zhuǎn)
require('./a.js').a

5婿禽、plugin && loader

  • compiler & compilation 對象

compiler 對象代表了完整的 webpack 環(huán)境配置。這個對象在啟動 webpack 時被一次性建立大猛,并在所有可操作的設(shè)置中被配置扭倾,包括原始配置,loader 和插件挽绩。當在 webpack 環(huán)境中應用一個插件時膛壹,插件將收到一個編譯器對象的引用“埃可以使用它來訪問 webpack 的主環(huán)境模聋。

compilation 對象代表了一次單一的版本構(gòu)建和生成資源。當運行 webpack 開發(fā)環(huán)境中間件時唠亚,每當檢測到一個文件變化链方,一次新的編譯將被創(chuàng)建,從而生成一組新的編譯資源灶搜。一個編譯對象表現(xiàn)了當前的模塊資源祟蚀、編譯生成資源、變化的文件割卖、以及被跟蹤依賴的狀態(tài)信息前酿。編譯對象也提供了很多關(guān)鍵點回調(diào)供插件做自定義處理時選擇使用。

compiler 是 webpack 環(huán)境的代表究珊,compilation 則是 webpack 構(gòu)建內(nèi)容的代表薪者,它包含了每個構(gòu)建環(huán)節(jié)及輸出環(huán)節(jié)所對應的方法,存放著所有 module剿涮、chunk言津、asset 以及用來生成最后打包文件的 template 的信息攻人。

  • 事件鉤子

事件鉤子其實就是類似 MVVM 框架的生命周期函數(shù),在特定階段能做特殊的邏輯處理悬槽。了解一些常見的事件鉤子是寫 webpack 插件的前置條件


compiler事件鉤子
  • 插件模板
function MyPlugin(options) {}
  this.opt = options
  //1.函數(shù)原型上的 apply 方法會注入 compiler 對象
  MyPlugin.prototype.apply = function(compiler) {
  // 2.compiler 對象上掛載了相應的 webpack 事件鉤子 
  compiler.plugin('emit', (compilation, callback) => { // 3.事件鉤子的回調(diào)函數(shù)里能拿到編譯后的 compilation 對象
    ...
  })
}
module.exports = MyPlugin
  • Loader

1怀吻、loader 用于對模塊的源代碼進行轉(zhuǎn)換。loader 可以使你在 import 或"加載"模塊時預處理文件初婆。因此蓬坡,loader 類似于其他構(gòu)建工具中“任務(task)”,并提供了處理前端構(gòu)建步驟的強大方法磅叛。loader 可以將文件從不同的語言(如 TypeScript)轉(zhuǎn)換為 JavaScript屑咳,或?qū)?nèi)聯(lián)圖像轉(zhuǎn)換為 data URL。loader 甚至允許你直接在 JavaScript 模塊中 import CSS文件弊琴!

2兆龙、css-loader 解析 @import 和 url()路徑中指定的css內(nèi)容

3、style-loader 會把原來的 CSS 代碼插入頁面中的一個 style 標簽中

  • Loader 模版
// loaderUtils 可以獲取 webpack.config.js 中的配置
var loaderUtils = require('loader-utils');
 
module.exports = function(source) {
  console.log("start process code...");
  var options = loaderUtils.getOptions(this) || {};
  if(options !== {}) {
    var replaceMap = options["replaceMap"];
    for(var key in replaceMap) {
      console.log(source);
      source = source.replace(key, replaceMap[key]);
      console.log(source);
    }
  }
  return source;
};

2敲董、參考

簡單易懂的 webpack 打包后 JS 的運行過程
簡要分析webpack打包后代碼

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末紫皇,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子腋寨,更是在濱河造成了極大的恐慌聪铺,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件萄窜,死亡現(xiàn)場離奇詭異铃剔,居然都是意外死亡,警方通過查閱死者的電腦和手機脂倦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門番宁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人赖阻,你說我怎么就攤上這事□獯溃” “怎么了火欧?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長茎截。 經(jīng)常有香客問我苇侵,道長,這世上最難降的妖魔是什么企锌? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任榆浓,我火速辦了婚禮,結(jié)果婚禮上撕攒,老公的妹妹穿的比我還像新娘陡鹃。我一直安慰自己烘浦,他們只是感情好,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布萍鲸。 她就那樣靜靜地躺著闷叉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪脊阴。 梳的紋絲不亂的頭發(fā)上握侧,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音嘿期,去河邊找鬼品擎。 笑死,一個胖子當著我的面吹牛备徐,可吹牛的內(nèi)容都是我干的孽查。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼坦喘,長吁一口氣:“原來是場噩夢啊……” “哼盲再!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瓣铣,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤答朋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后棠笑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體梦碗,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年蓖救,在試婚紗的時候發(fā)現(xiàn)自己被綠了洪规。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡循捺,死狀恐怖斩例,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情从橘,我是刑警寧澤念赶,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站恰力,受9級特大地震影響叉谜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜踩萎,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一停局、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦董栽、人聲如沸码倦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽叹洲。三九已至,卻和暖如春工禾,著一層夾襖步出監(jiān)牢的瞬間运提,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工闻葵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留民泵,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓槽畔,卻偏偏與公主長得像栈妆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子厢钧,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

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