mpx-es-check: 再也不用担心你的页面白屏

1,384 阅读3分钟

image.png

背景

日常开发中,有时会存在漏掉代码进行 babel 转换,或者是直接引用了未经过 babel 转换的第三方代码库中的 js 文件,很显然,这会导致页面在部分机型报错甚至页面白屏

为了解决上述问题,产出了 mpx-es-check 工具,用来对构建产物代码进行分析,检测其中是否有低版浏览器不支持的语法。

使用

install

npm i mpx-es-check --save-dev
// or
npm i mpx-es-check -g

Usage

  • 如果是本地安装:在 package.json 中添加 scripts 命令
"esCheck": "mpx-es-check --module --ecma=6 './dist/*.js'"
  • 如果是全局安装:可直接运行命令
mpx-es-check --module --ecma=6 ./dist/*.js
  • --module

默认以 script 检测代码

  • es6
    • 所需要检测的最低版本,输入es6 表示会检测 es6及以上的所有语法
  • ./dist/*.js
    • 设置文件匹配的范围:  ./somePath/*.js
  • --all
    • 在命令中添加 --all 参数会启用实例方法和静态方法的检测
mpx-es-check --module --all --ecma=6 ./dist/*.js

result

  • 如果检测到存在高版本语法或方法,则会在终端输出 error 提示 log,并会在检测文件目录生成 es-check.log 文件,进行详细错误信息的查看,log 文件中会输出
// 终端输出
检测进度:100.00% ████ 4/4
检测到语法错误, 详情请查看文件: 
      /Users/some/Project/babel-test/mpx-es-check/dist/es-check.log

// es-check.log
ERROR:
            Using const is not allowed
            at file: ./dist/test2.js
            at startLine: 1
            at startColumn: 0
            
ERROR:
            Using const is not allowed
            at file: ./dist/test4.js
            at startLine: 2
            at startColumn: 0

原理

image.png

parse

将构建产物代码使用 babel/parse 转成ast

traverse

  • 首先根据用户命令行输入的 es 版本进行检测规则的整合

这里有创建一个 eventEmitter,将检测规则进行注册,同时检测规则中,ecma 语法部分是依据与 estree 进行的配置 image.png instance method 和 static method,以及 BuiltIns Object 是依照 transform-runtime 中 runtime-corejs3-definitions 进行配置,这里列举一个简单的示例:

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _default = () => {
  return {
    BuiltIns: {
      Map: {
        stable: true,
        path: "map"
      }
    },
    StaticProperties: {
      Array: {
        from: {
          stable: true,
          path: "array/from"
        },
        isArray: {
          stable: true,
          path: "array/is-array"
        },
        of: {
          stable: true,
          path: "array/of"
        }
      },
     
    },
    InstanceProperties: {
      concat: {
        stable: true,
        path: "concat",
        types: ["array"]
      }
    }
  };
};

exports.default = _default;
  • 在代码里对这部分语法规则进行检测规则的注册:
module.exports = {
  meta: {
    docs: {
      description: 'ecma2017 rules'
    }
  },
  create (context) {
    return {
      // 检测 async
      FunctionDeclaration (node) {
        if (node.async === true) {
          context.report({
            node,
            message: 'Using async function is not allowed'
          })
        }
      },
      // 检测 await
      AwaitExpression (node) {
        if (node.operator === '**=') {
          context.report({
            node,
            message: 'Using AwaitExpression await is not allowed'
          })
        }
      }
    }
  }
}

方法和内建对象的检测是通过 MemberExpression 节点中,(object.name)[proterty.name] 是否匹配规则进行检测。 不过这种检测方法会存在误诊的情况,例如 引入的 core-js/pofyfill 中会存在一些 if 判断或者是 或 运算符:

var nativeAssign = Object.assign || _pofillAssign

会导致 es-check 产生方法的误判,目前也在逐步的完善对方法的整体语法环境的判断,暂时只实现了 在 ifStatement 中规避检测的方法。同时因为方法检测的不确定性,这一部分功能也添加了 --all 选项来供用户自由选择是否打开。

  • 对整个 ast 树进行遍历,这里使用的 babel/traverse

在遍历节点树的过程中,当遇到 eventEmitter 中已经注册过的节点,则进行 rule 的执行

applySelector (node, selector, path) {
    if (esquery.matches(node, selector.parsedSelector, this.currentAncestry)) {
      this.emitter.emit(selector.rawSelector, node, path)
    }
 }

error

匹配到相应的 ast 节点,通过report 函数进行 error/warning 上报,最终收集输出到 es-check.log 文件中

总结

使用 mpx-es-check 基本上能够避免应用因为语法兼容问题导致的故障。