对于webapck的初学者来讲,最受挫的就是引入jQuery
及jQuery插件
时,总是会遇到各种问题。在网上一搜,总能发现多种解决方案,什么externals
,providePlugin
,vendor
,export-loader
等等。我们搞不清楚,为什么会有那么多的引用方法,我只是想引用一个jQuery插件
而已。其实,webpack
引用jQuery
困难,是因为jQuery插件众多,有的插件提供了模块化支持,比如支持UMD
,有的则没有支持模块化,直接引用全局的jQuery
或window.jQuery
。下面,我们来分几中情况,来讨论一下webpack
引入jQuery
的几种方法和它们的区别,来方便大家在实际项目中取舍。
1.cdn引用jQuery
网上很多问,"怎样在webpack里全局引用jQuery
"。我对"全局引用"的理解,就是把jQuery
暴露到全局(浏览器是window
)。虽然把jQuery
暴露到全局是不推荐的,但是很多插件,尤其早期的插件,是依赖全局的jQuery
变量的。cdn引用jQuery
,大多是全局的引用。我们来看个例子
注:以下例子源码在github
上,可通过相应的链接打开,clone
下来后,可以直接运行webpack-dev-server
看效果,我的webpack
和webpack-dev-server
是全局安装,你的如果不是全局安装,运行前请自行安装)。
例子源代码,可以点击这里
jqGreen.js
//没有模块化
(function($){
$.fn.green = function(){
$(this).each(function(){
$(this).css('color','green');
})
}
})(jQuery);
index.js
require('./jqGreen');
$('#green').green();
index.html
<!DOCTYPE html>
<html>
<head>
<title>webpack引入jQuery(一)</title>
</head>
<body>
<div id="green">该段文字应该为绿色</div>
<script src='http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js'></script>
</body>
</html>
webpack.config.js
var htmlPlugin = require('html-webpack-plugin');
module.exports = {
entry:{
index:'./src/index.js'
},
output:{
path:'builds',
filename:'[name].js',
chunkFilename:'chunk.[name].js'
},
plugins:[
new htmlPlugin({
filename:__dirname+'/builds/index.html',
template:'./index.html'
})
],
devServer:{
contentBase:'./builds',
inline:true
}
}
jqGreen.js
是一个简单的插件,功能是把选中的元素的color
属性设置为green
。我们在index.js
引用了这个插件。需要重点说明的是,jqGreen
这个插件,没有采用任何模块化的方案,很多早期的jQuery插件都是这种写法。上面的例子,没有用externals
,但是也能正常跑起来。关键就是这个插件jqGreen
没有任何模块化方案。
我们运行webpack
命令,编译后的文件输出到builds
文件下,再运行webpack-dev-server
,程序是可以直接跑起来的。我例子里的代码是编译过的,大家clone
下来后,可以直接在命令行运行webpack-dev-server
把demo跑起来,然后打开http://localhost:8080
查看效果。
结论:如果jquery插件没有采用任何模块化方案,直接引用cdn上的jQuery,然后正常引用插件并打包就可以正常使用。
那么,如果我的jQuery插件,有模块化方案呢?
我们来改一下上面的jqGreen.js
//UMD模块方案
(function(window,factory){
if(typeof exports === 'object'){
module.exports = factory(require('jquery'));
}else if(typeof define === 'function' && define.amd){
define(['jquery'],factory);
}else{
factor();
}
})(window,function($){
$.fn.green = function(){
$(this).each(function(){
$(this).css('color','green');
});
}
});
注意,这个时候,我们的jQuery插件采用了UMD
模块化的方案。大家可以直接把jqGreen
改成上面的这种UMD
形式但不修改webpack.config.js
文件。在example1
运行webpack
命令,会报错,会提示找不到jquery
。我们查看builds
文件夹下面的index.js
文件时候,会发现if(typeof exports === 'object')
被webpack替换成了if(true)
,就是说,webpack编译后的代码,会执行module.exports = factory(require('jquery'));
这段代码。注意这里面的require('jquery')
,我们并没有在本地安装jquery
(没有npm install jquery --save-dev
),而是引用的cdn上的jquery
,所以,require('jquery')
是找不到'jquery'的,因为他不知道我们是引用cdn上的jquery
。那么,怎么才能让webpack不报错,能争取引用呢?答案是externals
。
externals引用'jquery'
我们只需要在webpack.config.js
文件里添加
externals:{
'jquery':'window.jQuery'
}
大家可以看我的例子源码,例子是可以直接跑起来的。
上面的externals
配置,告诉webpack,在编译时,看到require('jquery'),就把它替换成window.jQuery
。这样,就实现了引用全局上的jQuery
,我们的例子,也能正常跑起来啦。
这里多说一下,对于刚才我们的第一个例子,就是没有采用任何模块化方案的例子,用externals
配置也是可以的,那样externals
什么也不会做,但是程序也能跑起来。
总之,如果要全局引用jQuery
,不管你的jQuery有没有支持模块化,用externals
就对了。
.IgnorePlugin引用jQuery
IgnorePlugin的示例代码IgnorePlugin
和cnd
引用jQuery
,都是引用的未处理的jquery
源码文件。cdn
上的jquery
是没法打包(除非下载下来),而本地的jquery
webpack默认会对其打包,所以要用IgnorePlugin
来告诉webpack不要打包。所以这种引用方式,也需要用externals
来暴露全局变量,大家通过上面贴出来的链接,看看示例代码就ok。
注意,我们上面的例子,都是不对jquery
打包的,所以页面上的jquery.js
都是一个单独的文件。webpack当然也能把jquery
打包在内,那样就会用到CommonChunks
、vendor
等等,下次再聊那种情况。