如何使用webpack構建Ueditor

蘇格團隊發表於2019-02-28

由於種種原因,我們選擇了Ueditor作為我們的富文字編輯器選型。

Ueditor不支援模組化,所以無法在程式碼中使用import去引入。一開始我們在專案中是將Ueditor的js檔案直接通過script標籤引入,在React的程式碼裡直接使用window.UE去使用編輯器。但是這就有一個問題,我們對UE的原始碼進行了改動,加入了定製化的功能。而直接引入的UE檔案在瀏覽器是有快取的,我們每次改動都要清除快取才能生效。

我們要解決快取這個問題,webpack配置就必須滿足以下條件:

  1. 每次改動程式碼後,能自動給UE的檔名加hash
  2. 能自動插入html模板檔案並在主入口檔案載入之前載入完成

第一步

為了能讓UE的檔案進入打包流程,我們將它作為一個新的入口檔案

const entry = {
    main: [`babel-polyfill`, `./src/main.js`],
    ueditor_config: [`./src/common/UEditor/ueditor.config.js`],
    ueditor_all: [`./src/common/UEditor/ueditor.all.js`]
};

new HtmlWebpackPlugin({
    template: `./src/app/${key}/templates/${filename}`,
    filename: `../view/${targetHtml}`,
    hash: true,
    chunks: [ueditor_all, ueditor_config, main]
})
複製程式碼

按上面的配置構建完成之後,會發現效果並不是我們想要的

<script type="text/javascript" src="/public/main.xxxx.js"></script> 
<script type="text/javascript" src="/public/ueditor.config.xxxx.js"></script> 
<script type="text/javascript" src="/public/ueditor.all.xxxx.js"></script>
複製程式碼

main.js在UE的前面,這樣main中使用window.UE就會報錯。顯然,我們需要一種方式來讓這個順序符合我們的預期。

第二步

HtmlWebpackPlugin的chunksSortMode屬性是用來控制插入模板html的script標籤的順序的,預設是auto,會根據webpack給每個chunk生成的id去排序,在entry中排的越前的,id就越小,那在html中就排在前面。所以這裡我們第一種解決方案是,調換一下entry順序

const entry = {
	ueditor_config: [`./src/common/UEditor/ueditor.config.js`],
    ueditor_all: [`./src/common/UEditor/ueditor.all.js`]
    main: [`babel-polyfill`, `./src/main.js`]
};
複製程式碼

但是這個方法有缺陷,當專案中有多個模板html需要引用入口的時候,在entry裡面去控制這個排序就會遇到衝突的情況,不夠靈活。
所以我們把順序的控制權下方到每個HtmlWebpackPlugin中,通過把chunksSortMode設定為manual,按chunks的順序去排序,例如

new HtmlWebpackPlugin({
	...
    chunks: [ueditor_config, ueditor_all, main]
})
複製程式碼

這樣,生成的html中srcipt就會是下面的順序

<script type="text/javascript" src="/public/ueditor.config.xxxx.js"></script> 
<script type="text/javascript" src="/public/ueditor.all.xxxx.js"></script>
<script type="text/javascript" src="/public/main.xxxx.js"></script> 
複製程式碼

現在看上去順序是ok了,但是執行的時候,我們發現控制檯報錯
regeneratorRuntime is not defined

第三步

第二步最後出現的錯誤,是我們使用的ES6新API沒有被轉換導致的。由於之前我們只是在main的入口加了babel-polyfill,而main又是在UE的後面載入的,所以導致了報錯。所以需要將babel-polyfill放到入口第一個檔案

const entry = {
	ueditor_config: [`babel-polyfill`, `./src/common/UEditor/ueditor.config.js`],
    ueditor_all: [`./src/common/UEditor/ueditor.all.js`]
    main: [`./src/main.js`]
};
複製程式碼

繼續執行後,第二步的錯誤已經解決了。不過,新的錯誤又出現了

TypeError: `caller`, `callee`, and `arguments` 
properties may not be accessed on strict mode functions or the arguments objects for calls to them
複製程式碼

第四步

bable會預設給編譯的js加上use strict;
嚴格模式下callercalleearguments 是不能使用的,追溯到UE的原始碼中,我們發現裡面大量使用了arguments.callee這種寫法。
直接把原始碼都改了不現實,所以只能通過配置讓bable忽略這個檔案。在.babel中我們加入如下配置,

"presets": [
    "react"
 ],
 "ignore": [
     "./src/common/UEditor/ueditor.all.js"
 ],
複製程式碼

到此webpack就能按照我們的預期構建UE模組了。

相關文章