美文网首页
模块系统

模块系统

作者: mo_unique | 来源:发表于2017-06-25 10:32 被阅读0次

    前端产品的交付是基于浏览器,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统。

    模块系统主要解决模块的定义、依赖和导出

    模块化方式 简介 优点 缺点
    <script>标签 简单 1、全局作用域下容易造成变量冲突
    2、文件只能按照 <script> 的书写顺序进行加载
    3、开发人员必须主观解决模块和代码库的依赖关系
    4、在大型项目中各种资源难以管理,长期积累的问题导致代码库混乱不堪
    CommonJS 服务器端的 Node.js 遵循CommonJS规范,该规范的核心思想是允许模块通过 require方法来同步加载所要依赖的其他模块,然后通过 exports或 module.exports来导出需要暴露的接口。 1、服务器端模块便于重用
    2、NPM中已经有将近20万个可以使用模块包
    3、简单并容易使用
    1、同步的模块加载方式不适合在浏览器环境中,同步意味着阻塞加载,浏览器资源是异步加载的
    2、不能非阻塞地并行加载多个模块
    AMD 只有一个主要接口 define(id?, dependencies?, factory),它要在声明模块的时候指定所有的依赖 dependencies,并且还要当做形参传到 factory 中,对于依赖的模块提前执行,依赖前置。 1、适合在浏览器环境中异步加载模块
    2、可以并行加载多个模块
    1、提高了开发成本,代码的阅读和书写比较困难,模块定义方式的语义不顺畅
    2、不符合通用的模块化思维方式,是一种妥协的实现
    CMD 和 AMD 很相似,并与 CommonJS 和 Node.js 的 Modules 规范保持了很大的兼容性。
    define(function(require, exports, module) {}
    1、依赖就近,延迟执行
    2、可以很容易在 Node.js 中运行
    1、依赖 SPM 打包,模块的加载逻辑偏重
    ES6模块 尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。 1、容易进行静态分析

    前端模块加载

    前端模块要在客户端中执行,所以他们需要增量加载到浏览器中。

    模块的加载和传输,我们首先能想到两种极端的方式:

    • 一种是每个模块文件都单独请求
    • 另一种是把所有模块打包成一个文件然后只请求一次。

    显而易见,每个模块都发起单独的请求造成了请求次数过多,导致应用启动速度慢;一次请求加载所有模块导致流量浪费、初始化过程慢。这两种方式都不是好的解决方案,它们过于简单粗暴。

    分块传输,按需进行懒加载,在实际用到某些模块的时候再增量更新,才是较为合理的模块加载方案。

    要实现模块的按需加载,就需要一个对整个代码库中的模块进行静态分析、编译打包的过程。

    所有资源都是模块

    模块不仅仅指JavaScript模块文件,在前端开发过程中还涉及到样式、图片、字体、HTML 模板等等众多的资源。如果他们都可以视作模块,并且都可以通过require的方式来加载,将带来优雅的开发体验。

    那么如何做到让 require 能加载各种资源呢?

    静态分析

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

    同时,为了能利用已经存在的各种框架、库和已经写好的文件,我们还需要一个模块加载的兼容策略,来避免重写所有的模块。

    Webpack

    Webpack 是一个模块打包器。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源

    webpack的特点

    代码拆分

    Webpack 有两种组织模块依赖的方式,同步和异步。异步依赖作为分割点,形成一个新的块。在优化了依赖树后,每一个异步区块都作为一个文件被打包。

    Loader

    Webpack 本身只能处理原生的 JavaScript 模块,但是 loader 转换器可以将各种类型的资源转换成 JavaScript 模块。这样,任何资源都可以成为 Webpack 可以处理的模块。

    智能解析

    Webpack 有一个智能解析器,几乎可以处理任何第三方库,无论它们的模块形式是 CommonJS、 AMD 还是普通的 JS 文件。甚至在加载依赖的时候,允许使用动态表达式 require("./templates/" + name + ".jade")。

    插件系统

    Webpack 还有一个功能丰富的插件系统。大多数内容功能都是基于这个插件系统运行的,还可以开发和使用开源的 Webpack 插件,来满足各式各样的需求。

    快速运行

    Webpack 使用异步 I/O 和多级缓存提高运行效率,这使得 Webpack 能够以令人难以置信的速度快速增量编译

    执行过程

    Webpack 会分析入口文件,解析包含依赖关系的各个文件。这些文件(模块)都打包到 bundle.js 。Webpack 会给每个模块分配一个唯一的 id 并通过这个 id 索引和访问模块。在页面启动时,会先执行 entry.js 中的代码,其它模块会在运行 require 的时候再执行。

    Loader

    Webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件,就需要使用 loader 进行转换。

    Loader 可以理解为是模块和资源的转换器,它本身是一个函数,接受源文件作为参数,返回转换的结果。这样,我们就可以通过 require 来加载任何类型的模块或文件。

    先来看看 loader 有哪些特性?

    • Loader 可以通过管道方式链式调用,每个 loader 可以把资源转换成任意格式并传递给下一个 loader ,但是最后一个 loader 必须返回 JavaScript。
    • Loader 可以同步或异步执行。
    • Loader 运行在 node.js 环境中,所以可以做任何可能的事情。
    • Loader 可以接受参数,以此来传递配置项给 loader。
    • Loader 可以通过文件扩展名(或正则表达式)绑定给不同类型的文件。
    • Loader 可以通过 npm 发布和安装。
    • 除了通过 package.json 的 main 指定,通常的模块也可以导出一个 loader 来使用。
    • Loader 可以访问配置。
    • 插件可以让 loader 拥有更多特性。
    • Loader 可以分发出附加的任意文件。

    Loader 可以在 require() 引用模块的时候添加,也可以在 webpack 全局配置中进行绑定,还可以通过命令行的方式使用。

    • require()引用时:require("!style-loader!css-loader!./style.css")
    • 全局配置:webpack.config.js
    • 命令行方式:webpack entry.js bundle.js --module-bind 'css=style-loader!css-loader'

    插件

    插件可以完成更多 loader 不能完成的功能。
    插件的使用一般是在 webpack 的配置信息 plugins 选项中指定。
    Webpack 本身内置了一些常用的插件,还可以通过 npm 安装第三方插件。

    开发环境

    当项目逐渐变大,webpack 的编译时间会变长,可以通过参数让编译的输出内容带有进度和颜色。

    webpack --progress --colors

    如果不想每次修改模块后都重新编译,那么可以启动监听模式。开启监听模式后,没有变化的模块会在编译后缓存到内存中,而不会每次都被重新编译,所以监听模式的整体速度是很快的。

    webpack --progress --colors --watch

    当然,使用 webpack-dev-server开发服务是一个更好的选择。它将在localhost:8080 启动一个 express 静态资源 web 服务器,并且会以监听模式自动运行 webpack,在浏览器打开http://localhost:8080/http://localhost:8080/webpack-dev-server/ 可以浏览项目中的页面和编译后的资源输出,并且通过一个 socket.io 服务实时监听它们的变化并自动刷新页面。

    webpack-dev-server --progress --colors

    故障处理

    一般情况下,webpack 如果出问题,会打印一些简单的错误信息,比如模块没有找到。我们还可以通过参数 --display-error-details 来打印错误详情。

    webpack --display-error-details

    Webpack 的配置提供了 resolve 和 resolveLoader 参数来设置模块解析的处理细节,resolve 用来配置应用层的模块(要被打包的模块)解析,resolveLoader 用来配置 loader 模块的解析

    当引入通过 npm 安装的 node.js 模块时,可能出现找不到依赖的错误。Node.js 模块的依赖解析算法很简单,是通过查看模块的每一层父目录中的 node_modules 文件夹来查询依赖的。当出现 Node.js 模块依赖查找失败的时候,可以尝试设置 resolve.fallback 和 resolveLoader.fallback 来解决问题。

    module.exports = {

      resolve: { fallback: path.join(__dirname, "node_modules") },
      resolveLoader: { fallback: path.join(__dirname, "node_modules") }
    

    };

    相关文章

      网友评论

          本文标题:模块系统

          本文链接:https://www.haomeiwen.com/subject/cizhcxtx.html