【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 */

參考文章

相關文章
相關標籤/搜索