本文首发于
Array_Huang的手艺博客——
有用至上
,非经作者赞同,请勿转载。原文地点:
https://segmentfault.com/a/1190000006887523
假如您对本系列文章感兴趣,迎接关注定阅这里:
https://segmentfault.com/blog/array_huang
媒介
现在前端虽处于百花齐放阶段,angular/react/vue竞相比赛,但毕竟还没有完整成熟,有些需求照样得依托我们的老大哥jQuery的。
我个人对jQuery并不恶感,但我对jQuery生态的裹足不前相称无法,比方说大名鼎鼎的bootstrap(特指3代),在webpack上打包还得靠个loader的,太跟不上时事了。何况,bootstrap还算好的,有些jquery插件都有一两年没更新了,连NPM都没上架呢,可偏偏就是找不到它们的替代品,项目又急着要上,这可咋办呐?
别急,本日就教你适配兼容老式jQuery插件。
老式jQuery插件为和不能直接用webpack打包?
假如你把jQuery看作是一个一般的js模块来加载(要用到jQuery的模块一切先require后再运用),那末,当你加载老式jQuery插件时,往往会提醒找不到jQuery实例(有时刻是提醒找不到$
),这是为啥呢?
要诠释这个题目,就必须先轻微诠释一下jQuery插件的机制:jQuery插件是经由过程jQuery供应的jQuery.fn.extend(object)
和jQuery.extend(object)
这俩要领,来把插件本身完成的要领挂载到jQuery
(也即$
)这个对象上的。传统援用jQuery及其插件的体式格局是先用<script>
加载jQuery本身,然后再用一样的要领来加载其插件;jQuery会把jQuery
对象设置为全局变量(固然也包含了$
),既然是全局变量,那末插件们很轻易就能够找到jQuery
对象并挂载本身的要领了。
而webpack作为一个顺从模块化准绳的构建东西,自然是要把各模块的上下文环境给星散隔以削减相互间的影响;而jQuery也早已适配了AMD/CMD等加载体式格局,换句话说,我们在require jQuery
的时刻,实际上并不会把jQuery
对象设置为全局变量。说到这里,题目也很明显了,jQuery插件们找不到jQuery
对象了,由于在它们各自的上下文环境里,既没有局部变量jQuery
(由于没有适配AMD/CMD,所以就没有响应的require语句了),也没有全局变量jQuery
。
怎样来兼容老式jQuery插件呢?
要领有不少,下面一个一个来看。
ProvidePlugin
+ expose-loader
首先来引见我最为引荐的要领:ProvidePlugin
+ expose-loader
,在我公司的项目,以及我个人的脚手架开源项目webpack-seed
里运用的都是这一种要领。
ProvidePlugin的设置是如许的:
var providePlugin = new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'window.$': 'jquery',
});
ProvidePlugin的机制是:当webpack加载到某个js模块里,涌现了未定义且称号相符(字符串完整婚配)设置中key的变量时,会自动require设置中value所指定的js模块。
如上述例子,当某个老式插件运用了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
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的第三方库?),也算是有肯定的代价。
imports-loader
这个计划就相称于手动版的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,本身多多发掘,很有兴趣的哈~~
补充
误用externals(2016-10-17更新)
有童鞋私信我,说用了我文章的计划依旧提醒$ is not a function
,在我仔细分析后,发明:
- 他用的是我引荐的
ProvidePlugin
+expose-loader
计划,也就是说,他已把jquery打包进来了。 - 然则他又不明就里得配了externals:
externals: {
jquery: 'window.jQuery',
},
- 但是实际上他并没有直接用
<script>
来援用jQuery,因而window.jQuery是个null。 - 效果,他的jquery插件取得的
$
就是个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
)。
附系列文章目次(同步更新)
- webpack多页运用架构系列(一):一步一步处理架构痛点:
https://segmentfault.com/a/1190000006843916
- webpack多页运用架构系列(二):webpack设置经常使用部份有哪些?:
https://segmentfault.com/a/1190000006863968
- webpack多页运用架构系列(三):怎样打包大众代码才防止反复?:
https://segmentfault.com/a/1190000006871991
- webpack多页运用架构系列(四):老式jQuery插件还不能丢,怎样兼容?:
https://segmentfault.com/a/1190000006887523
- webpack多页运用架构系列(五):据说webpack连less/css也能打包?:
https://segmentfault.com/a/1190000006897458
- webpack多页运用架构系列(六):据说webpack连图片和字体也能打包?:
https://segmentfault.com/a/1190000006907701
- webpack多页运用架构系列(七):开辟环境、临盆环境傻傻分不清楚?:
https://segmentfault.com/a/1190000006952432
- webpack多页运用架构系列(八):锻练我要写ES6!webpack怎样整合Babel?:
https://segmentfault.com/a/1190000006992218
- webpack多页运用架构系列(九):总有刁民想害朕!ESLint为你阻击渣滓代码:
https://segmentfault.com/a/1190000007030775
- webpack多页运用架构系列(十):怎样打造一个自定义的bootstrap:
https://segmentfault.com/a/1190000007043716
- webpack多页运用架构系列(十一):预打包Dll,完成webpack音速编译:
https://segmentfault.com/a/1190000007104372
- webpack多页运用架构系列(十二):应用webpack天生HTML一般网页&页面模板:
https://segmentfault.com/a/1190000007126268
- webpack多页运用架构系列(十三):构建一个简朴的模板规划体系:
https://segmentfault.com/a/1190000007159115
- webpack多页运用架构系列(十四):No复制粘贴!多项目共用基础设施
- webpack多页运用架构系列(十五):论前端怎样在后端衬着开辟形式下夹缝生计
- webpack多页运用架构系列(十六):善用浏览器缓存,该去则去,该留则留
本文首发于
Array_Huang的手艺博客——
有用至上
,非经作者赞同,请勿转载。原文地点:
https://segmentfault.com/a/1190000006887523
假如您对本系列文章感兴趣,迎接关注定阅这里:
https://segmentfault.com/blog/array_huang