前端开发过程当中,总会有一些机械重复的工作要做,比如:新建文件夹,新建一个 ts 文件,新建一个样式文件,向已有的菜单文件中增加新建的文件,初始化等等。这些繁复的工作虽然不复杂,但仍需要占用大量的时间,有没有除了手动添加外其它的方法呢?
答案是有的。
初始化
对于创建文件之类的,我们可以使用 fs-extra 来解决,初始化的文件我们只需要传入一段已写好的 js
就好。
fs-extra
: 文件操作相关工具库,是系统fs
模块的扩展,提供了更多便利的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
。
追加文件
我们想要追加文件的话大概需要如何几个步骤:
读取文件
解析文件
遍历修改
生成代码
写回文件
读取文件
使用上面的 fs-extra
读取文件,方法如下:
fs.readFileSync(dir, format)
dir
: 读取文件的路径,format
: 编码格式
解析文件
使用 @babel/parser
解析文件
babelParser.parse(code, [options])
babelParser.parseExpression(code, [options])
parse
将提供的代码作为一个完整的ECMAScript
程序进行解析,而parseExpression
则尝试解析单个表达式并考虑性能。code
: 刚刚读取的代码,options
: 配置信息
options
选项如下:
allowImportExportEverywhere
: 默认情况下,import
和export
声明只能出现在程序的顶层。如果将此选项设置为true
,则允许在任何允许使用语句的地方使用它们。allowAwaitOutsideFunction
: 默认情况下,只允许在异步函数内部使用 await,或者在启用topLevelAwait
插件时,允许在模块的顶层作用域中使用await。将其设置为true,以便在脚本的顶级范围中也接受它。allowReturnOutsideFunction
: 默认情况下,顶层的 return 语句会引发错误。将此设置为 true 以接受此类代码。allowSuperOutsideMethod
: 默认情况下,在类和对象方法之外不允许 super 使用。将此设置为 true 以接受此类代码。allowUndeclaredExports
: 默认情况下,导出未在当前模块范围中声明的标识符将引发错误。虽然ECMAScript
模块规范要求这种行为,但是 Babel 的解析器无法预测插件管道中稍后可能插入适当声明的转换,因此,有时必须将此选项设置为 true,以防止解析器过早地抱怨稍后将添加的未声明的导出。createParenthesizedExpressions
: 默认情况下,解析器设置extra.parenthesized
在表达式节点上。当此选项设置为 true 时,将创建ParenthesizedExpression
(圆括号) AST节点。errorRecovery
: 默认情况下,Babel总是在发现一些无效代码时抛出一个错误。当此选项设置为 true 时,它将存储解析错误并尝试继续解析无效的输入文件。生成的AST
将有一个errors属性,表示所有解析错误的数组。请注意,即使启用了此选项,@babel/parser也可能抛出不可恢复的错误。plugins
: 包含要启用的插件的数组。sourceType
: 指示分析代码的模式。可以是"script"
,"module"
或"unambiguous"
之一。默认为"script"
。"unambiguous"
将使 @babel/parser尝试根据存在的 ES6 导入或导出语句进行猜测。带有ES6 import
和export
的文件被视为"module"
,否则是"script"
。sourceFilename
: 将输出AST
节点与其源文件名关联。从多个输入文件的AST 生成代码和源映射时非常有用。startLine
: 默认情况下,被解析的第一行代码被视为第1行。您可以提供一个行号作为替代。有助于与其他源工具集成。strictMode
: 默认情况下,只有在存在“use strict”
;指令或解析的文件是ECMAScript
模块时,ECMAScript 代码才会被解析为 strict。将此选项设置为true可始终以严格模式解析文件。ranges
: 向每个节点添加range
属性:[node.start, node.end]
tokens
: 将所有解析的令牌添加到File
节点上的tokens
属性
遍历修改
使用 @babel/traverse
遍历解析过的代码,并在此基础上进行修改。
traverse(ast, visitors)
ast
: parser 解析的代码,visitors: 特定节点操作
traverse(ast, {
CallExpression(p) {
// 对语法树中特定的节点进行操作 参考@babel/types (特定节点类型)
// CallExpression 特定节点
},
FunctionDeclaration: function(path) {
// 对语法树中特定的节点进行操作 参考@babel/types (特定节点类型)
// FunctionDeclaration 特定节点
}
})
生成代码
使用 @babel/generator
将修改过的 ast
重新生成代码。
generate(ast, [opts], [code]);
ast
: 修改过的抽象语法树,options: 配置信息,code: 原始代码,用于映射
opts
选项如下:
auxiliaryCommentBefore
作为块注释添加到输出文件开头的可选字符串auxiliaryCommentAfter
在文件的结尾添加可选的字符串作为注释shouldPrintComment
类型:function,默认值:opts.comments。该函数接受注释(作为字符串)并在输出中包含注释时返回 true。默认情况下,注释是被包含的。如果 opts.comments:true 或者opts.minified:false,并且注释包含@preserve 或 @licenseretainLines
类型:boolean,默认值:false。尝试在输出代码中使用与源代码相同的行号(有助于保留堆栈跟踪)retainFunctionParens
类型:boolean,默认值:false。保留函数表达式周围的 parens(可用于更改引擎解析行为)comments
类型:boolean,默认值:true。输出中是否应包含注释compact
类型:boolean or 'auto',默认值:opts.minified。设置为 true 以避免为格式添加空白minified
类型:boolean,默认值:false。确定是否缩小输出concise
类型:boolean,默认值:false。设置为true以减少空白(但不如选择紧凑型)filename
用于警告消息jsonCompatibleStrings
类型:boolean,默认值:false。设置为 true 以使用“json”运行 jsesc:true 将打印“\u00A9”。sourceMaps
类型:boolean,默认值:false。启用生成源映射sourceRoot
源映射中所有相对URL的根sourceFileName
源代码的文件名(即code参数中的代码)。仅当代码是字符串时才使用此选项。
写回文件
使用 fs-extra
将重新生成的代码写回文件。
fs.writeFileSync(dir, code);
dir
: 文件目录,code
: 代码
总结
通过 fs-extra
和 babel
相关插件我们可以很愉快地进行文件的创建,代码的修改,当然也不止适用于这一种情况,还有很多无限的可能等着我们去实现。