如何向 js 文件中插入一段代码?

前端开发过程当中,总会有一些机械重复的工作要做,比如:新建文件夹,新建一个 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

Sync

那么如何向已有文件追加呢?

答:我们可以考虑使用 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: 默认情况下,importexport声明只能出现在程序的顶层。如果将此选项设置为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 importexport的文件被视为"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 或 @license

  • retainLines 类型: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-extrababel 相关插件我们可以很愉快地进行文件的创建,代码的修改,当然也不止适用于这一种情况,还有很多无限的可能等着我们去实现。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

友情链接更多精彩内容