【前端工程化】工程化的发展历史

788 阅读5分钟

一、前端工程化解决的主要问题

JS全局作用域冲突

JS创建之初是为了快速开发网页脚本,但是未想现在发展壮大,随着项目变大,随处定义的全局变量很容易导致冲突,JS作者也承认,全局变量是JS设计的缺陷。

编码规范

首先,前端开发的前提是代码开发,而代码开发肯定离不开编码管理的规范,尤其是多人开发时,如何解决好规范问题,可以避免很多低级问题。

资源合并和压缩

当项目发布上线,受限于网络、浏览器并发请求数量的限制等,如何更高效地加载和运行依赖于资源体积的控制、加载次数的控制,这一部分需要对资源进行合并和压缩。

高版本JS降级

随着JS的升级,产生了许多新语法,但是存量浏览器不一定能很快速地进行支持,这要求我们对JS运行时进行兼容性处理,因此出现了不同的pollyfill方案。

二、工程化历史

image.png

前后端混合:1995-2005

此阶段前端页面的开发工作其实主要由后端处理,浏览器请求URL触发后端接口,后端直接渲染出HTML进行返回。

前后端分离:2005-2013

这个阶段将前端开发工作分离出来,前端可以通过AJAX进行异步网络请求,根据返回结果进行页面渲染,但该阶段存在很多开发体验的缺陷,最大的问题就是模块化开发体验差。

模块化开发:2013-2014

该阶段是对前一阶段的优化,利用webpack等打包工具将所有资源文件进行打包处理,能很好地支持模块化开发。

模块化+MVVM:2014至今

随着各种MVVM开发框架的诞生,前端开发工作从开发原生HTML、CSS、JS变化为开发Vue、React等框架的代码。通过打包工具进行转化,生成浏览器执行的原生代码。

三、模块化

模块化历史

  1. 全局function模式:其实就是简单地在JS脚本文件中定义全局函数,在HTML中引入使用,缺点是容易引发全局命名冲突。
  2. 全局namespace模式:将不同函数分类存储到不同的对象内,通过对象属性访问该方法;通过对象封装模块能一定程度解决命名冲突,但外部能够修改模块内部的数据。
  3. IIFE模式:通过自执行函数创建闭包,并导出执行结果;但无法解决模块间相互依赖问题。
(function (global) {
  function sum(a, b) {
    return a + b
  }
  function api() {
    return {
      a: 1,
      b: 2
    }
  }
  global.__Module = {
    api,
    sum,
  }
})(window)
  1. IIFE模式增强,支持传入自定义依赖(参考webpack打包结果);但多依赖传入时,代码阅读困难,无法支持大规模模块化开发,无特定语法支持,代码丑陋。
(function (global, moduleAPI) {
  function sum(a, b) {
    return a + b
  }
  global.__Module = {
    api: moduleAPI.api,
    sun,
  }
})(window, window.__Module_API)

模块化标准

CommonJS

  1. 代码运行在模块作用域,按照书写顺序同步加载执行
  2. 模块可以多次加载,第一次加载运行模块,模块内的代码会被执行,模块输出结果会被缓存,再次加载会从缓存获取
  3. 模块输出的是值的拷贝,类似IIFE方案中的内部变量,而非闭包引用的变量
  4. 原理:主模块中通过require加载模块时,会调用load方法,执行IIFE(require, module, exports, filename, dirname),将要加载的模块转为方法参数,这就是在模块中能使用require方法、__filename等变量的原因。同时执行完成后,会将执行结果存入Module Cache Map中,存储方式为 key(module path + module name): module.exports
  5. 在浏览器中使用可以使用browserify打包

ESModule

  1. ESM通过import、export导入、输出模块。
  2. 设计理念是希望在编译时就能确定模块关系和输入输出。

ESModule与CommonJS区别

  1. ESM输出的是值的引用,而CommonJS输出的是值的拷贝。
  2. CommonJS是单个值导出(module.exports),ESM可以导出多个。
  3. CommonJS是同步加载,ESM支持异步加载。
  4. CommonJS的this是当前模块module.exports,ESM中this为undefined。
  5. ESM编译时就能确定模块关系和输入输出,而CommonJS必须在运行时才能确定依赖和输入、输出。

AMD、CMD

  1. 非同步加载,允许指定回调函数
  2. 随着ESModule诞生,两者应用较少,因为没有通过语法升级解决模块化

模块化优缺点

  1. 更高开发效率,可读性强,复用性高。
  2. 浏览器中缺乏模块管理能力,模块分散在各个项目中。
  3. 加载性能慢,无法在大型项目中直接使用,需要npm和webpack的。

模块管理:npm

img

  1. 集中管理所有模块,所有模块上传到仓库,本地通过package.json管理模块基本信息。通过npm init初始化,npm link本地开发,npm publish/install进行发布/安装。
  2. 解决了模块的高效管理和获取问题,但无法解决加载性能问题。

模块打包:webpack

img

webpack诞生于2014年,最初是为了解决代码合并和拆分,核心理念是将所有资源视为模块,统一进行打包和处理。

将模块进行打包后,浏览器只需要请求少量个数的资源便可以进行执行,避免了HTTP1.x浏览器并发请求数量的限制。

同时,webpack通过loader和plugin进行功能扩展,在代码压缩、兼容降级等多方面均有很好的支撑。