【smart-transform】取自 Atom 的 babeljs/coffeescript/typescript 智能转 es5 库

简介

有时间研究下开源库的源码,老是会有些收获的。注意到 Atom 插件编写时,能够直接使用 babel, coffeescript 或者 typescript。有些诧异,毕竟 Electron 中内置的 node 引擎,也必定不是彻底兼容 es6,更不用说 coffeescript 和 typescript了。因此,必然在加载插件时,Atom 有某种自动转换的操做。恰好最近有一些相似的需求,须要批量以单个文件的方式转换一些其余语法的文件到 es5 兼容的js文件,因而就把 Atom 的转换机制拆分了出来,写成一个 cli。前端

他山之玉,不敢私藏。若是只是使用,请直接在npmjs上查找:smart-transformnode

特点定制

毋容置疑,最核心的地方是取自于 Atom 自己。之因此把这个逻辑单独剥离出来,主要是我很羡慕 Atom 插件编写时,各类语法随心使用的舒爽!要是本身项目,也能这么随意,岂不是爽歪歪!!!webpack

为了独立于 Atom 使用,同时又具有必定的通用新,主要定制性体如今:ios

  • 将逻辑剥离成一个 cli 命令行工具,之后无论本身仍是别人,拿来即用。不是每一个前端,都很擅长 nodejs,因此我以为,这仍是能方便一些人的。
  • 经过配置文件,容许个性化定制。即,每一个项目的输入和输出目录能够经过配置文件来自由配置。如今还不够灵活,只支持指定惟一一个输入文件夹和惟一一个输出文件夹,不过暂时够用了。
  • 引入 uglify-js 进行压缩和混淆。这一点,确实是项目自己的须要,我相信大部分人,都有这个需求吧?另外,之因此直接使用 uglify-js ,固然是由于我不想再额外配置 webpack 呀!!

扔一个 smart-transform.json 配置文件示例上来吧:git

{
  "in":"./src",
  "out":"./lib",
  "exclude":["./src/hi-ignore.js"],
  "minify":true,
  "minifyExclude":["./src/hi-ts.ts"]
}

源码解读

package.json

"bin": {
    "smart-transform": "index.js"
  }

比较特殊的是 bin 字段。第一次写 cli 的童鞋,经常由于没有写这个字段,致使没有以全局命令的形式使用本身的工具库。es6

index.js

这是定制最多的一个文件。它实现的主要功能是,读取具体项目根目录的配置文件 smart-transform.json ,而后根据内部字段,来进行一些个性化的转换操做。github

目前支持的操做有:web

  • 将指定目录的 babeljs/coffeescript/typescript 转为 es5 兼容的js文件,并输出到另外一个目录。
  • 忽略某些文件,不对其进行转换操做。
  • 转换时,可选支持同时进行压缩和混淆操做。压缩和混淆,目前使用的是 uglify-js

代码不长,可是自己有一些 node 相关的代码,因此我就仍是贴出来,感兴趣的顺便瞅一眼:typescript

#!/usr/bin/env node
'use strict'
var path = require("path")
var fs = require ('fs-plus')
var fse = require('fs-extra')
var os = require("os")
var {execSync} = require("child_process")
var UglifyJS = require("uglify-js")

var argv = require('minimist')(process.argv.slice(2))

var project = argv.project
var configInfo = require(path.resolve(project,"./smart-transform.json"))

var inDir = path.resolve(project,configInfo.in)
var outDir = path.resolve(project,configInfo.out)
var minify = configInfo.minify

var excludeFiles = configInfo.exclude.map(function (filePath) {
  return path.resolve(project,filePath)
})

var minifyExcludeFiles = configInfo.minifyExclude.map(
  function (filePath) {
    return path.resolve(project,filePath)
  }
)

fse.ensureDirSync(outDir)

var inFiles = fs.listSync(inDir,[".js",".ts","coffee"])

for (var inFile of inFiles) {
    if (excludeFiles.includes(inFile)) { // 不须要处理的,直接复制到输出目录
      var outFile = path.resolve(project,outDir,path.basename(inFile))
      fse.copySync(inFile,outFile)
      continue
    }

    var sourceCode = require("./compile-file")(inFile)

    if (minify && !minifyExcludeFiles.includes(inFile)) {
      sourceCode = UglifyJS.minify(sourceCode).code
    }

    var outFile = path.resolve(project,outDir,path.basename(inFile,path.extname(inFile)) + ".js")
    fse.ensureFileSync(outFile)
    fs.writeFileSync(outFile,sourceCode)
}

compile-file.js

相关预编译逻辑取自原Atom代码中的 src/compile-cache.js 类,主要区别是,禁用代码地图并禁用输出代码内的注释。考虑到项目自己的内部兼容性,并无直接使用最新版的 Atom 源码演绎。若是本身有其余定制需求,能够直接看 Atom 源码。npm

这个文件比较出彩的地方是,它把各类相似的语法都使用 COMPILERS 的机制管理。一种语法对应一个 COMPILER。在某些特定状况下,若是你想解析或转换其余类型的文件,只须要修改这个类,新增一个 COMPILER 便可。

'use strict'
var path = require('path')
var fs = require('fs-plus')

var COMPILERS = {
  '.js': require('./babel'),
  '.ts': require('./typescript'),
  '.coffee': require('./coffee-script')
}

function compileFileAtPath (filePath) {
  const extension = path.extname(filePath)
  const compiler = COMPILERS[extension]

  var sourceCode = fs.readFileSync(filePath, 'utf8')

  if (compiler.shouldCompile(sourceCode, filePath)) {
    const compiledCode = compiler.compile(sourceCode, filePath)
    return compiledCode
  }

  return sourceCode
}

module.exports = compileFileAtPath

babel.js coffee-script.js typescript.js

分别取自 Atom 源码中的 babel.js coffee-script.js typescript.js。有极小的修改,典型的 拿来主义 。有兴趣的,直接去看下源码,此处不作赘述。

注意

使用 bable 的js文件,开头应是如下几种的其中一种,不然没法被识别:

/** @babel */
"use babel"
'use babel'
/* @flow */

参考文章

相关文章
相关标签/搜索