本文首發(fā)于Array_Huang的技術(shù)博客——
實用至上
,非經(jīng)作者同意,請勿轉(zhuǎn)載。
原文地址:https://segmentfault.com/a/1190000006887523
如果您對本系列文章感興趣,歡迎關(guān)注訂閱這里:https://segmentfault.com/blog/array_huang
前言
目前前端雖處于百花齊放階段,angular/react/vue競相角逐,但畢竟尚未完全成熟,有些需求還是得依靠我們的老大哥jQuery的。
我個人對jQuery并不反感,但我對jQuery生態(tài)的停滯不前相當(dāng)無奈,比如說赫赫有名的bootstrap(特指3代),在webpack上打包還得靠個loader的,太跟不上時勢了。況且,bootstrap還算好的,有些jquery插件都有一兩年沒更新了,連NPM都沒上架呢,可偏偏就是找不到它們的替代品,項目又急著要上,這可咋辦吶?
別急,今天就教你適配兼容老式j(luò)Query插件。
老式j(luò)Query插件為和不能直接用webpack打包?
如果你把jQuery看做是一個普通的js模塊來加載(要用到j(luò)Query的模塊統(tǒng)統(tǒng)先require后再使用),那么,當(dāng)你加載老式j(luò)Query插件時,往往會提示找不到j(luò)Query實例(有時候是提示找不到$
),這是為啥呢?
要解釋這個問題,就必須先稍微解釋一下jQuery插件的機(jī)制:jQuery插件是通過jQuery提供的jQuery.fn.extend(object)
和jQuery.extend(object)
這倆方法,來把插件本身實現(xiàn)的方法掛載到jQuery
(也即$
)這個對象上的。傳統(tǒng)引用jQuery及其插件的方式是先用<script>
加載jQuery本身,然后再用同樣的方法來加載其插件;jQuery會把jQuery
對象設(shè)置為全局變量(當(dāng)然也包括了$
),既然是全局變量,那么插件們很容易就能找到jQuery
對象并掛載自身的方法了。
而webpack作為一個遵從模塊化原則的構(gòu)建工具,自然是要把各模塊的上下文環(huán)境給分隔開以減少相互間的影響;而jQuery也早已適配了AMD/CMD等加載方式,換句話說,我們在require jQuery
的時候,實際上并不會把jQuery
對象設(shè)置為全局變量。說到這里,問題也很明顯了,jQuery插件們找不到jQuery
對象了,因為在它們各自的上下文環(huán)境里,既沒有局部變量jQuery
(因為沒有適配AMD/CMD,所以就沒有相應(yīng)的require語句了),也沒有全局變量jQuery
。
怎么來兼容老式j(luò)Query插件呢?
方法有不少,下面一個一個來看。
ProvidePlugin
+ expose-loader
首先來介紹我最為推薦的方法:ProvidePlugin
+ expose-loader
,在我公司的項目,以及我個人的腳手架開源項目webpack-seed
里使用的都是這一種方法。
ProvidePlugin的配置是這樣的:
var providePlugin = new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'window.$': 'jquery',
});
ProvidePlugin的機(jī)制是:當(dāng)webpack加載到某個js模塊里,出現(xiàn)了未定義且名稱符合(字符串完全匹配)配置中key的變量時,會自動require配置中value所指定的js模塊。
如上述例子,當(dāng)某個老式插件使用了jQuery.fn.extend(object)
,那么webpack就會自動引入jquery
(此處我是用NPM的版本,我也推薦使用NPM的版本)。
另外,使用ProvidePlugin還有個好處,就是,你自己寫的代碼里,再!也!不!用!require!jQuery!啦!畢竟少寫一句是一句嘛哈哈哈。
接下來介紹expose-loader,這個loader的作用是,將指定js模塊export的變量聲明為全局變量。下面來看下expose-loader的配置:
/*
很明顯這是一個loader的配置項,篇幅有限也只能截取相關(guān)部分了
看不明白的麻煩去看本系列的另一篇文章《webpack多頁應(yīng)用架構(gòu)系列(二):webpack配置常用部分有哪些?》:https://segmentfault.com/a/1190000006863968
*/
{
test: require.resolve('jquery'), // 此loader配置項的目標(biāo)是NPM中的jquery
loader: 'expose?$!expose?jQuery', // 先把jQuery對象聲明成為全局變量`jQuery`,再通過管道進(jìn)一步又聲明成為全局變量`$`
},
你或許會問,有了ProvidePlugin為嘛還需要expose-loader?問得好,如果你所有的jQuery插件都是用webpack來加載的話,的確用ProvidePlugin就足夠了;但理想是豐滿的,現(xiàn)實卻是骨感的,總有那么些需求是只能用<script>
來加載的。
externals
externals是webpack配置中的一項,用來將某個全局變量“偽裝”成某個js模塊的exports,如下面這個配置:
externals: {
'jquery': 'window.jQuery',
},
那么,當(dāng)某個js模塊顯式地調(diào)用var $ = require('jquery')
的時候,就會把window,jQuery
返回給它。
與上述ProvidePlugin + expose-loader
的方案相反,此方案是先用<script>
加載的jQuery滿足老式j(luò)Query插件的需要,再通過externals將其轉(zhuǎn)換成符合模塊化要求的exports。
我個人并不太看好這種做法,畢竟這就意味著jQuery脫離NPM的管理了,不過某些童鞋有其它的考慮,例如為了加快每次打包的時間而把jQuery這些比較大的第三方庫給分離出去(直接調(diào)用公共CDN的第三方庫?),也算是有一定的價值。
imports-loader
這個方案就相當(dāng)于手動版的ProvidePlugin,以前我用requireJS的時候也是用的類似的手段,所以我一開始從requireJS遷移到webpack的時候用的也是這種方法,后來知道有ProvidePlugin就馬上換了哈。
這里就不詳細(xì)說明了,放個例子大家看看就懂:
// ./webpack.config.js
module.exports = {
...
module: {
loaders: [
{
test: require.resolve("some-module"),
loader: "imports?$=jquery&jQuery=jquery", // 相當(dāng)于`var $ = require("jquery");var jQuery = require("jquery");`
}
]
}
};
總結(jié)
以上的方案其實都屬于shimming,并不特別針對jQuery,請舉一反三使用。另外,上述方案并不僅用于shimming,比如用上ProvidePlugin
來寫少幾個require,自己多多挖掘,很有樂趣的哈~~
示例代碼
諸位看本系列文章,搭配我在Github上的腳手架項目食用更佳哦(笑):Array-Huang/webpack-seed(https://github.com/Array-Huang/webpack-seed
)。
附系列文章目錄(同步更新)
- webpack多頁應(yīng)用架構(gòu)系列(一):一步一步解決架構(gòu)痛點
- webpack多頁應(yīng)用架構(gòu)系列(二):webpack配置常用部分有哪些?
- webpack多頁應(yīng)用架構(gòu)系列(三):怎么打包公共代碼才能避免重復(fù)?
- webpack多頁應(yīng)用架構(gòu)系列(四):老式j(luò)Query插件還不能丟,怎么兼容?
- webpack多頁應(yīng)用架構(gòu)系列(五):聽說webpack連less/css也能打包?
- webpack多頁應(yīng)用架構(gòu)系列(六):聽說webpack連圖片和字體也能打包?
- webpack多頁應(yīng)用架構(gòu)系列(七):開發(fā)環(huán)境、生產(chǎn)環(huán)境傻傻分不清楚?
- webpack多頁應(yīng)用架構(gòu)系列(八):教練我要寫ES6!webpack怎么整合Babel?
- webpack多頁應(yīng)用架構(gòu)系列(九):總有刁民想害朕!ESLint為你阻擊垃圾代碼
- webpack多頁應(yīng)用架構(gòu)系列(十):如何打造一個自定義的bootstrap
- webpack多頁應(yīng)用架構(gòu)系列(十一):預(yù)打包Dll,實現(xiàn)webpack音速編譯
- webpack多頁應(yīng)用架構(gòu)系列(十二):利用webpack生成HTML普通網(wǎng)頁&頁面模板
- webpack多頁應(yīng)用架構(gòu)系列(十三):構(gòu)建一個簡單的模板布局系統(tǒng)
- webpack多頁應(yīng)用架構(gòu)系列(十四):No復(fù)制粘貼!多項目共用基礎(chǔ)設(shè)施
- webpack多頁應(yīng)用架構(gòu)系列(十五):論前端如何在后端渲染開發(fā)模式下夾縫生存
本文首發(fā)于Array_Huang的技術(shù)博客——
實用至上
,非經(jīng)作者同意,請勿轉(zhuǎn)載。
原文地址:https://segmentfault.com/a/1190000006887523
如果您對本系列文章感興趣,歡迎關(guān)注訂閱這里:https://segmentfault.com/blog/array_huang