1、前端编译、构建

不知道你是怎么理解编译和构建这两个词语的?

我的理解是:

  • 编译:从 A 语言到 B 语言的转换过程,如 sass 预编译文件编译到 css 文件等,sass 虽然和 css 长得像,但不能直接运行,与 css 不是同一种语言。
  • 构建:对 A 语言的修饰过程,如压缩 js 文件,压缩之前和之后都是 JS 代码,都可以直接运行。

你同意吗?

  • 如果同意的话,继续往下看。
  • 如果不同意,直接往底看。

2、现状

使用预编译文件、新规范越来越流行

为什么使用预编译文件、新规范越来越流行?

sass 语言

/* sass */
.banner {
    &-nav {
        /*... */
    }

    &-list {
        /*... */
    }
}

/* css */
.banner-nav {
    /*... */
}

.banner-list {
    /*... */
}

如上,两种代码的直视,显然 sass 的语法更加亲民,看起来更美。

es2015

// es2015
fn() => {}

// es5
function fn() {
    return {};
}

如上,新规范的代码看起来更加简洁。

但是,这股流行风,带来的一个负面作用就是需要编译手写完的代码。手动编译是不可能的了,就需要使用工具来代替了。但在使用工具的过程中,分别有两种途径:

  • 编译单个文件,如 webstorm、手写 watch、grunt、gulp、各种独立编译工具
  • 编译整个工程,如 webpack

直觉上看,编译单个文件的代价会更低。但实际上,编译整个工程更加的流行起来。其中一部分原因来自于这张图:

直接在 JS 文件里引用各种资源、各种预编译文件,看起来非常的美不是吗?编写一个 UI 组件使用的是最美的 JS 语法,使用最美的 css 预编译,在 JS 里直接引用各种图片、字体等。这种特性对奔波在 JS 组件开发开发者来说,是直击痛点的。

其实在 webpack 之前,模块化流行的时候,就已经有资源即是模块的概念了,比如 fseajs-css 就是支持引用 css 文件的。但是这种技术当初只是作为一个 plugin 来支持的,并且配套的构建工具也是非常的难用。

构建工具的能力

深受 webpack 或者是同类产品的影响,开发者们对构建工具的能力要求是越来越多了。

  • 支持直接编写最新规范的 JS
  • 支持自定义语法规范的 JS,如 react
  • 支持预编译文件,如 sass
  • 支持直接引用资源文件
  • 支持各种姿势的构建
  • 支持模块化
  • 支持工程化

正巧的是,webpack 拥有大部分这样的能力,并且可以通过 plugin 的模式来扩展自己,使得 webpack 的影响力在前端领域越来越广,甚至将 webpack 作为内部的构建工具的公司也逐渐增多。

3、启示

回到我们文章开始的编译与构建的区分。webpack 是同时拥有这样的能力的,也正是因为这样的能力带来了一些不可不接受的代价:

  • 需要支持增量编译,因为对整个工程的编译花费的时间是非常的长的,可喜的是 webpack 现在已经实现了。
  • 无法直接在浏览器运行手写的代码,因为没有及时对单个文件编译,并且因为的是编译之前的文件,所以导致整个工程无法直接运行。
  • 学习成本大幅提高,需要了解和掌握 webpack 的基础能力和各种插件的支持情况。

fcoolie 在这点上另辟蹊径,将编译过程交给各种自定义 watch 任务,而只掌握构建过程。为什么要这么做?

首先来看看前端开发涉及了哪些文件,分别是 HTML、CSS、JS,其中 HTML 源码里标记各种资源的引用,是浏览器直接运行的文件,所有的资源的源头都是这里,比如引用的图片、引用的模块加载器、引用样式文件等等。而在模块加载器里又动态加载了各种模块,如图片模块、样式模块、文本模块等等。

其次,我们不直接使用预编译文件,而是编译后、浏览器可以直接解析的文件,这样我们写的是美观的代码,实际运行的是编译后的代码,对我们开发者来说几乎是零障碍的。

coolie 从 HTML 文件出发,完善模块化解决方案,支持引用各种类型的资源文件,如图片、字体、样式等等。有了特制的模块加载器,可以直接运行在浏览器,并且在构建上能够非常好的支持。

最终与 webpack 是殊途同归,但带来的代价却是非常的小。

  • 编译直接交给 watch 任务,并且是单文件编译,一秒钟的事情。
  • 因为我们在代码里引用都是编译后的文件,所以可以直接运行在浏览器上。
  • 学习成本非常低,几乎没有改变现在的任何开发习惯。