专栏 文章详情
曾培森 232 关注作者
2 天前发布
node.JS webpack 构建工具
971 次阅读 . 读完需要 14 分钟
29
对于前端仔来说, 相信大家对 webpack 都再熟悉不过了, 但是你对 webpack 的了解程度又有多深呢, 笔者花了几天时间看了一下《深入浅出 webpack》, 虽然说书中大部分介绍的是配置和使用相关的, 但是如果你对 webpack 的配置, 使用, 原理和构建流程更加熟悉的话, 对于你的开发可以说是百里无一害! 本文不会局限于介绍配置, 也不会详细介绍打包原理 (后面打算写一篇有关 webpack 打包原理的~), 更多着重于 webpack 打包的思想介绍.
没有打包构建的日子
Node.JS 的出现对于构建工具具有重要的意义, 在没有 Node.JS 之前, JS 只能执行在浏览器环境下, 所以意味着对发布前的 JS 文件要进行处理, 十分局限, 没有打包工具, 只能用 PHP 脚本来处理文件, 甚至还需要借助一些在线压缩网站, 开发体验十分差劲, 在史前时代存在以下几个痛点:
1, 缺乏文件处理工具, 对文件进行编译或其他预处理, 进行打包压缩等工作;
2, 缺乏文件的模块化, 引入第三方库直接用 cdn 引入, 需要处理依赖管理, 人为控制脚本的加载顺序, 并且存在全局变量命名冲突的问题;
3, 缺乏代码校验和自动化测试, 在代码被提交到仓库前需要校验代码是否符合规范, 以及单元测试是否通过.
有了打包构建工具的日子
随着 Node.JS 的诞生, 我们可以在开发环境下书写 Node.JS 代码脚本, 对我们的前端代码做预处理, 编译压缩等工作, 最初诞生的是 grunt 和 gulp,Grunt 和 Gulp 都属于任务流工具 Tast Runner, 两者都是通过配置好配置文件, 但是相比之下, gulp 通过函数式编写配置文件, 以及前端人员所熟悉的链式调用, 让大家觉得更易懂更易上手, gulp 本身借鉴了 grunt 的经验进行升级和加入一些新特性. 正因为流管理多任务配置输出方式的提高, 人们逐渐选择使用 Gulp 而放弃 grunt.
有了 grunt 和 gulp, 文件压缩处理的工作解决了, 代码校验和测试也可以处理了, 但是模块化仍没有结果?
其实前端的痛点还远不止模块化那么简单, 频繁的 DOM 节点处理, JS 里杂糅了交互逻辑, 请求逻辑, 数据处理和校验逻辑, DOM 操作逻辑, 导致 JQ 书写的代码就更意大利炒大便, 呸! 意大利炒面一样. 在团队开发中, 可能你的代码要给别人维护, 这就非常痛苦了.
webpack 诞生记
1, 模块化思想
隔离不同的 JS 文件, 模块化开发, 仅暴露当前模块所需要的其他模块, 这是模块化思想想要传递给我们的. Node.JS 诞生后, 后端所采取的模块化思想是 commonjs, 然而, 不同于后端, 前端的代码运行在浏览器端, 有两点不同之处:
1, 没有 Node.JS 执行环境, 不支持 module.exports 的书写格式;
2, 后端 require 一个文件, 是读取本地文件的形式, 速度极快, 而对于前端而言, 需要去动态加载一个 JS 文件, 存在额外耗时.
于是 AMD 思想应运而生, 对此的相应实现是 RequireJS, 允许你定义好模块名称, 模块依赖以及当前的模块代码 (function), 通过广度优先遍历的方式, 递归加载父模块所依赖的子模块, 但是这也暴露出了一些问题:
1, 通过 JS 加载执行后再去加载其依赖的子模块, 这个递归加载过程本身是耗时的;
2, 模块化思想提倡我们分隔逻辑, 管理好各个 JS 文件内的逻辑, 一旦分割的 JS 文件过多, 最终造成前端资源加载压力.
不过不用担心, RequireJS 提供了 r.JS 来处理发布前的模块合成, 帮助你把多个 JS 文件打包成一个文件.
再到后来, 国内出现了 CMD 的思想, 不同于 AMD 的声明依赖的形式, 允许你动态加载依赖, 但是其实现以及具体的运行结果被大家诟病.
再到后后来, 为了解决这种不同库的模块实现不一致的问题, 提出了 UMD, 其实很简单, 只是写一段 hack, 让你的模块能够兼容不同的模块加载场景, 无论是 commonjs 还是 AMD, 如果都没有的话就直接声明为一个全局变量的形式.
下面引用一段 UMD 的代码:
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
- typeof define === 'function' && define.amd ? define(factory) :
- (global = global || self, global.vue = factory());
- }(this, function () {
- 'use strict';
- //your code here
- }
再到后后后来, 未来的大一统, es6 中所提出的 import 和 export 的形式来统一前后端的模块化加载方式. 相比以往的实现, import/export 的形式, 在模块化加载 JS 文件的时候, 保留动态的执行引用, 其次, 不允许动态控制加载依赖, 使得 tree-shaking 成为可能.
2, 组件化思想
组件化的思想并非前端所特有, 在客户端也会面临相同的问题. 想象一下, A 跟 B 被同时分配一起开发完成一个首页页面, 包括导航栏, 轮播图, 网站列表数据, 登录框等, 两人需要如何分工协作? 导航栏, 列表这种需要在多个页面复用的 html 怎么办? 假如在没有组件化处理的情况下:
1,A 和 B 分工困难麻烦, 代码提交时会处理大量的冲突;
2, 导航栏, 列表等多处复用的地方, 需要 cv 大法直接复制粘贴到另一个页面中去使用.
组件化思想, 让我们把页面划分为一个个组件, 组件内部维护自己的 UI 展示, 交互逻辑, 组件间可以进行数据通信, 实现一种变相的相互隔离, 便不会出现 A 和 B 两人一起编辑一段 HTML 的难受场景, 同时, 提高了代码的可维护性和复用性, 这是其解决的关键痛点.
引用 vue 官网的一张有关组件化思想的图:
3,MVC 框架, MVVM 框架的流行
在模块化和组件化的基础上, 实现了页面组件之间的隔离和各自维护, 但是面临的最大的一个痛点问题, 仍然是前面所说的, 前端的 JS 逻辑中杂糅了各种处理逻辑, 交互逻辑, 请求逻辑, 数据处理和校验逻辑, DOM 操作逻辑; 而其实这一切可以划分为两个层次, 一个是数据层, 一个是视图层, 如何避免重复的书写操作 DOM 的逻辑, 如果说早期的各种模板引擎给了我们初期的解决方案, 那么 vue,react 以及 angular 就是在模板引擎的基础上的上层建筑.
为了让我们更加专注于数据的处理, MVC 框架和 MVVM 框架帮我们做了以下两件事:
1, 监听页面操作事件, 触发相应的事件钩子, 执行代码逻辑, 即 V 层到 M 层的过程;
2, 执行代码逻辑后, 数据层发生修改, 帮我们更新渲染页面, 即 M 层到 V 层的过程; vue 中通过 vm 实现, react 中通过触发 setState 通知.
如此, 我们只需要书写一次 HTML, 在 HTML 中写明绑定或展示的数据, 同时绑定好事件监听器, 后续便不需要再处理视图层相关的操作, 只需要关注于自己的业务逻辑代码, 数据层的处理等.
MVVM 架构流程图:
4, 代码打包构建
前面介绍了 grunt,gulp 打包构建工具, 其实 webpack 本质也是打包构建工具, 但是 webpack 呈现出来的功能更为强大和成熟. 对于代码的预处理, 模块化加载, 代码分割等, webpack 具有更大的优势.
webpack 诞生!
读者读到这里, 可能仍有些许疑惑, 前面讲了这么多, 为啥还是没有介绍到 webpack 相关的, 其实不然, 仔细回想一下前面所介绍的思想, 以及你平时使用 webpack 来打包构建的时候, 其实 webpack 正是帮你处理了这些繁杂琐碎的事情.
如果代码预处理压缩足以, 那么 grunt 和 gulp 已经满足了;
如果说模块化开发足以, 那么 RequireJS 和 Browserify 已经满足了;
如果说组件化开发, MV * 框架足以, 那么只需要在页面内引入相应的 vue 或 react 框架, 足矣.
笔者写这边文章, 更多是想让大家能够思考工具或者框架背后, 所呈现出来的思想, webpack 就像是一个巨无霸, 集大成者, 它解决了打包构建, 它处理了模块化开发, 它帮助你和其他框架完美融合实现组件化开发; 而这几年来 MV * 框架的流行对于 webpack 市场的迅速扩展有着不小的贡献.
webpack 为我们做了以下这些事:(引自《深入浅出 webpack》)
代码转换: TypeScript 编译成 JavaScript,SCSS 编译成 CSS 等.
文件优化: 压缩 JavaScript,CSS,HTML 代码, 压缩合并图片等.
代码分割: 提取多个页面的公共代码, 提取首屏不需要执行部分的代码让其异步加载.
模块合并: 在采用模块化的项目里会有很多个模块和文件, 需要构建功能把模块分类合并成一个文件.
自动刷新: 监听本地源代码的变化, 自动重新构建, 刷新浏览器.
代码校验: 在代码被提交到仓库前需要校验代码是否符合规范, 以及单元测试是否通过.
其实以小见大, 你能窥见的不仅是 webpack 的思想, 更多的是前端的发展, 从最初的土法炼钢, 不规范, 到如今的模块化, 组件化, MV * 框架, 是前端思想的进步. 作为一个前端仔, 我们应该探索和研究的是如何磨刀, 磨好刀, 而不是砍柴而已.
谢谢观看~
来源: https://segmentfault.com/a/1190000020613537