likes
comments
collection
share

从Webpack入手看前端工程化,一切终于清晰了

作者站长头像
站长
· 阅读数 13

前端工程化

工程化是一种思想而不是某种技术,那啥是工程化的思想?

以前,你要写一个项目,需要每次都从新建一个html、css、js文件开始,先手动引入jq或是Bootstrap等js库,再把一些通用css样式、通用工具函数如处理时间等复制粘贴过来,为方便调试,再写一个本地服务器,此时终于项目框架搭好了,可以开始写你的业务代码,写代码的过程中你发现这次需求里要实现一个轮播功能,而公司以往做过的需求里已经写过了同样的轮播,你不想再撸一遍代码,遂你又把代码小心翼翼地粘贴复制了过来,结果你发现效果并不与你的预期完全吻合,那怎么办?改!终于,业务代码写完了,你得开始压缩代码、图片、字体等资源,把你用各种软件啊还是工具处理完的文件打包放到一个文件夹里,然后上传到服务器。当需求要迭代时,你修改完代码之后又要重复以上步骤。

所以,大家是不是已经发现痛点了:

  • 人工做的重复工作太多,耗时费力,如压缩打包上传等
  • 代码可维护性差,将可复用的代码到处复制,不能保证代码的一致性,想要更新的时候得挨个改
  • 要时刻考虑上古难题,浏览器兼容性,如css要加前缀、js新特性不敢用等
  • 当项目业务线较多时,技术方案不统一,技术复用率低,最佳实践无法方便的共享
  • 开发人员风格不一,团队协作规范全靠口头约定,协作效率低下,代码维护困难

痛点远远不止这些,有痛点就会有解决方案,那工程化就应运而生了。

前端工程化要解决什么问题?怎么解决?

所谓工程化即系统化、模块化、规范化的一个过程。一般来说,前端工程化包含模块化、组件化、规范化、自动化四个方面。要解决的问题是如何提高编码、测试、维护阶段的生产效率

一. 模块化

定义:模块化就是将一个大文件拆分成相互依赖的小文件,按一个个模块来划分,再进行统一的管理。

作用:

  • 避免变量污染、命名冲突
  • 代码职责分离、降低耦合
  • 代码复用,避免重复造轮子
  • 提高生产效率,降低维护难度

举例:

  • JS 模块化:使用CommonJS、ES6 Module等组织代码
  • CSS 模块化:使用less、sass等预处理器组织代码
  • 资源模块化:npm包等

二. 组件化

模块化是在文件层面上,对代码或资源的拆分,而组件化是在设计层面上,对用户界面的拆分,组件化实现了对一套相关的视图和逻辑的复用,大大降低重复代码,提高开发效率。

应用组件化思想的框架如Vue、微信小程序等。

三. 规范化

目标:制定各项规范,使工作有章可循,便于团队协作和代码维护,提高应用质量

  1. 统一编码规范,目录创建和文件命名规范

    • 包含目录结构规范
    • 文件命名规范
    • 代码规范
    • 前后端接口规范等

例如我工作过一个团队在项目中期要建立一套全局埋点系统,要求每个js/ts文件的开头都要有一行文件功能说明,以用来被埋点系统捕捉分析,团队立即加入了新的代码规范,在提交代码时会进行检查,没有该说明的文件提交不上去,这在工程化出现之前几乎是不可能只花10分钟配置就可以一劳永逸的。

  1. 开发流程规范

    • 使用版本控制工具,高效安全的管理源代码

      如主干开发,主干发布原则,本地分支提交后质量通过可合入主干,代码提交要小而频(方便代码review)的同时也要保证主干代码随时可发布,基于此,往往要求开发人员要对新合入的功能加好开关。

    • file owner(文件负责人)和code review(代码复审):给每个文件或木模块添加负责人,CI质量检测通过后还需由负责人review 代码才可合入

  2. 文档规范

四. 自动化

目标:提高效率,解放人力,开发人员更加专注应用质量

  • 使用构建打包工具、脚手架工具、mock工具等

  • CI(持续集成)过程中自动进行质量检测、代码风险统计、质量评估

    CI(持续集成):频繁地将新增的代码能够与原先代码正确的集成,即合入主干

    质量检测内容包含代码复杂度、写法等

  • CDE(持续交付)过程中自动进行代码功能测试,将测试结果反馈开发者

  • CD(持续部署)过程自动部署代码到生产环境

    大多数的项目在CI完成后都会进行人工干预,由人工进行测试验证并部署上线。

工程化思想可以大致理解为:工厂给你提供场地,工具器械,以及帮你包装上线销售,你只需要用合适的工具以及你自己的技术生产商品就行了,但是要依照规范保证生产线井然有序做到高效且高质。

webpack 是自动化层面的一个优秀实践

Webpack 是一个用于现代JavaScript应用程序的静态模块打包工具,静态模块指的是开发阶段可以被 Webpack 直接引用的资源,当 webpack 处理应用程序时,它会递归地构建一个依赖图(dependency graph),这个依赖图包含着应用程序中所需的每个模块,然后将所有模块分组打包成一个或多个 bundles,它们均为静态资源,可由浏览器加载。

如图: 从Webpack入手看前端工程化,一切终于清晰了

module、chunk、bunlde

  • module: 项目源码中所有资源(包括 JS、CSS、Image、Font 等等)都属于 module 模块。webpack中一切皆模块,可以配置指定的 Loader 去处理这些文件。

  • chunk: 该术语用于webpack处理模块依赖的过程中,有三种方式会生成不同的chunk,entry、动态加载模块、splitChunks代码分割,一个chunk会生成一个或多个bunlde。

    可以理解为chunk是将模块分块、分组

  • bundle: 最终生成的文件,可由浏览器加载

    通常情况下,一个chunk对应一个bunlde,但是有些配置不会产生一对一的关系,例如MiniCssExtractPlugin可从chunk中抽离出css文件,单独生成bundle。或者 devtool配置成’source-map’,这样就会生成一个单独的扩展名为.map的bundle,用于查看源码。

module,chunk 和 bundle 其实就是同一份逻辑代码在不同转换场景下的不同叫法: 我们直接写出来的是 module,webpack 处理时是 chunk,最后生成浏览器可以直接运行的 bundle。

Webpack构建过程

webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:

  1. 初始化阶段:从配置文件和 Shell 语句中读取与合并参数,用得到的参数初始化 Compiler 实例,加载所有配置的插件,执行实例的 run 方法开始编译
  2. 编译构建阶段:从 Entry 发出,针对每个模块串行调用对应的 Loader 去翻译文件内容,再找到该 Module 依赖的 Module,递归地进行编译处理
  3. 输出阶段:所有模块都编译完成后,把编译后的 Module 组合成 Chunk(三种方式会生成不同的chunk,entry、动态加载模块、splitChunks代码分割),把 Chunk 转换成文件加入到输出列表,这步是可以修改输出内容的最后机会,在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

Webpack Plugin

插件可以扩展 Webpack 的功能,在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果, 如打包优化、代码压缩插件等。

Webpack Loader

Loader 是webpack中提供了一种处理多种文件格式的机制,因为webpack只认识JS和JSON,所以Loader相当于翻译官,将其他类型资源进行预处理,如css、图片、字体等,最终处理为js代码。

  • babel-loader 将es新特性转换为es5语法
  • css-loader 将css文件转换为js代码,并且把css文件中的url路径转换为require路径

Webpack对前端工程化的贡献

不止Plugin和Loader,webpack提供了丰富的能力尽可能地将你的应用开发过程自动化,让你可以更加专注需求本身。

  • 编译代码能力,可以使用ts,es新特性,css预处理器等,提高效率,解决浏览器兼容问题
  • 模块整合能力,提高性能,合并压缩文件,减少浏览器请求,提高加载速度
  • ...

总结

前端工程化就是处理代码的一系列工具链,他们并不关心代码的内容,只是把代码作为字符串来进行一系列处理。编译构建、CI/CD、代码托管、静态分析、格式化等都是。

到这里,我们捋了一遍前端工程化的概念,前端工程化解决了哪些痛点,带来了哪些好处,以及工程化理念的一个非常棒的实践Webpack(前端工程化的一部分-自动化)。

前端工程化看似已经成熟,但是其实还有很多可以开拓和探索的地方,永远没有什么技术是主流,在如此内卷的时代中,前端技术可以说是卷上加卷了,我们甚至可以大胆地预测,未来会全面拥抱 rust / golang 工程链和工具(因为性能是真的好),到时候前端开发只会JS恐怕都不行了。说回来,“卷”点也没啥不好的,我们也是能切身体验到技术带来的变化的,希望自己也可以为前端工程化做出一点微小的贡献,哈哈。