运行js代码的运行环境大部分是浏览器或是node.js,现如今高性能v8大有一统天下的趋势,不但node.js天然采用v8,就连微软也在逐渐向v8靠拢。

    js引擎虽强,但碎片化过于严重的问题依旧存在,多极的浏览器,版本频繁发布的node.js,兼容性一直都是前端工程师绕不过去的一道坎。

    前端的发展速度越来越快,越来越强大丰富的api,越来越强大的社区开源项目,应接不暇的落地。除了社区的火爆外,还要归功于babel,ts这类代码转译工具和webpack、rollup这种模块化打包工具。

    前端开发现在的主流趋势就是spa、mv*、数据驱动,进而衍生了三大框架,angular,vue,react。三大框架各自尤其优秀之处,我们把关注点暂时剥离,讨论这些框架不是我们今天的主旨。我们先来看下这些框架各自的特色。

    angular(2.0后)天然采用ts,html,css与component文件分离,在html中可以使用特定指令与语法。

    vue使用.vue文件,style标签,template标签,script标签分别承载不同逻辑,template可以使用指令与特有语法。

    react使用jsx混合原生js,发挥原生力量,同时亦有自己的模板语法。

    总结下来,我们可以发现,无论哪个框架,几乎都有自己的特殊模板语法和指令。实际上,我们可以理解为,无论哪个框架,在编译过程中,都会包容和传统模板渲染机制类似的功能。

    以react为例子:

    1. import React from 'react';
    2. export function App() {
    3. return <div>hello world</div>
    4. }

    经过babel转换后:

    1. "use strict";
    2. Object.defineProperty(exports, "__esModule", {
    3. value: true
    4. });
    5. exports.App = App;
    6. var _react = _interopRequireDefault(require("react"));
    7. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
    8. function App() {
    9. return _react.default.createElement("div", null, "hello world");
    10. }

    大家应该都知道,真正跑在浏览器里的,其实是后面babel转换后的代码,因为浏览器根本不了解所谓的jsx代码,干脆就没法识别。需要工具来帮忙让这段浏览器不认识,没法解析的代码,让浏览器能认识,能识别。所幸,babel可以帮我们来做这件事,实际上,angular也好,vue也好,都需要babel来转换。

    那么,babel是怎样做到的呢?没什么黑魔法,但也绝非是简单的正则批量替换,真正的核心有三步:

    1. 分析ast解析后的源码对象
    2. 根据自己的规则来转换代码,即更改ast对象(创建代码节点-删除代码节点)
    3. 根据变更后的ast源码源码,生成代码。

    实际上定义一套转换规则是很复杂的(也并不是黑魔法),但是只要你能定义的出规则,就可以写出属于你自己的编译器,babel,typescript等。具体要如何做,后面我们会讲到,现在再来说下模块化打包。

    光有了babel是不行的,代码创建出来了,但依然有很多问题存在,比如如何将所有模块化的内容打包在一起?如何拆包?commonjs规范是node.js环境中实现的,浏览器要如何模拟出commonjs?或者amd等。这些就需要用到模块打包器了,比如rollup,webpack。(gulp是工作流工具,不负责打包)

    那他们又是怎么实现的呢?其实也是没啥黑魔法,根据入口文件递归读取依赖->ast解析->转换commonjs/amd/umd等浏览器实现->生成代码->吐文件。

    过程相对繁琐,可理解了这套机制,你也可以实现自己的模块打包机。

    下面开始,就从手撸webpack模块打包功能开始,去逐步了解ast!