ESCheck工具原理解析及增强实现(1)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 前言2022了,大家做的面向C端的产品(Web,小程序,其它跨端方案),涉及JS产物的还是避不开兼容性的话题(即使IE已官宣停止支持)但就目前看来这个停止维护还是避免不了大家做开发还是要考虑兼容低端机,甚至IE11

前言

2022了,大家做的面向C端的产品(Web,小程序,其它跨端方案),涉及JS产物的还是避不开兼容性的话题(即使IE已官宣停止支持)

但就目前看来这个停止维护还是避免不了大家做开发还是要考虑兼容低端机,甚至IE11

针对js目前通常的手段都是通过工具对js进行语法降级至 ES5,同时引入对应的 polyfill(垫片)

工具首选还是老牌 Babel,当然现在还有 SWC 这个冉冉升起的新星

经过一顿操作为项目配置 Babel 之后,为了保证产物不出现 ES5 之外的语法,通常都会搭配一个 Check 工具去检测产物是否符合要求

本文将阐述市面上已有工具的实现原理功能对比,最后实现增强型的es-check,提供 CLI 和 Lib 两种使用方式

下面先分别介绍一下社区版的es-check和滴滴版的@mpxjs/es-check实现原理,最后再实现一个集大成者

es-check

先看一下其效果,下面是用于测试的代码

作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

// test.js
var str = 'hello'
var str2 = 'world'
const varConst = 'const'
let varLet = 'let'
const arrFun = () => {
    console.log('hello world');
}
npx es-check es5 testProject/**/*.js

image.png

可以看到其报错信息比较简单,只输出了代码中的第一个ES语法问题const,然后对应的是行数和具体文件路径

我们再把这个测试文件构建压缩混淆一下(模拟build产物)

npx tsup __test__/testProject/js/index.js --sourcemap -d __test__/testProject/dist --minify

通过结果,可以看到,只说有解析问题,并未告知是什么问题,然后有对应的行列数

image.png

如果有sourcemap那么我们暂且是可以通过source-map这个库解析一下,以上面的报错为例

// npx esno source-map.ts
import sourceMap from 'source-map'
import fs from 'fs'
import path from 'path'
const file = path.join(__dirname, 'testProject/dist/index.js.map')
const lineNumber = 1
const columnNumber = 45
;(async () => {
  const consumer = await new sourceMap.SourceMapConsumer(
    fs.readFileSync(file, 'utf-8')
  )
  const sm = consumer.originalPositionFor({
    column: columnNumber,
    line: lineNumber
  })
  // 对应文件的源码
  const content = consumer.sourceContentFor(sm.source!)
  // 错误行的代码
  const errCode = content?.split(/\r?\n/g)[sm.line! - 1]
  console.log(errCode)
})()

执行结果如下,可以得到对应的错误代码

image.png

原理分析

打开源码可以看到实现非常简单,关键不过100行。可以总结为3步骤

  1. 使用 fast-glob 获取目标文件
  2. 使用 acorn 解析源码生层AST,并捕获解析错误
  3. 判断是否存在解析错误,有就打印

acorn 是一个很常见的 js 解析库,可以用于AST的生成与CRUD操作,其包含1个 ecmaVersion 参数用于指定要解析的 ECMAScript 版本。es-check正是利用了这个特性

import * as acorn from 'acorn'
try {
  acorn.parse(`const a = 'hello'`, {
    ecmaVersion: 5,
    silent: true
    // sourceType: 'module'
    // allowHashBang:true
  })
} catch (err) {
  // The keyword 'const' is reserved (1:0)
  console.log(err)
  // err 除了继承常规 Error 对象,包含 stack 和 message 等内容外,还包含如下信息
  // {
  //   pos: 0,
  //   loc: Position { line: 1, column: 0 },
  //   raisedAt: 7
  // }
}

下面是es-check的精简实现,完整源码见 Github

// npx esno es-check.ts
import fg from 'fast-glob'
import path from 'path'
import * as acorn from 'acorn'
import fs from 'fs'
const testPattern = path.join(__dirname, 'testProject/**/*.js')
// 要检查的文件
const files = fg.sync(testPattern)
// acorn 解析配置
const acornOpts = {
  ecmaVersion: 5,// 目标版本
  silent: true
  // sourceType: 'module'
  // allowHashBang:true
}
// 错误
const errArr: any[] = []
// 遍历文件
files.forEach((file) => {
  const code = fs.readFileSync(file, 'utf8')
  try {
    acorn.parse(code, acornOpts as any)
  } catch (err: any) {
    errArr.push({
      err,
      stack: err.stack,
      file
    })
  }
})
// 打印错误信息
if (errArr.length > 0) {
  console.error(
    `ES-Check: there were ${errArr.length} ES version matching errors.`
  )
  errArr.forEach((o) => {
    console.info(`
        ES-Check Error:
        ----
        · erroring file: ${o.file}
        · error: ${o.err}
        · see the printed err.stack below for context
        ----\n
        ${o.stack}
      `)
  })
  process.exit(1)
}
console.info(`ES-Check: there were no ES version matching errors!  🎉`)

image.png

小结

  1. 只能检测源码中是否存在不符合对应ECMAScript版本的语法
  2. 只会反应出文件中第一个语法问题
  3. 错误信息只包含所在文件中的行列号以及parser error
  4. 不支持html

mpx-es-check

滴滴出品的 mpx (增强型跨端小程序框架)的配套工具 @mpxjs/es-check

咱们还是用上面的例子先实测一下效果

# 1
npm i -g @mpxjs/es-check
# 2
mpx-es-check --ecma=6 testProject/**/*.js

可以看到其将错误信息输出到了1个log文件中

image.png

log日志信息如下,还是很清晰的指出了有哪些错误并标明了错误的具体位置,内置了source-map解析。

image.png

下面来探究一下实现原理

原理分析

打开源码,从入口文件开始看,大体分为以下几步:

  1. 使用glob获取要检测目标文件
  2. 获取文件对应的源码sourcemap文件内容
  3. 使用@babel/parser解析生成AST
  4. 使用@babel/traverse遍历节点
  5. 将所有非ES5语法的节点规则进行枚举,再遍历节点时,找出符合条件的节点
  6. 格式化输出信息

其中@babel/parser@babel/traversebabel的核心构成部分。一个用于解析一个用于遍历

节点规则示例如下,这个方法准确,就是费时费力,需要将每个版本的特性都穷举出来

// 部分节点规则
const partRule = {
  // let and const
  VariableDeclaration(node) {
    if (node.kind === 'let' || node.kind === 'const') {
      errArr.push({
        node,
        message: `Using ${node.kind} is not allowed`
      })
    }
  },
  // 箭头函数
  ArrowFunctionExpression(node) {
    errArr.push({
      node,
      message: 'Using ArrowFunction(箭头函数) is not allowed'
    })
  }
}

下面是遍历规则与节点的逻辑

// 存放所有节点
const nodeQueue = []
const code = fs.readFileSync(file, 'utf8')
// 生成AST
const ast = babelParser.parse(code, acornOpts)
// 遍历获取所有节点
babelTraverse(ast, {
  enter(path) {
    const { node } = path
    nodeQueue.push({ node, path })
  }
})
// 遍历每个节点,执行对应的规则
nodeQueue.forEach(({ node, path }) => {
  partRule[node.type]?.(node)
})
// 解析格式化错误
errArr.forEach((err) => {
  // 省略 sourcemap 解析步骤
  problems.push({
    file,
    message: err.message,
    startLine: err.node.loc.start.line,
    startColumn: err.node.loc.start.column
  })
})

ESCheck工具原理解析及增强实现(2): https://developer.aliyun.com/article/1394814?spm=a2c6h.13148508.setting.18.55964f0ez7IHhI

相关文章
|
2月前
|
存储 缓存 算法
HashMap深度解析:从原理到实战
HashMap,作为Java集合框架中的一个核心组件,以其高效的键值对存储和检索机制,在软件开发中扮演着举足轻重的角色。作为一名资深的AI工程师,深入理解HashMap的原理、历史、业务场景以及实战应用,对于提升数据处理和算法实现的效率至关重要。本文将通过手绘结构图、流程图,结合Java代码示例,全方位解析HashMap,帮助读者从理论到实践全面掌握这一关键技术。
113 14
|
3月前
|
运维 持续交付 云计算
深入解析云计算中的微服务架构:原理、优势与实践
深入解析云计算中的微服务架构:原理、优势与实践
134 3
|
6天前
|
机器学习/深度学习 算法 数据挖掘
解析静态代理IP改善游戏体验的原理
静态代理IP通过提高网络稳定性和降低延迟,优化游戏体验。具体表现在加快游戏网络速度、实时玩家数据分析、优化游戏设计、简化更新流程、维护网络稳定性、提高连接可靠性、支持地区特性及提升访问速度等方面,确保更流畅、高效的游戏体验。
52 22
解析静态代理IP改善游戏体验的原理
|
3天前
|
编解码 缓存 Prometheus
「ximagine」业余爱好者的非专业显示器测试流程规范,同时也是本账号输出内容的数据来源!如何测试显示器?荒岛整理总结出多种测试方法和注意事项,以及粗浅的原理解析!
本期内容为「ximagine」频道《显示器测试流程》的规范及标准,我们主要使用Calman、DisplayCAL、i1Profiler等软件及CA410、Spyder X、i1Pro 2等设备,是我们目前制作内容数据的重要来源,我们深知所做的仍是比较表面的活儿,和工程师、科研人员相比有着不小的差距,测试并不复杂,但是相当繁琐,收集整理测试无不花费大量时间精力,内容不完善或者有错误的地方,希望大佬指出我们好改进!
46 16
「ximagine」业余爱好者的非专业显示器测试流程规范,同时也是本账号输出内容的数据来源!如何测试显示器?荒岛整理总结出多种测试方法和注意事项,以及粗浅的原理解析!
|
1月前
|
机器学习/深度学习 自然语言处理 搜索推荐
自注意力机制全解析:从原理到计算细节,一文尽览!
自注意力机制(Self-Attention)最早可追溯至20世纪70年代的神经网络研究,但直到2017年Google Brain团队提出Transformer架构后才广泛应用于深度学习。它通过计算序列内部元素间的相关性,捕捉复杂依赖关系,并支持并行化训练,显著提升了处理长文本和序列数据的能力。相比传统的RNN、LSTM和GRU,自注意力机制在自然语言处理(NLP)、计算机视觉、语音识别及推荐系统等领域展现出卓越性能。其核心步骤包括生成查询(Q)、键(K)和值(V)向量,计算缩放点积注意力得分,应用Softmax归一化,以及加权求和生成输出。自注意力机制提高了模型的表达能力,带来了更精准的服务。
|
20天前
|
网络协议 Unix Linux
深入解析:Linux网络配置工具ifconfig与ip命令的全面对比
虽然 `ifconfig`作为一个经典的网络配置工具,简单易用,但其功能已经不能满足现代网络配置的需求。相比之下,`ip`命令不仅功能全面,而且提供了一致且简洁的语法,适用于各种网络配置场景。因此,在实际使用中,推荐逐步过渡到 `ip`命令,以更好地适应现代网络管理需求。
33 11
|
2月前
|
人工智能 搜索推荐 API
Cobalt:开源的流媒体下载工具,支持解析和下载全平台的视频、音频和图片,支持多种视频质量和格式,自动提取视频字幕
cobalt 是一款开源的流媒体下载工具,支持全平台视频、音频和图片下载,提供纯净、简洁无广告的体验
341 9
Cobalt:开源的流媒体下载工具,支持解析和下载全平台的视频、音频和图片,支持多种视频质量和格式,自动提取视频字幕
|
2月前
|
人工智能 自然语言处理 Java
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
FastExcel 是一款基于 Java 的高性能 Excel 处理工具,专注于优化大规模数据处理,提供简洁易用的 API 和流式操作能力,支持从 EasyExcel 无缝迁移。
218 9
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
|
2月前
|
数据可视化 项目管理
个人和团队都好用的年度复盘工具:看板与KPT方法解析
本文带你了解高效方法KPT复盘法(Keep、Problem、Try),结合看板工具,帮助你理清头绪,快速完成年度复盘。
137 7
个人和团队都好用的年度复盘工具:看板与KPT方法解析
|
1月前
|
监控 数据可视化 数据挖掘
直播电商复盘全解析:如何通过工具提升团队效率
直播电商作为新兴商业模式,正改变传统零售格局。其成功不仅依赖主播表现和产品吸引力,更需团队高效协作与分工优化。复盘是提升执行力的关键环节,通过总结经验、发现问题、优化流程,结合在线工具如板栗看板,可提升复盘效率。明确团队角色、建立沟通机制、制定优化方案,确保数据驱动决策,从而在竞争中保持领先。

热门文章

最新文章

推荐镜像

更多