webpack系列(二)webpack原理,loader、plugin原理
Published by Shangyu Liu,
webpack的最本质作用是赋予js代码模块化的能力,模块化的本质就是把不同功能的代码放置到不同的文件中以明确代码逻辑。因此webpack的原理就是指的webpack如何打包模块化组织的代码变成非模块化的文件。
一、webpack原理
1、整体逻辑:
webpack打包出来的文件中是一个自执行函数,函数参数是一系列匿名函数体组成的数组。这些函数就来自于各个模块,因此webpack的原理很简单,把分散在各个文件中的函数集中到一个文件而已。函数体中定义了一个__webpack_require__的函数,参数是moduleId,并调用了这个函数,给moduleId = 0,也就是调用第一个实参,实参列表的每个函数的形参中都有__webpack_require__这个函数,在源代码中使用require(或者import)时就是在此代码中调用__webpack_require__之时。除了__webpack_require__,自执行函数体还定义了installedModules一个对象,其实是当成数组用。
2、__webpack_require__:
__webpack_require__接受的参数是id,指向实参数组的第id个函数。__webpack_require__在执行时首先去installedModules的数组中找一下,找到了直接返回模块,没找到则创建一个module对象,通过apply的方式调用把module.exports传到__webpack_require__中,去函数(模块)中取出要export的量。
3、实参列表:
每一个对应的是一个模块,第0个对应的是main。每个函数的参数是module,exports,__webpack_require__,当函数执行时,将module进行赋值。并调用__webpack_require__。
理解loader与plugin要知道webpack提供了compiler这样一个全局变量。
二、loader原理
loader的作用不是进行模块化,而是针对单个文件进行编译,比如es6编译为es5。要牢记loader是处理单文件的。本质上loader是一个函数,被exports出来,形参是webpack的compiler传递给loader的文件原文(source)。比如处理scss文件,首先sass-loader将scss转化为css,转交给css-loader,也就是css-loader的source这个形参对应的实参,css-loader会找出这个css依赖的资源,压缩后生成最终css交给style-loader,style-loader将css转化为能够操作dom样式的js文件,等待webpack打包。loader可以使用webpack提供的多种api,比如可以获取loader的options,loader的options不像plugin那样从参数传入,而需要webpack的api获取。在使用方面,loader不像plugin直接给对象实例,而是只给loader名,webpack自己实例化loader,更像是依赖注入。
三、plugin原理
注意webpack的配置文件是一个js文件而不是json文件,原因就是方便配置plugin,plugins是一个数组对象,数组元素是一些plugin的实例,也就是new出来的,因此是js可执行代码,而要实例化就要require class,因此webpack的配置文件是通过js来export某些量。
loader是针对单文件的翻译器,plugin则灵活的多。它的本质也是一个函数(或class,取决于语言是ts/es6还是es5),参数是options,在webpack配置js中new这个类时传入options,从这里就可以看出loader与plugin的不同,前者要原文故要处理的就是原文。plugin会提供apply函数,供webpack使用,这个apply接受webpack传入的compiler对象,此外还有compilation对象,这两者时webpack与plugin的桥梁,前者包含所有webpack的配置信息,webpack启动时实例化,全局单例。webpack是一条复杂的流水线,为此webpack提供了时间机制,每当有事件发生时就会广播,plugin可以监听自己感兴趣的事件作出反应。有一些常用的webpack插件,比如提取公共模块、将css单独拎出来而不是变为js打包等,逐渐学习这些plugin以更好的使用webpack