We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
今天是暗恋她的第90天,但马上就要失恋了
因为组织架构变动,要换到一个离她很远的地方
暗恋她的90天里,一直在997
每天都在跟同类互相残杀
我厌倦了和一群老男人加班的日子
她是这段黑暗时间里,唯一的光
她曾是年会的女主持
万千男人暗恋的女神,而我只是个加班狗
她身边都是鲜花和掌声
我身边全是抠脚大汉和LSP
我配不上她,但却又被她深深的吸引
结婚7年来,我每天下班就回家
不抽烟不喝酒不近女色
腾讯男德第一人
居然对她产生了情愫
本以为我很专一,遇见她以后才明白
原来男人真的可以同时爱上好几个女人
离别之前,不知道要不要跟她表白
如果表白,她一定会说我是个好人
如果自己长的再好看点,是不是就不用自卑了
可惜没有如果,我是个完美的垃圾
就这样心烦意乱的上线了一版代码,配置文件还修改错了
直接崩出线上大bug
所有网页全部 404 not found
1000封报警邮件狂轰滥炸
boss委婉的发来1星绩效的暗示
都要哭了
配置文件这种东西,人工去修改,太容易受情绪影响而改错了
这些重复且易出错的操作,应该用工程化、自动化手段去解决
完整代码参考:github。
像那些js配置文件,里面可能有很多的非配置代码,而且一次可能要修改好几个文件
比如我们在前端项目,要插入一个页面,需要修改router、menus等配置文件,还要手动拷贝页面模板等等
这些高重复机械化操作,人工修改非常容易出错
我们可以直接用babel来操作AST抽象语法树,通过工程化去精准修改。让babel去帮我们找到指定位置,并正确插入配置代码。我们在做工程化开发的时候,经常会用到babel去操作AST。
首先我们了解一下什么是AST
AST,抽象语法树(Abstract Syntax Tree)它是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构。
我们使用babel来转化和操作AST,主要分为三个步骤:解析(parser)、转换(traverse)、生成(generator)
如下图,如果我们想通过babel,在配置文件里面插入一段配置代码,应该怎么实现呢
第一步:读取配置文件代码,并生成AST抽象语法树
let configJsData = fs.readFileSync(configJsPath, "utf8");
然后将配置文件代码生成AST抽象语法树
const parser = require("@babel/parser"); let configJsTree = parser.parse(`${configJsData}`,{ sourceType: "module", plugins: [ "jsx", "flow", ], });
configJsTree就是我们的AST了
加上sourceType: "module"这个配置属性,是为了让babel支持解析export和import
sourceType: "module"
转换(traverse)阶段,就是要遍历整个AST抽象语法树,找到指定的位置,然后插入对应的配置代码。
代码如下:
const traverse = require("@babel/traverse").default; traverse(configJsTree, { ObjectProperty(path) { // 插入配置文件代码 }, });
我们使用@babel/traverse的traverse方法进行遍历整个AST
@babel/traverse
其中ObjectProperty的作用是在遍历AST过程中,识别出所有的Object对象,因为我们是要将配置代码插入一个Object对象,所以使用的是ObjectProperty。如果要将配置插入数组中,就使用ArrayExpression。
ObjectProperty
ArrayExpression
然后我们开始进行配置代码的插入,将代码
{ key: "testPath", icon: HomeOutlined, exact: true, }
插入如下的位置
我们需要在traverse的ObjectProperty进行位置的查找和代码插入
traverse
首先我们要找到key: 'home'的位置
key: 'home'
traverse(configJsTree, { ObjectProperty(path) { if ( path.node.key.name === "key" && path.node.value.value === "home" ) { // 这就是 key: 'home'的位置 } }, });
通过path.node.key.name和path.node.value.value找到对象属性为key并且对象值为home的Object对象
path.node.key.name
path.node.value.value
key
home
找到位置后开始插入代码
traverse(configJsTree, { ObjectProperty(path) { // 搜索并识别出配置文件里key: "home" 这个object对象位置 if ( path.node.key.name === "key" && path.node.value.value === "home" ) { path.parent.properties.forEach(e=>{ if ( e.key.name === "children" ) { // 找到children属性 } }) } }, });
通过path.parent.properties找到对象的父级,然后遍历父级下的所有属性,找到children这个属性。这就是我们要插入的位置。
path.parent.properties
children
接下来我们要构造要插入的数据
构造数据的代码如下:
const t = require("@babel/types"); const newObj = t.objectExpression([ t.objectProperty( t.identifier("key"), t.stringLiteral("testPath") ), t.objectProperty( t.identifier("icon"), t.identifier("HomeOutlined") ), t.objectProperty( t.identifier("exact"), t.booleanLiteral(true) ), ]);
可以看到用dentifier来标识对象的属性,用stringLiteral标识字符串数据,booleanLiteral标识boolean值,这些类型都可以在@babel/types查询到。
dentifier
stringLiteral
booleanLiteral
@babel/types
最后一步,将构造好的数据插入:
e.value.elements.push(newObj)
完成~!
将所有 traverse 阶段代码汇总起来如下:
const traverse = require("@babel/traverse").default; const t = require("@babel/types"); traverse(configJsTree, { ObjectProperty(path) { // 搜索并识别出配置文件里key: "home" 这个object对象位置 if ( path.node.key.name === "key" && path.node.value.value === "home" ) { path.parent.properties.forEach(e=>{ if ( e.key.name === "children" ) { const newObj = t.objectExpression([ t.objectProperty( t.identifier("key"), t.stringLiteral("testPath") ), t.objectProperty( t.identifier("icon"), t.identifier("HomeOutlined") ), t.objectProperty( t.identifier("exact"), t.booleanLiteral(true) ), ]); e.value.elements.push(newObj) } }) } }, });
这个阶段就是把AST抽象语法树反解,生成我们常规的代码
const generate = require("@babel/generator").default; const result = generate(configJsTree, { jsescOption: { minimal: true } }, "").code; fs.writeFileSync(resultPath, result);
通过@babel/generator将AST抽象代码语法树反解回原代码,jsescOption: { minimal: true }配置是为了解决中文为unicode乱码的问题。
@babel/generator
jsescOption: { minimal: true }
至此咱们就完成了对js配置文件插入代码,最终结果如下:
以上就是通过babel操作AST,然后精准插入配置代码的全流程,完整代码参考:github。
线上一切都稳定后
回头看了下女神
她正在照镜子涂口红
就静静坐着,都好喜欢好喜欢
她很爱笑、每周三都会去打篮球,早上10:30准时到公司、喜欢咖啡和奶茶
她的生活每天都是一首歌
而我只会敲代码,加班加到腿抽筋
据线人说,她已经有男朋友了,又高又帅又有钱
而我又老又丑、不仅穷还秃
听说她还很年轻,而我已经32
还有不到3年就35岁,我的时间不多了
怎么能留恋世间烟火呢
女人只会影响我敲代码的速度
哎。。。真该死
我还是默默地守护她、支持她、欣赏她吧
不打搅是屌丝最高级的告白
只是可惜的是
至始至终,我都不知道她叫什么
我们从没说过一句话
都是我一个人的独角戏
鲁迅说过:“我知道妳不是我的花,但能途经妳的盛放,我不胜荣幸”
。。。。。。
深夜空无一人的总部大楼
就这样默默坐在彼此的身边
就当我们也曾经在一起过吧
这次离别,可能就再也见不到了
不知道妳会不会想起我
也不知道我会不会爱上别的女孩
但是还是谢谢妳
惊艳了我每个加班的夜晚
goodbye my lover
————— yours 小蝌蚪
The text was updated successfully, but these errors were encountered:
No branches or pull requests
今天是暗恋她的第90天,但马上就要失恋了
因为组织架构变动,要换到一个离她很远的地方
暗恋她的90天里,一直在997
每天都在跟同类互相残杀
我厌倦了和一群老男人加班的日子
她是这段黑暗时间里,唯一的光
她曾是年会的女主持
万千男人暗恋的女神,而我只是个加班狗
她身边都是鲜花和掌声
我身边全是抠脚大汉和LSP
我配不上她,但却又被她深深的吸引
结婚7年来,我每天下班就回家
不抽烟不喝酒不近女色
腾讯男德第一人
居然对她产生了情愫
本以为我很专一,遇见她以后才明白
原来男人真的可以同时爱上好几个女人
离别之前,不知道要不要跟她表白
如果表白,她一定会说我是个好人
如果自己长的再好看点,是不是就不用自卑了
可惜没有如果,我是个完美的垃圾
就这样心烦意乱的上线了一版代码,配置文件还修改错了
直接崩出线上大bug
所有网页全部 404 not found
1000封报警邮件狂轰滥炸
boss委婉的发来1星绩效的暗示
都要哭了
配置文件这种东西,人工去修改,太容易受情绪影响而改错了
这些重复且易出错的操作,应该用工程化、自动化手段去解决
babel修改js配置文件实现原理
完整代码参考:github。
像那些js配置文件,里面可能有很多的非配置代码,而且一次可能要修改好几个文件
比如我们在前端项目,要插入一个页面,需要修改router、menus等配置文件,还要手动拷贝页面模板等等
这些高重复机械化操作,人工修改非常容易出错
我们可以直接用babel来操作AST抽象语法树,通过工程化去精准修改。让babel去帮我们找到指定位置,并正确插入配置代码。我们在做工程化开发的时候,经常会用到babel去操作AST。
首先我们了解一下什么是AST
AST,抽象语法树(Abstract Syntax Tree)它是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构。
我们使用babel来转化和操作AST,主要分为三个步骤:解析(parser)、转换(traverse)、生成(generator)
操作AST三大阶段
如下图,如果我们想通过babel,在配置文件里面插入一段配置代码,应该怎么实现呢
解析(parser)
第一步:读取配置文件代码,并生成AST抽象语法树
然后将配置文件代码生成AST抽象语法树
configJsTree就是我们的AST了
加上
sourceType: "module"
这个配置属性,是为了让babel支持解析export和import转换(traverse)
转换(traverse)阶段,就是要遍历整个AST抽象语法树,找到指定的位置,然后插入对应的配置代码。
代码如下:
我们使用
@babel/traverse
的traverse方法进行遍历整个AST其中
ObjectProperty
的作用是在遍历AST过程中,识别出所有的Object对象,因为我们是要将配置代码插入一个Object对象,所以使用的是ObjectProperty
。如果要将配置插入数组中,就使用ArrayExpression
。然后我们开始进行配置代码的插入,将代码
插入如下的位置
我们需要在
traverse
的ObjectProperty
进行位置的查找和代码插入首先我们要找到
key: 'home'
的位置代码如下:
通过
path.node.key.name
和path.node.value.value
找到对象属性为key
并且对象值为home
的Object对象找到位置后开始插入代码
通过
path.parent.properties
找到对象的父级,然后遍历父级下的所有属性,找到children
这个属性。这就是我们要插入的位置。接下来我们要构造要插入的数据
构造数据的代码如下:
可以看到用
dentifier
来标识对象的属性,用stringLiteral
标识字符串数据,booleanLiteral
标识boolean值,这些类型都可以在@babel/types
查询到。最后一步,将构造好的数据插入:
完成~!
将所有 traverse 阶段代码汇总起来如下:
生成(generator)
这个阶段就是把AST抽象语法树反解,生成我们常规的代码
通过
@babel/generator
将AST抽象代码语法树反解回原代码,jsescOption: { minimal: true }
配置是为了解决中文为unicode乱码的问题。至此咱们就完成了对js配置文件插入代码,最终结果如下:
以上就是通过babel操作AST,然后精准插入配置代码的全流程,完整代码参考:github。
结尾
结尾
线上一切都稳定后
回头看了下女神
她正在照镜子涂口红
就静静坐着,都好喜欢好喜欢
她很爱笑、每周三都会去打篮球,早上10:30准时到公司、喜欢咖啡和奶茶
她的生活每天都是一首歌
而我只会敲代码,加班加到腿抽筋
据线人说,她已经有男朋友了,又高又帅又有钱
而我又老又丑、不仅穷还秃
听说她还很年轻,而我已经32
还有不到3年就35岁,我的时间不多了
怎么能留恋世间烟火呢
女人只会影响我敲代码的速度
哎。。。真该死
我还是默默地守护她、支持她、欣赏她吧
不打搅是屌丝最高级的告白
只是可惜的是
至始至终,我都不知道她叫什么
我们从没说过一句话
都是我一个人的独角戏
鲁迅说过:“我知道妳不是我的花,但能途经妳的盛放,我不胜荣幸”
。。。。。。
深夜空无一人的总部大楼
就这样默默坐在彼此的身边
就当我们也曾经在一起过吧
这次离别,可能就再也见不到了
不知道妳会不会想起我
也不知道我会不会爱上别的女孩
但是还是谢谢妳
惊艳了我每个加班的夜晚
goodbye my lover
————— yours 小蝌蚪
The text was updated successfully, but these errors were encountered: