如果我們僅僅是實現一個專案,我們大概率不會關注到webpack output中的這兩個屬性。但是如果我們是實現一個元件庫,那麼這兩個屬性就變得至關重要了。本文從自己之前遇到的一個問題說起,繼而引申出library和libraryTarget屬性。
1. 故事起源
當我自己開始寫第一個元件庫的時候,很快我就擼好了框架的程式碼,然後我興致沖沖的把我的元件庫引入到我的專案中,我記得那時候我是這麼寫的:
元件庫:
import Feeds from `@/components/feeds/index`;
export {
Feeds,
};
主專案:
import Feeds from `@/tencent/newsH5Ad`;
// 一些其他程式碼
<Feeds data=`xxx`>
然後我就收穫了一個報錯,Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: null
。啊?難道是我的最終輸出程式碼有問題?我檢查了一下最終輸出的程式碼,沒有問題,Feed元件的程式碼也在裡面。這個問題我查了很久,都沒有答案,最後才發現是webpack打包的問題。這就涉及到了本文的主角,library和libraryTarget。
2.
2. library和libraryTarget
我們都知道,webpack可以將不同的模組化方式(commonjs, AMD, CMD, ES6 Module)的程式碼打包。那我們打出來的程式碼包其實也可以按不同的模組化方式生成,所以:
libraryTarget就是配置webpack打包內容的模組方式的引數
而library就是webpack打包內容的名字
所以library規定了元件庫返回值的名字,libraryTarget規定了返回值的編碼格式。
libraryTarget的配置選項可以分為四大類:
2.1 按不同的模組方式生成
也就是我們這個問題的解決方法,由於我寫的是一個React的UI元件庫,所以我們需要commonjs的模組方式。因此只需要在webpack.config.js中配置這一項即可:
module.exports = {
entry: `./src/index.js`,
output: {
filename: `index.js`,
// library: `MyLibrary`, // 模組名稱
libraryTarget: `commonjs2`, // 輸出格式
},
// 其他程式碼
}
事實上,你可以選擇的選項有:
commonjs/commonjs2: 將你的library暴露為CommonJS模組
amd: 將你的library暴露為amd模組
umd: 將你的library暴露為所有的模組定義下都可執行的方式
其中AMD和UMD需要指定library,如果不宣告元件庫則不能正常執行。這是為了在瀏覽器上通過script標籤載入時,用AMD模組方式輸出的元件庫可以有明確的模組名。如:
define("MyLibrary", [], function() {
return _entry_return_; // 此模組返回值,是入口 chunk 返回的值
});
注意:commonjs和commonjs2幾乎相同,只不過commonjs只包含exports,而commonjs2還包含module.exports,所以直接使用commonjs2即可。
2.2 生成為一個變數
libraryTarget的預設值是var,顧名思義,就是將元件庫入口起點的返回值生成一個變數。如:
var MyLibrary = _entry_return_;
也可以選擇‘assign`,那樣的話將預設生成和一個全域性的變數。不管是var還是assign,都需要設定library的名稱,否則就會報錯。
2.3 生成一個為一個物件的屬性
和第二種情況差不多,只不過會把這個變數賦值給某個物件,作為它的一個屬性存在。可以選擇的選項有:
this: 返回值成為this的一個屬性
window: 返回值成為window的一個屬性
global: 返回值成為global的一個屬性
例如:
this["MyLibrary"] = _entry_return_;
window["MyLibrary"] = _entry_return_;
global["MyLibrary"] = _entry_return_;
可以看到,這種情況下也必須指定library的名字。
2.4 非同步生成方式
在這種情況下,libraryTarget的值為‘jsonp’,元件庫入口起點的返回值,會被包裹到一個jsonp包裝容器中,並配合webpack的externals使用——元件庫的依賴由externals指定。如:
MyLibrary(_entry_return_);
3. 總結
本文介紹了webpack中libraray和libraryTarget的相關內容,解釋了為什麼不設定它們時使用webpack打包出來的元件庫會有問題。一般情況下,作為vue或者react元件庫,libraryTarget在commonjs2,amd,umd中三者擇其一即可。