本文首发于 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