天天看點

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

簡介

有時間研究下開源庫的源碼,總是會有些收獲的。注意到 Atom 插件編寫時,可以直接使用 babel, coffeescript 或者

typescript。有些詫異,畢竟 Electron 中内置的 node 引擎,也一定不是完全相容 es6,更不用說 coffeescript

和 typescript了。是以,必然在加載插件時,Atom

有某種自動轉換的操作。剛好最近有一些類似的需求,需要批量以單個檔案的方式轉換一些其他文法的檔案到 es5 相容的js檔案,于是就把 Atom

的轉換機制拆分了出來,寫成一個 cli。

他山之玉,不敢私藏。如果隻是使用,請直接在npmjs上查找:

smart-transform

特色定制

毋容置疑,最核心的地方是取自于 Atom 本身。之是以把這個邏輯單獨剝離出來,主要是我很羨慕 Atom 插件編寫時,各種文法随心使用的舒爽!要是自己項目,也能這麼随意,豈不是爽歪歪!!!

為了獨立于 Atom 使用,同時又具備一定的通用新,主要定制性展現在:

  • 将邏輯剝離成一個 cli 指令行工具,以後不管自己還是别人,拿來即用。不是每個前端,都很擅長 nodejs,是以我覺得,這還是能友善一些人的。
  • 通過配置檔案,允許個性化定制。即,每個項目的輸入和輸出目錄可以通過配置檔案來自由配置。現在還不夠靈活,隻支援指定唯一一個輸入檔案夾和唯一一個輸出檔案夾,不過暫時夠用了。
  • 引入 uglify-js 進行壓縮和混淆。這一點,确實是項目本身的需要,我相信大部分人,都有這個需求吧?另外,之是以直接使用 uglify-js ,當然是因為我不想再額外配置 webpack 呀!!

扔一個 smart-transform.json 配置檔案示例上來吧:

{
  "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 的童鞋,常常因為沒有寫這個字段,導緻沒有以全局指令的形式使用自己的工具庫。

index.js

這是定制最多的一個檔案。它實作的主要功能是,讀取具體項目根目錄的配置檔案 smart-transform.json ,然後根據内部字段,來進行一些個性化的轉換操作。

目前支援的操作有:

  • 将指定目錄的 babeljs/coffeescript/typescript 轉為 es5 相容的js檔案,并輸出到另一個目錄。
  • 忽略某些檔案,不對其進行轉換操作。
  • 轉換時,可選支援同時進行壓縮和混淆操作。壓縮和混淆,目前使用的是 uglify-js

代碼不長,但是本身有一些 node 相關的代碼,是以我就還是貼出來,感興趣的順便瞅一眼:

#!/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 源碼。

這個檔案比較出彩的地方是,它把各種類似的文法都使用 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 */
           

參考文章

原文釋出時間為:2017/11/28

原文作者: ios122

本文來源:

開源中國

如需轉載請聯系原作者

繼續閱讀