webpack原理与实践(一)为什么选用webpack

1,890 阅读8分钟

写在前面

在写Node入门系列的时候,我在文中就预告过,会再出一个webpack系列,因为webpack的打包构建离不开Node.js的支持,二者紧密联系,如果仅仅只学webpack,一定会碰到Node.js的相关知识。截止本文发稿,Node.js系列已经写到第五篇,我已经为你准备好了所有的文章链接放到下文,如果还没看过Node.js的文章,建议先看Node.js系列,该系列语言通俗易懂,大家反馈的结果是即使初学者也能看懂,同时还拓展了你平时想不到的知识面。也可通过我的主页查阅感兴趣的文章:

请点击这里跳转需要阅读的章节:

漫谈Node.js入门
Node.js入门系列(一)特点、适用场景、解决的前端痛点问题
Node.js入门系列(二)模块、REPL
Node.js入门系列(三)开发调试、全局内置函数和变量 【写给初入前端职场同学的话】,顺便聊聊:Node.js入门系列(四)事件处理机制及事件环机制

顺便预告,之所以在这个时候推出webpack系列,是因为,马上,我将推出Node.js第六篇,讲述npm相关知识,如何管理拆分后模块也是本篇要讨论的内容,因此,此时发布webpack系列是最符合适宜的。

引言

前端经过几年爆炸式的发展,目前已经不仅仅是要求会进行简单的切图配合后端完成开发就可以的了,也正是因为这样,前端开发工程师才能脱掉“切图仔”的帽子,在开发领域担当着跟后端同样重要的角色。而在前端发展过程中,出现了以下几个现象:

1)前端项目大型化,功能复杂,维护、迭代成本高。

2)团队协作低效率,合作开发时互相影响,耦合性高,甚至造成代码冲突。

3)团队内部人员流动造成新人对旧项目维护十分痛苦;团队内开发人员能力和开发习惯各不相同造成代码质量不一,维护困难。

而这一切问题,都可以通过一个叫模块化的概念来解决。

模块化本身只是一个概念,它不提供任何针对性的解决方案,而关于这个概念,目前有很多优秀的实现,包括,rollup,parcel,webpack等。

而要隆重介绍的,就是webpack。

webpack 是什么?它能做什么?跟其他模块化工具比他为什么优秀?它的缺点是什么?这些疑问,将在这节细细讲解。

1.webpack是什么?

webpack是前端模块化开发的一种具体的实现方案,通过其内部的loader机制和插件机制对项目进行构建打包,最终达到代码模块化的目的。

2.什么是模块化?它的发展历程是怎么的?

模块化是指:将一个完整的功能,单独拆分成若干个独立的功能块,这些块通过组合,最终实现整体功能的思想,称为模块化。

第一阶段:文件拆分式:早期的模块化 指的是将各个独立的功能通过拆分不同文件的方式,独立的放在不同的文件中,再通过script标签引入到页面中,一个script标签就代表一个模块。
它的缺点是:

1)这种模块是工作在全局的,很容易造成全局成员命名冲突;
2)没有一个私有的工作空间,暴露出来的对象很容易被修改;
3)无法管理模块与模块之间的关系。

第二阶段:命名空间式:在文件拆分式的基础上,规定每一个模块只能暴露除一个对象,并且,要将暴露出来的对象挂载到全局的window对象上,它解决了命名冲突的问题,但是其他问题依然存在。

第三阶段:IIFE,立即执行函数:将每一个模块的成员都放在一个立即执行函数中,这样,立即执行函数就为模块提供了私有空间,对于需要暴露给全局的成员,可以通过挂载到全局对象的方式去实现,并且呢,这种方式可以通过参数的形式标明模块内部依赖的模块,这种方式解决了全局作用域污染、作用域冲突和模块依赖关系的问题。这种方法的典型应用就是JQuery源码的封装,感兴趣的同学可以试着阅读JQuery源码。

综上,上面的三种方式,虽然最终解决了模块组织管理的问题,但是却没有解决模块加载的问题,这样会造成,模块冗余或者模块缺失,所有的模块都是通过script标签全局引入的,并没有以模块加载机制来进行管理,并且,上述三种方式,没有一个统一的规范,具体实现因人而异,因此,想要实现模块自动按需加载的库,和保持一致的开发风格,还需建立一种统一的模块规范。

3.模块规范有哪些?

1)commonJS:他是Node.js的模块规范,该规范约定一个文件就是一个模块,每一个模块有单独的作用域,模块通过module.exports导出成员,再通过require函数引入成员。

这种模块方案如果放在浏览器中使用,会出现一些问题,原因在于:node.js中,模块是在启动时进行同步加载的,在运行时只是进行相应的调用,浏览器端如果使用这种方式,会出现在初始时出现大量的模块请求,降低执行效率,造成加载等待时间太长的问题。

因此,早期的前端模块规范并没有直接选择commonJS作为前端模块规范,而是使用一种叫做:异步模块定义规范的方案,简称AMD。

2)requireJS是AMD模块规范的实现方案之一,requireJS除了本身实现了AMD规范以外,它本身还是一个强大的模块加载器。

AMD 规范规定,通过define函数来定义一个模块,该函数接收两个参数,第一个参数是一个数组,表示该模块需要依赖的其他模块的路径,第二个参数是一个函数,相当于立即执行函数,它的作用是提供给模块一个私有的作用域,在函数内部,如果想要暴露除一个全局的对象,只需要通过return的方式return出去就可以了。

3)在require.js实现AMD规范的同时,淘宝推出了前端模块化的另一种方式,称为CMD,它的实现方式是sea.js,它的使用方法基本和require.js类似,可以算是一个重复的轮子,但是CMD只在国内流行,后来,CMD也被require.js兼容了。

4)随着前端的发展,规范越来越完善,目前,前端推行的推荐方案是在node.js中使用require.js模块规范,在浏览器端使用ESModules规范,并且呢,node.js也发声将会在以后逐渐兼容ESModules规范,因此,对于前端来说,ESModules依然是最重要的AMD实现方案,应该重点掌握。ESModules是ES2015(ES6)才定义的模块系统,由于像webpack等一系列打包工具的流行,才逐渐流行开来,目前,它已经是主流的前端模块化标准。

小结

前端的模块化标准经历了三个阶段:AMD --> CMD --> ESModules

4.模块化会带来什么问题?

1)无法保证所有浏览器都兼容模块化标准;
2)依赖的模块太多、划分太细会导致一次会发送多个请求向服务端请求模块资源造成效率低下;
3)前端不仅仅JS需要模块化,其他的CSS、HTML、图片资源等也需要模块化。

那么如何解决既能使用模块化,又能达到对所有资源都进行模块化的问题呢?

为解决上述问题,催生出了模块化打包工具。

模块化打包工具需要能解决以下问题:

1)具备代码编译能力:能够将开发阶段使用新特性编写的代码转化成大多数浏览器都兼容的代码,从而解决浏览器环境兼容问题;

2)需要他能将散落的模块再次打包到一起,从而解决多次请求模块资源问题(因为模块化实际上只需要我们在开发阶段进行项目结构管理,在线上实际上并没有太大的作用);

3)需要他能将不同类型的文件都进行模块化打包,包括图片、css、字体等。

如果仅仅需要解决1)和2)的问题,完全可以使用gulp构建系统再配合相应编译插件就可以完成了。但是针对于第三点,其他工具很难解决,因此催生了一款强大的打包工具---webpack。

小结

好了,到目前为止,你已经知道了:
1)为什么要前端模块化?
2)前端模块化的发展历程?
3)模块化工具为什么选择webpack?

在接下来的几篇文章中,我将穿插更新Node.js系列和webpack系列,目的在于将服务端和前端对比结合学习,敬请期待。

文末

本文是webpack系列的第一篇,后续会陆续更新。

好文章,需要你的支持,所以,请先点个赞,然后再有序退场,评论区前排沙发欢迎交流。

前端格局,带你看有深度的前端世界,搭建属于自己的知识架构,关注我,跑的更快一点。