You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// 命名函数
function MyExampleWebpackPlugin() {
};
// 在它的 prototype 上定义一个 `apply` 方法。
MyExampleWebpackPlugin.prototype.apply = function(compiler) {
// 指定挂载的webpack事件钩子。
compiler.plugin('webpacksEventHook', function(compilation /* 处理webpack内部实例的特定数据。*/, callback) {
console.log("This is an example plugin!!!");
// 功能完成后调用webpack提供的回调。
callback();
});
};
这是官网提供的插件编写例子,先撇开公共的代码部分我们看以下核心代码:
// 指定挂载的webpack事件钩子。
compiler.plugin('webpacksEventHook', function(compilation /* 处理webpack内部实例的特定数据。*/) {
console.log("This is an example plugin!!!");
});
注:本文查看的源码是webpack1.x版本,2.x版本已经不存在这个问题,查看描述。
webpack1.x时代讨论地比较热烈的一个话题,就是
UglifyJsPlugin
插件为什么会对其他loader造成影响。我这里有个曾经遇到的问题,可以查看我为此编写的一个demo,有兴趣可以clone试验一下这个问题。由
postcss-loader、autoprefixer
处理后的css如下,在开发环境一切ok:可是用线上环境
UglifyJsPlugin
进行打包后,最后的css被剔除了很多-webkit-前缀:这样的最终css在ios8以下版本是不兼容的,解决办法我也写在了demo中,大家可以试验一下。
通过给css-loader添加
-autoprefixer
参数来告诉css-loader,虽然你被某股不知名的力量强制进行压缩了,但是在压缩的时候关闭掉autoprefixer
这个功能,不要强制删除某些你觉得不重要的前缀。文章最前面的webpack issue也提到了,这股不知名的力量其实就是
UglifyJsPlugin
插件。我们先来看一下这个插件的一段核心源码。这块代码先不用理解什么意思,但是minimize字段很明确地告诉大家,某个上下文
context
的minimize字段被设置成true了。至于这个上下文context
是哪个上下文,下文会解释道。对webpack运行原理不清楚的同学肯定会跟我有一样的疑惑,webpack中的插件(plugin),加载器(loader)到底是怎样的运行机制?插件在什么情况下会影响到loader的工作?以及插件除了影响到loader,还能影响什么?能否影响最后的打包输出?
加载器(loader)的作用很明显,负责处理各种类型的模块,比如
png /vue/jsx/css/less
等等各种后缀类型,用相应的loader就能识别并进行转换。转换好的文件内容才能被webpack运行时读懂。插件(plugin),官网的解释非常简单
比方说,css-loader识别并转换完对应的css模块,babel-loader识别并转换完对应的js,他们的工作就结束了,现在我想把css内容从js里抽离出来变成单独一个css文件,这个工作就只能交给插件来做了。
而插件又是如何识别
.css
模块成功被css-loader
转换这个关键事件节点的?这是官网提供的插件编写例子,先撇开公共的代码部分我们看以下核心代码:
我们看到
webpacksEventHook
webpack事件钩子,用plugin
方法注册到了compiler对象上,compiler是webpack非常核心的对象,稍后会介绍。这里的
webpacksEventHook
事件钩子的种类可以看webpack官网webpack开放了非常丰富的事件钩子,供开发者们在插件中进行注册。而这些注册完的事件由webpack的compiler对象在对应的节点进行调用。
插件何时以及如何作用于webpack的构建过程,注册事件钩子由compiler(以及下文提到的compilation)进行统一分配调用就是答案。
再看一个相对较复杂的插件编写方式:
抽离核心代码:
compiler
对象注册方法的回调返回了一个compilation
对象,这个对象也能进行事件注册,但两者的事件钩子是有区别的。具体的事件钩子查看。compilation
对象和compiler
对象构成了webpack最核心的两个对象,几乎所有的构建编译逻辑都由这两个对象完成。我们看下两个对象在编写插件的时候可以进行事件钩子注册的几个重要事件。
以上列出的只是部分比较关键的节点,这些节点事件都能在插件中进行注册。注册完后只需等待webpack运行时在对应的节点进行调用,就能完成插件想做的事情。
那么
compiler
和compilation
是如何完成编译构建的?其实看了事件钩子罗列大概就对webpack的构建流程有点眉目了,我们顺着事件钩子来大致理一理webpack的工作方式。至此就粗略地完成了整个webpack的编译构建过程。
现在再回头看
UglifyJsPlugin
插件。其在插件中对js的压缩注册了optimize-chunk-assets
事件,查阅文档可知这个事件模块封装成chunk触发,所以在最后的阶段对js进行压缩是最好的选择。还有一个事件就是开头提到的
normal-module-loader
这个事件在模块开始构建并载入了loader时触发,这段代码的意思就是当模块载入对应的loader时,直接将loader的上下文环境中的minimize字段设置成true,而这个字段在css-loader
和postcss-loader
中设置成true会开启优化模式,所以会对代码进行压缩。而webpack2.x在迁移方案中官方明确说明去掉了
UglifyJsPlugin
强制开启其他loader优化模式的说明,在webpack2.x源码中UglifyJsPlugin
插件已经没有注册normal-module-loader
了。引用:
The text was updated successfully, but these errors were encountered: