webpack解惑:require的五種用法 (轉)

我以前在 《前端搭環境之從入門到放棄》這篇文章中吐槽過,webpack中能夠寫commonjs格式的require同步語法,能夠寫AMD格式的require回調語法,還有一個require.ensure,以及webpack本身定義的require.include,再加上ES6的import語法,這麼多豈不是會把人給搞亂。本篇就來梳理一下這些require各自的特色,以及都在什麼場景下使用。css

commonjs同步語法

經典的commonjs同步語法以下:html

var a = require('./a');
a.show();

此時webpack會將a.js打包進引用它的文件中。這是最廣泛的情形,沒必要贅述。前端

commonjs異步加載

在commonjs中有一個Modules/Async/A規範,裏面定義了require.ensure語法。webpack實現了它,做用是能夠在打包的時候進行代碼分片,並異步加載分片後的代碼。用法以下:webpack

require.ensure([], function(require){
    var list = require('./list');
    list.show();
});

此時list.js會被打包成一個單獨的chunk文件,大概長這樣:web

1.fb874860b35831bc96a8.js

可讀性比較差。我在上一篇結尾也提到了,給它命名的方式,那就是給require.ensure傳遞第三個參數,如:gulp

require.ensure([], function(require){
    var list = require('./list');
    list.show();
}, 'list');

  這樣就能獲得你想要的文件名稱:數組

list.fb874860b35831bc96a8.js

  

你也能夠傳入像"question/list"這樣帶層級的名字,這樣webpack會按照層級給你建立文件夾。瀏覽器

須要注意的是,若是你在require.ensure的函數中引用了兩個以上的模塊,webpack會把它們打包在一塊兒,好比:babel

require.ensure([], function(require){
    var list = require('./list');
    list.show();
    var edit = require('./edit');
    edit.display();
}, 'list_and_edit');

  

list.js和edit.js將會被打包成一個文件,並命名爲list_and_edit.js。這就須要根據你的實際狀況來衡量了,若是你不但願打包在一塊兒,只能寫兩個require.ensure分別引用這兩個文件。異步

多說一句,這種思惟其實我是很不喜歡的,在編碼階段卻要對打包的事情作出決策,明顯違背了職責分離原則。

 

commonjs預加載懶執行

在上面的用法中,咱們給require.ensure的第一個參數傳了空數組,實際上這裏是能夠接收模塊名稱的,做用就是實現預加載懶執行。用法以下:

require.ensure(['./list'], function(require){
    var list = require('./list');
    list.show();
});

  

給require.ensure的第一個參數傳了['./list'],執行到這裏的時候list.js會被瀏覽器下載下來,可是並不會執行list.js模塊中的代碼,也就是webpack官網說的,不會進行evaluate。真正進行evaluate的時候是到了後面這句var list = require('./list');這就是所謂的懶執行。

寫在函數中的多個模塊會被打包在一塊兒,這一點和上面沒有區別。另外,寫在數組中的模塊也會跟他們打包在一塊兒,無論你有沒有手動執行。

這種寫法也是有點彆扭的,像是commonjs和AMD的結合體,並且一個模塊名稱還要寫兩次,真是不夠優雅。因此webpack本身定義了一個方法,可以實現預加載。

 

webpack自帶的require.include

require.include是webpack本身提供的,並無什麼規範作後臺,因此是個小角色。它能夠實現上面是預加載功能,而不用把模塊寫在數組中,用法以下:

require.ensure([], function(require){
    require.include('./list');//此處只加載不執行
});

據webpack官網文檔介紹,require.include還有一個做用是能把子模塊中的公共部分,提取到父模塊中,好比child1和child2都引用了list.js這個模塊,那麼若是在parent中include了list.js,那麼子模塊中的就會被刪掉,至關於提高到了父模塊中。(這裏所謂的父子關係是指引用關係)

這個方法官方也是一筆帶過,看來也是一個雞肋的東西,用處不大。由於我發現require.include的返回值是undefined,也就是說,若是你想使用模塊,姿式是這樣的:

 

require.ensure([], function(require){
    require.include('./preview'); //加載
    let p = require('./preview'); //執行
    p.getUrl(); //使用
}, 'pre');

  

AMD異步加載

webpack既支持commonjs規範也支持AMD規範,這就意味着AMD的經典語法是能夠正常使用的,如:

require(['./list'], function(list){
    list.show();
});

固然,這樣寫的話list.js也是被單獨打包成一個文件的。與上面相似,若是你在這裏寫了多個模塊,那麼這些模塊都會被打包成一個文件,如:

require(['./list', './edit'], function(list, edit){
    list.show();
    edit.display();
});

list.js和edit.js會被打包在一塊兒。不一樣的是,AMD的方式沒法傳入第三個參數當文件名,因此得不到很好看的文件。

 

ES6 import

這年頭不用ES6都很差意思跟人打招呼。因此咱們的代碼中,又會多一種模塊引入語法,那就是import。import會被轉化爲commonjs格式或者是AMD格式,因此不要把它認爲是一種新的模塊引用方式。babel默認會把ES6的模塊轉化爲commonjs規範的,你也不用費勁再把它轉成AMD了。

因此以下寫法是等價的:

import list from './list';
//等價於
var list = require('./list');

不過這兩種寫法只需選一種,避免在代碼中同時使用兩種,不然會形成混淆。

 

總結

以上把require的用法捋了一遍,明白了各自用法的區別以後,咱們就能夠在項目中進行選擇了。我以爲最佳選擇是往commonjs方向靠攏,想嘗試ES6的話就用import代替commonjs同步語法便可。

所以,代碼中保持如下兩種風格就好:

//可打包在一塊兒的同步代碼,使用import語法
import list from './list';

//須要獨立打包、異步加載的代碼,使用require.ensure
require.ensure([], function(require){
    var list = require('./list');
});

  很顯然,你在寫代碼的時候仍是須要對打包結果進行決策,這是我不喜歡webpack的緣由。gulp那樣多好,編碼就是編碼,編譯就是編譯,分開來。不過這就是webpack以模塊爲核心的打包方式的特色吧,仁者見仁,只要團隊內作一個約定,也不會打的一塌糊塗。

轉自:http://www.cnblogs.com/lvdabao/p/5953884.html

相關文章
相關標籤/搜索