本文首發於 Array_Huang的技術博客——實用至上
,非經做者贊成,請勿轉載。
原文地址:https://segmentfault.com/a/1190000006887523
若是您對本系列文章感興趣,歡迎關注訂閱這裏:https://segmentfault.com/blog/array_huang
目前前端雖處於百花齊放階段,angular/react/vue競相角逐,但畢竟還沒有徹底成熟,有些需求仍是得依靠咱們的老大哥jQuery的。javascript
我我的對jQuery並不反感,但我對jQuery生態的停滯不前至關無奈,好比說赫赫有名的bootstrap(特指3代),在webpack上打包還得靠個loader的,太跟不上時勢了。何況,bootstrap還算好的,有些jquery插件都有一兩年沒更新了,連NPM都沒上架呢,可恰恰就是找不到它們的替代品,項目又急着要上,這可咋辦吶?css
別急,今天就教你適配兼容老式jQuery插件。前端
若是你把jQuery看作是一個普通的js模塊來加載(要用到jQuery的模塊通通先require後再使用),那麼,當你加載老式jQuery插件時,每每會提示找不到jQuery實例(有時候是提示找不到$
),這是爲啥呢?vue
要解釋這個問題,就必須先稍微解釋一下jQuery插件的機制:jQuery插件是經過jQuery提供的jQuery.fn.extend(object)
和jQuery.extend(object)
這倆方法,來把插件自己實現的方法掛載到jQuery
(也即$
)這個對象上的。傳統引用jQuery及其插件的方式是先用<script>
加載jQuery自己,而後再用一樣的方法來加載其插件;jQuery會把jQuery
對象設置爲全局變量(固然也包括了$
),既然是全局變量,那麼插件們很容易就能找到jQuery
對象並掛載自身的方法了。java
而webpack做爲一個聽從模塊化原則的構建工具,天然是要把各模塊的上下文環境給分隔開以減小相互間的影響;而jQuery也早已適配了AMD/CMD等加載方式,換句話說,咱們在require jQuery
的時候,實際上並不會把jQuery
對象設置爲全局變量。說到這裏,問題也很明顯了,jQuery插件們找不到jQuery
對象了,由於在它們各自的上下文環境裏,既沒有局部變量jQuery
(由於沒有適配AMD/CMD,因此就沒有相應的require語句了),也沒有全局變量jQuery
。react
方法有很多,下面一個一個來看。jquery
ProvidePlugin
+ expose-loader
首先來介紹我最爲推薦的方法:ProvidePlugin
+ expose-loader
,在我公司的項目,以及我我的的腳手架開源項目webpack-seed
裏使用的都是這一種方法。webpack
ProvidePlugin的配置是這樣的:git
var providePlugin = new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery', 'window.jQuery': 'jquery', 'window.$': 'jquery', });
ProvidePlugin的機制是:當webpack加載到某個js模塊裏,出現了未定義且名稱符合(字符串徹底匹配)配置中key的變量時,會自動require配置中value所指定的js模塊。github
如上述例子,當某個老式插件使用了jQuery.fn.extend(object)
,那麼webpack就會自動引入jquery
(此處我是用NPM的版本,我也推薦使用NPM的版本)。
另外,使用ProvidePlugin還有個好處,就是,你本身寫的代碼裏,再!也!不!用!require!jQuery!啦!畢竟少寫一句是一句嘛哈哈哈。
接下來介紹expose-loader,這個loader的做用是,將指定js模塊export的變量聲明爲全局變量。下面來看下expose-loader的配置:
/* 很明顯這是一個loader的配置項,篇幅有限也只能截取相關部分了 看不明白的麻煩去看本系列的另外一篇文章《webpack多頁應用架構系列(二):webpack配置經常使用部分有哪些?》:https://segmentfault.com/a/1190000006863968 */ { test: require.resolve('jquery'), // 此loader配置項的目標是NPM中的jquery loader: 'expose?$!expose?jQuery', // 先把jQuery對象聲明成爲全局變量`jQuery`,再經過管道進一步又聲明成爲全局變量`$` },
你或許會問,有了ProvidePlugin爲嘛還須要expose-loader?問得好,若是你全部的jQuery插件都是用webpack來加載的話,的確用ProvidePlugin就足夠了;但理想是豐滿的,現實倒是骨感的,總有那麼些需求是隻能用<script>
來加載的。
externals是webpack配置中的一項,用來將某個全局變量「假裝」成某個js模塊的exports,以下面這個配置:
externals: { 'jquery': 'window.jQuery', },
那麼,當某個js模塊顯式地調用var $ = require('jquery')
的時候,就會把window,jQuery
返回給它。
與上述ProvidePlugin + expose-loader
的方案相反,此方案是先用<script>
加載的jQuery知足老式jQuery插件的須要,再經過externals將其轉換成符合模塊化要求的exports。
我我的並不太看好這種作法,畢竟這就意味着jQuery脫離NPM的管理了,不過某些童鞋有其它的考慮,例如爲了加快每次打包的時間而把jQuery這些比較大的第三方庫給分離出去(直接調用公共CDN的第三方庫?),也算是有必定的價值。
這個方案就至關於手動版的ProvidePlugin,之前我用requireJS的時候也是用的相似的手段,因此我一開始從requireJS遷移到webpack的時候用的也是這種方法,後來知道有ProvidePlugin就立刻換了哈。
這裏就不詳細說明了,放個例子你們看看就懂:
// ./webpack.config.js module.exports = { ... module: { loaders: [ { test: require.resolve("some-module"), loader: "imports?$=jquery&jQuery=jquery", // 至關於`var $ = require("jquery");var jQuery = require("jquery");` } ] } };
以上的方案其實都屬於shimming,並不特別針對jQuery,請觸類旁通使用。另外,上述方案並不只用於shimming,好比用上ProvidePlugin
來寫少幾個require,本身多多挖掘,頗有樂趣的哈~~
有童鞋私信我,說用了我文章的方案依然提示$ is not a function
,在我仔細分析後,發現:
ProvidePlugin
+ expose-loader
方案,也就是說,他已經把jquery打包進來了。externals: { jquery: 'window.jQuery', },
<script>
來引用jQuery,所以window.jQuery是個null。$
就是個null了。這裏面咱們能夠看出,externals是會覆蓋掉ProvidePlugin
的。
但這裏有個問題,expose-loader
的做用就是設置好window.jQuery和window.$,那window.jQuery怎麼會是null呢?個人猜測是:externals在expose-loader
設置好window.jQuery
前就已經取了window.jQuery
的值(null
)了。
說了這麼多,其實關鍵意思就是,不要手賤不要手賤不要手賤(重要的事情說三遍)!
諸位看本系列文章,搭配我在Github上的腳手架項目食用更佳哦(笑):Array-Huang/webpack-seed(https://github.com/Array-Huang/webpack-seed
)。
https://segmentfault.com/a/1190000006843916
https://segmentfault.com/a/1190000006863968
https://segmentfault.com/a/1190000006871991
https://segmentfault.com/a/1190000006887523
https://segmentfault.com/a/1190000006897458
https://segmentfault.com/a/1190000006907701
https://segmentfault.com/a/1190000006952432
https://segmentfault.com/a/1190000006992218
https://segmentfault.com/a/1190000007030775
https://segmentfault.com/a/1190000007043716
https://segmentfault.com/a/1190000007104372
https://segmentfault.com/a/1190000007126268
https://segmentfault.com/a/1190000007159115
本文首發於 Array_Huang的技術博客——實用至上
,非經做者贊成,請勿轉載。
原文地址:https://segmentfault.com/a/1190000006887523
若是您對本系列文章感興趣,歡迎關注訂閱這裏:https://segmentfault.com/blog/array_huang