爲什麼自己寫的組件庫被引用總是報錯——詳解webpack的library和libraryTarget

如果我們僅僅是實現一個項目,我們大概率不會關注到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中三者擇其一即可。

參考文獻

  1. webpack文檔
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章