前端開(kāi)發(fā)過(guò)程當(dāng)中,總會(huì)有一些機(jī)械重復(fù)的工作要做顷蟆,比如:新建文件夾诫隅,新建一個(gè) ts 文件,新建一個(gè)樣式文件帐偎,向已有的菜單文件中增加新建的文件逐纬,初始化等等。這些繁復(fù)的工作雖然不復(fù)雜削樊,但仍需要占用大量的時(shí)間豁生,有沒(méi)有除了手動(dòng)添加外其它的方法呢?
答案是有的漫贞。
初始化
對(duì)于創(chuàng)建文件之類的甸箱,我們可以使用 fs-extra 來(lái)解決,初始化的文件我們只需要傳入一段已寫(xiě)好的 js
就好迅脐。
fs-extra
: 文件操作相關(guān)工具庫(kù)摇肌,是系統(tǒng)fs
模塊的擴(kuò)展,提供了更多便利的API
仪际,并繼承了fs
模塊的API
围小。
安裝
npm install fs-extra
使用示例:
const fs = require('fs-extra')
// Async with promises:
fs.copy('/tmp/myfile', '/tmp/mynewfile')
.then(() => console.log('success!'))
.catch(err => console.error(err))
// Async with callbacks:
fs.copy('/tmp/myfile', '/tmp/mynewfile', err => {
if (err) return console.error(err)
console.log('success!')
})
// Sync:
try {
fs.copySync('/tmp/myfile', '/tmp/mynewfile')
console.log('success!')
} catch (err) {
console.error(err)
}
// Async/Await:
async function copyFiles () {
try {
await fs.copy('/tmp/myfile', '/tmp/mynewfile')
console.log('success!')
} catch (err) {
console.error(err)
}
}
copyFiles()
使用方法:
Async
- copy
- emptyDir
- ensureFile
- ensureDir
- ensureLink
- ensureSymlink
- mkdirp
- mkdirs
- move
- outputFile
- outputJson
- pathExists
- readJson
- remove
- writeJson
Sync
- copySync
- emptyDirSync
- ensureFileSync
- ensureDirSync
- ensureLinkSync
- ensureSymlinkSync
- mkdirpSync
- mkdirsSync
- moveSync
- outputFileSync
- outputJsonSync
- pathExistsSync
- readJsonSync
- removeSync
- writeJsonSync
那么如何向已有文件追加呢?
答:我們可以考慮使用 babel
树碱。
追加文件
我們想要追加文件的話大概需要如何幾個(gè)步驟:
讀取文件
解析文件
遍歷修改
生成代碼
寫(xiě)回文件
讀取文件
使用上面的 fs-extra
讀取文件肯适,方法如下:
fs.readFileSync(dir, format)
dir
: 讀取文件的路徑,format
: 編碼格式
解析文件
使用 @babel/parser
解析文件
babelParser.parse(code, [options])
babelParser.parseExpression(code, [options])
parse
將提供的代碼作為一個(gè)完整的ECMAScript
程序進(jìn)行解析成榜,而parseExpression
則嘗試解析單個(gè)表達(dá)式并考慮性能框舔。code
: 剛剛讀取的代碼,options
: 配置信息
options
選項(xiàng)如下:
allowImportExportEverywhere
: 默認(rèn)情況下,import
和export
聲明只能出現(xiàn)在程序的頂層刘绣。如果將此選項(xiàng)設(shè)置為true
樱溉,則允許在任何允許使用語(yǔ)句的地方使用它們。allowAwaitOutsideFunction
: 默認(rèn)情況下纬凤,只允許在異步函數(shù)內(nèi)部使用 await福贞,或者在啟用topLevelAwait
插件時(shí),允許在模塊的頂層作用域中使用await停士。將其設(shè)置為true挖帘,以便在腳本的頂級(jí)范圍中也接受它。allowReturnOutsideFunction
: 默認(rèn)情況下恋技,頂層的 return 語(yǔ)句會(huì)引發(fā)錯(cuò)誤拇舀。將此設(shè)置為 true 以接受此類代碼。allowSuperOutsideMethod
: 默認(rèn)情況下蜻底,在類和對(duì)象方法之外不允許 super 使用骄崩。將此設(shè)置為 true 以接受此類代碼。allowUndeclaredExports
: 默認(rèn)情況下薄辅,導(dǎo)出未在當(dāng)前模塊范圍中聲明的標(biāo)識(shí)符將引發(fā)錯(cuò)誤刁赖。雖然ECMAScript
模塊規(guī)范要求這種行為,但是 Babel 的解析器無(wú)法預(yù)測(cè)插件管道中稍后可能插入適當(dāng)聲明的轉(zhuǎn)換长搀,因此,有時(shí)必須將此選項(xiàng)設(shè)置為 true鸡典,以防止解析器過(guò)早地抱怨稍后將添加的未聲明的導(dǎo)出源请。createParenthesizedExpressions
: 默認(rèn)情況下,解析器設(shè)置extra.parenthesized
在表達(dá)式節(jié)點(diǎn)上彻况。當(dāng)此選項(xiàng)設(shè)置為 true 時(shí)谁尸,將創(chuàng)建ParenthesizedExpression
(圓括號(hào)) AST節(jié)點(diǎn)。errorRecovery
: 默認(rèn)情況下纽甘,Babel總是在發(fā)現(xiàn)一些無(wú)效代碼時(shí)拋出一個(gè)錯(cuò)誤良蛮。當(dāng)此選項(xiàng)設(shè)置為 true 時(shí),它將存儲(chǔ)解析錯(cuò)誤并嘗試?yán)^續(xù)解析無(wú)效的輸入文件悍赢。生成的AST
將有一個(gè)errors屬性决瞳,表示所有解析錯(cuò)誤的數(shù)組。請(qǐng)注意左权,即使啟用了此選項(xiàng)皮胡,@babel/parser也可能拋出不可恢復(fù)的錯(cuò)誤。plugins
: 包含要啟用的插件的數(shù)組赏迟。sourceType
: 指示分析代碼的模式屡贺。可以是"script"
,"module"
或"unambiguous"
之一。默認(rèn)為"script"
甩栈。"unambiguous"
將使 @babel/parser嘗試根據(jù)存在的 ES6 導(dǎo)入或?qū)С稣Z(yǔ)句進(jìn)行猜測(cè)泻仙。帶有ES6 import
和export
的文件被視為"module"
,否則是"script"
量没。sourceFilename
: 將輸出AST
節(jié)點(diǎn)與其源文件名關(guān)聯(lián)玉转。從多個(gè)輸入文件的AST 生成代碼和源映射時(shí)非常有用。startLine
: 默認(rèn)情況下允蜈,被解析的第一行代碼被視為第1行冤吨。您可以提供一個(gè)行號(hào)作為替代。有助于與其他源工具集成饶套。strictMode
: 默認(rèn)情況下漩蟆,只有在存在“use strict”
;指令或解析的文件是ECMAScript
模塊時(shí)妓蛮,ECMAScript 代碼才會(huì)被解析為 strict怠李。將此選項(xiàng)設(shè)置為true可始終以嚴(yán)格模式解析文件。ranges
: 向每個(gè)節(jié)點(diǎn)添加range
屬性:[node.start, node.end]
tokens
: 將所有解析的令牌添加到File
節(jié)點(diǎn)上的tokens
屬性
遍歷修改
使用 @babel/traverse
遍歷解析過(guò)的代碼蛤克,并在此基礎(chǔ)上進(jìn)行修改捺癞。
traverse(ast, visitors)
ast
: parser 解析的代碼,visitors: 特定節(jié)點(diǎn)操作
traverse(ast, {
CallExpression(p) {
// 對(duì)語(yǔ)法樹(shù)中特定的節(jié)點(diǎn)進(jìn)行操作 參考@babel/types (特定節(jié)點(diǎn)類型)
// CallExpression 特定節(jié)點(diǎn)
},
FunctionDeclaration: function(path) {
// 對(duì)語(yǔ)法樹(shù)中特定的節(jié)點(diǎn)進(jìn)行操作 參考@babel/types (特定節(jié)點(diǎn)類型)
// FunctionDeclaration 特定節(jié)點(diǎn)
}
})
生成代碼
使用 @babel/generator
將修改過(guò)的 ast
重新生成代碼构挤。
generate(ast, [opts], [code]);
ast
: 修改過(guò)的抽象語(yǔ)法樹(shù)髓介,options: 配置信息,code: 原始代碼筋现,用于映射
opts
選項(xiàng)如下:
auxiliaryCommentBefore
作為塊注釋添加到輸出文件開(kāi)頭的可選字符串auxiliaryCommentAfter
在文件的結(jié)尾添加可選的字符串作為注釋shouldPrintComment
類型:function唐础,默認(rèn)值:opts.comments。該函數(shù)接受注釋(作為字符串)并在輸出中包含注釋時(shí)返回 true矾飞。默認(rèn)情況下一膨,注釋是被包含的。如果 opts.comments:true 或者opts.minified:false洒沦,并且注釋包含@preserve 或 @licenseretainLines
類型:boolean豹绪,默認(rèn)值:false。嘗試在輸出代碼中使用與源代碼相同的行號(hào)(有助于保留堆棧跟蹤)retainFunctionParens
類型:boolean申眼,默認(rèn)值:false瞒津。保留函數(shù)表達(dá)式周圍的 parens(可用于更改引擎解析行為)comments
類型:boolean,默認(rèn)值:true括尸。輸出中是否應(yīng)包含注釋compact
類型:boolean or 'auto'仲智,默認(rèn)值:opts.minified。設(shè)置為 true 以避免為格式添加空白minified
類型:boolean姻氨,默認(rèn)值:false钓辆。確定是否縮小輸出concise
類型:boolean,默認(rèn)值:false。設(shè)置為true以減少空白(但不如選擇緊湊型)filename
用于警告消息jsonCompatibleStrings
類型:boolean前联,默認(rèn)值:false功戚。設(shè)置為 true 以使用“json”運(yùn)行 jsesc:true 將打印“\u00A9”。sourceMaps
類型:boolean似嗤,默認(rèn)值:false啸臀。啟用生成源映射sourceRoot
源映射中所有相對(duì)URL的根sourceFileName
源代碼的文件名(即code參數(shù)中的代碼)。僅當(dāng)代碼是字符串時(shí)才使用此選項(xiàng)烁落。
寫(xiě)回文件
使用 fs-extra
將重新生成的代碼寫(xiě)回文件乘粒。
fs.writeFileSync(dir, code);
dir
: 文件目錄,code
: 代碼
總結(jié)
通過(guò) fs-extra
和 babel
相關(guān)插件我們可以很愉快地進(jìn)行文件的創(chuàng)建伤塌,代碼的修改灯萍,當(dāng)然也不止適用于這一種情況,還有很多無(wú)限的可能等著我們?nèi)?shí)現(xiàn)每聪。