cmdfix

0.1.16 • Public • Published

基于语法分析的CMD格式标准化工具

背景

新前端资源加载方式将代码依赖的打包编译转移到线下,那么线上就不需要独角兽对资源进行打包,线上静态资源服务可以变得更纯粹。而线下代码,可以使用标准的CommonJS方式书写,基于此的js的运行环境也不再局限于浏览器。
前端js/6v下的代码采用了seajs划分模块,遵循CMD规范,与CommonJS差别仅在于头尾多了define的包装。如果要将CMD规范的代码迁移到CommonJS规范,仅需去除define定义。如下:

CMD规范代码,基于seajs可在浏览器端运行。

// 所有模块都通过 define 来定义
define(function(require, exports, module) {

  // 通过 require 引入依赖
  var $ = require('jquery');

  // 通过 exports 对外提供接口
  exports.doSomething = ...

  // 或者通过 module.exports 提供整个接口
  module.exports = ...

});

CommonJS,可在node端运行。

// 通过 require 引入依赖
var fs = require('fs');

// 通过 exports 对外提供接口
exports.doSomething = ...

// 或者通过 module.exports 提供整个接口
module.exports = ...

但是,seajs又在返回模块上加了语法糖封装,支持以下更简化的写法。

// 所有模块都通过 define 来定义
define(function(require) {

  // 通过 require 引入依赖
  var $ = require('jquery');

  // 等同于module.exports = ...
  return ...;

});

这种写法有异于CommonJS,仅使用到了模块引用(require),模块导出无需模块定义(exports)或模块标识(module)的方式传递,而使用了直接return的方式。

所以,js/6v下的代码要迁移到CommonJS规范的代码需要2步:

  1. 把用语法糖书写的方式的代码CMD格式标准化;
  2. CMD标准格式的代码去define变成CommonJS规范。

单个文件操作起来并不复杂,以迁移询盘系统(gangesweb)为例,总文件1135个,仅js也有800多个,人肉修改是个苦力活。编辑器批量替换实现难度也很高。那么久只能通过编写工具来实现。

解决方案与使用方法

为此,用node写了个小工具cmdfix来解决背景问题中的第一步。(PS:第二步架构组有相应的工具解决,只针对标准化的CMD迁移CommonJS,所以还是需要通过cmdfix完成seajs代码CMD格式标准化处理)。

通过npm可安装:

npm install cmdfix -g

安装后可以通过命令行调用:

cmdfix <target> [ignore]

target:必选,扫描修正的目录或文件地址;ignore:可选,扫描目录下忽略的目录或文件,多个用逗号隔开。

例子:

cmdfix ./htdocs/js/6v/biz/gangesweb ./customer,./fastfeedback

扫描修正gangesweb下除了customer和fastfeedback以外的所有目录下的文件。

也可以把它作为可以node模块引入使用,如:

var cmd = require('cmdfix');

var result = cmd.fix({
  "target": "", // 目标地址,扫描修正的目标目录或文件
  "destination": "", // 修正后代码输出路径,为空则直接替换源文件
  "suffix": [".js"], // 修正的代码文件后缀名
  "ignore": [] // 忽略扫描的子目录或文件,地址相对于目标地址
}, function (scans, index) { // 进度回调,每处理完一个文件执行
  // scans 所有需要处理的文件
  // index 当前已经处理过的文件索引
});

/* 
 * 处理结果,包括:
 * scans所有扫描处理的文件路径;
 * cmds所有CMD规范的文件路径;
 * fixed所有修正处理的文件路径;
 */
console.log(result); 

基于语法分析的实现

要完成代码修正,最容易想到的就是用正则替换最后的returnmodule.exports和补全require, exports, module。但是考虑上以下场景就发现没那么简单了:

// return一个带有return的函数
define(function(require) {
  var $ = require('$');
  // doSomething ...
  return (function(){
    // doSomething ...
    return 'something';
  });
});

// 用其他命名代替require。exports,module类同
define(function(r, e) {
  var $ = r('$');
  e.doSomething = function() {
    // doSomething ... 
  }
});

// 工厂函数参数为0个、1个(即require)、2个(即require和exports)和3个(require,exports,module)的情况
define(function(require, exports) {
  var $ = require('$');
  exports.doSomething = function() {
    // doSomething ... 
  }
});

// 多写了个空的return
define(function() {
  // doSomething ...
  return;
});

应对以上一些可能的场景,正则的替换处理就会变得特别复杂,而且还容易出错。

所以从保证工具准确率的角度上,使用基于语法分析的实现会更安全,具体的代码实现就不展开细节。

应用场景

首先当然就是6v下的应用代码的修正,这里以修正询盘系统(gangesweb)的代码为例:

img

耗时3秒不到扫描了885个js文件,其中CMD模块658个,修正了647个非标准化CMD格式的模块。

对修正后代码进行diff查看,准确率100%;

除了近期要迁移到git上的gangesweb代码,其他业务线迁移前需要对代码进行CMD标准化修正,都可以使用。

另外一个应用场景,就是可以通过node模块调用的方式,使用到架构组CMD到CommonJS迁移的工具中,弥补未做CMD标准化处理的缺失。甚至可以使用cmdfix的语法分析方案,改进迁移工具。

Readme

Keywords

none

Package Sidebar

Install

npm i cmdfix

Weekly Downloads

3

Version

0.1.16

License

MIT

Last publish

Collaborators

  • wiky
  • sunny.zhouy