首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Web 开发中的利器 - Webpack(1)

Web 开发中的利器 - Webpack(1)

简介伴随着互联网的出现,网站的表现形式也变得越来越丰富多彩。页面不仅要求内容的充实,表现形式的丰富,而且越来越关注用户的感官与体验。加上智能手机的推广与普及,在短短的10年时间,前端开发就涌现出了                HTML5、 CSS3、 ES6 等众多的技术方案。同时前端的开发也从简单的类库调用,转而关注和强调框架的运用,出现了一批像                AngularJs,ExtJs 这样的 MVC 框架。
但无论是使用类库还是框架,都需要页面加载相对应的 JavaScript 或 CSS                代码,甚至大量的第三方库。如何来管理和组织这些代码和资源,并保证它们在浏览器端可以快速、灵活的加载与更新呢?这就是目前 Web                端所倡导的模块系统所要面对和解决的问题。
本文先从 Web 应用中的模块系统出发,了解目前已经存在的模块系统以及它们的使用方法,从而进一步的理解 Webpack 的出现的历史背景。
模块系统的分类模块系统,需要解决的就是如何定义模块,以及如何处理模块间的依赖关系。我们来看看目前已经存在的模块系统,是如何处理这些问题的。
<script>标签清单 1.                使用<script>标签
1
2
3
4
<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="libraryA.js"></script>
<script src="module3.js"></script>




在 Web 开发的初期,这是最常见的 JavaScript                文件加载方式。但这种方式带来的问题,就是每一个文件中声明的变量都会出现在全局作用域内,也就是在 window                对象中。而且模块间的依赖关系完全由文件的加载顺序所决定,显然这样的模块组织方式会出现很多的弊端
  • 全局作用域下容易造成变量冲突
  • 文件只能按照 <script> 的书写顺序进行加载
  • 开发人员需要自己解决模块/代码库的依赖关系
  • 在大型项目中这样的加载方式,导致文件冗长而难以管理
CommonJS在 CommonJS 规范中,模块使用 require 方法,同步加载所依赖的其他模块。并通过设置 exports 对象(或                module.exports 对象)属性的方式,对外部提供所支持的接口。
清单 2.                使用CommonJS
1
2
3
4
require("module");
require("../file.js");
exports.doStuff = function() {};
module.exports = someValue;




优点:
  • 可重用服务器端模块
  • 在 中,有大量的模块使用 CommonJS 规范来书写
  • 简单并且容易使用
缺点:
  • 同步的加载方式,不适合在浏览器环境,浏览器的资源往往是异步加载的
  • 不能非阻塞的并行加载多个模块
实现:
AMD(Asynchronous Module Definition)在 AMD 规范中,模块通过 define (id, dependencies, function)                方法来定义,同时需要指定模块的依赖关系,而这些依赖的模块会被当做形参传到 function 方法中。而应用通过使用 require                方法来调用所定义的模块。
清单 3.                使用AMD
1
2
3
4
5
6
7
define("module", ["dep1", "dep2"], function(d1, d2) {
     return someExportedValue;
});

require(["module", "../file"], function(module, file) {
/* ... */
});




优点:
  • 适合在浏览器环境中异步加载模块
  • 可以并行加载多个模块
缺点:
  • 增加开发成本,不利于代码的阅读与书写
  • 不符合通用的模块化思维方式,是一种妥协的实现
实现:
ES6 模块ECMAScript2015 (第六版标准) 增加了很多 JavaScript 语言层面的模块体系定义。 的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。(CommonJS 和 AMD                模块,都只能在运行时确定这些东西)
清单 4. 使用ES6                模块
1
2
3
import "jquery";
export function doStuff() {}
module "localModule" {}




优点:
  • 容易进行静态分析
  • 面向未来的 ECMAScript 标准
缺点:
  • 原生浏览器端还没有实现该标准
  • 目前支持的模块较少
实现:
期望的模块系统每一种模块系统都有它的优点和缺点,总结下来,我们期望的模块系统是
  • 兼容多种模块系统风格。
  • 模块可以按需加载,从而不影响页面的初始化速度。
  • 支持多种资源文件,不仅仅只是 JavaScript 模块化,还有 CSS、图片、字体等。
  • 支持静态分析,以及第三方类库。
  • 合理的测试解决方案。
按需加载
前端模块要在客户端中执行,所以他们需要增量加载到浏览器中。
模块的加载和传输,我们首先能想到两种极端的方式,一种是每个模块文件都单独请求,另一种是把所有模块打包成一个文件然后只请求一次。显而易见,每个模块都发起单独的请求造成了请求次数过多,导致应用启动速度慢;一次请求加载所有模块导致流量浪费、初始化过程慢。这两种方式都不是好的解决方案,它们过于简单粗暴。
分块传输,按需进行懒加载,在实际用到某些模块的时候再增量更新,才是较为合理的模块加载方案。要实现模块的按需加载,就需要一个对整个代码库中的模块进行静态分析、编译打包的过程。
支持多种资源文件
在上面的分析过程中,我们提到的模块仅仅是指 JavaScript 模块文件。然而,在前端开发过程中还涉及到样式、图片、字体、HTML                模板等等众多的资源。这些资源还会以各种方言的形式存在,比如 CoffeeScript、Less、                Sass、众多的模板库、多语言系统(i18n)等等。如果他们都可以视作模块,并且都可以通过require的方式来加载,将带来优雅的开发体验,比如:
清单 5.                加载多种资源文件
1
2
3
4
require("./style.css");
require("./style.less");
require("./template.jade");
require("./image.png");




静态分析
在编译的时候,要对整个代码进行静态分析,分析出各个模块的类型和它们依赖关系,然后将不同类型的模块提交给适配的加载器来处理。比如一个用 LESS                写的样式模块,可以先用 LESS 加载器将它转成一个 CSS 模块,在通过 CSS 模块把他插入到页面的 <style>                标签中执行。
Webpack 就是在这样的需求中应运而生了
返回列表