JavaScript 是一门编译型语言。
AST/Babel/依赖
bable的原理
- parse 把代码code变成AST(Abstract Syntax Tree:什么是抽象语法树)
- traverser遍历AST进行修改
- generate:把AST变成代码code2
即 原代码 --(1)-> ast ---(2)->ast--(3)->code(2)
示例(将let 变成var)
import { parse } from '@babel/parser'
import traverse from '@babel/traverse'
import generate from '@babel/generator'
const code = `let a = 'let';let b = 2`
const ast = parse(code, { sourceType: 'module' })
traverse(ast, {
enter: (item) => {
if (item.node.type === 'VariableDeclaration') {
if (item.node.kind === 'let') {
item.node.kind = 'var'
}
}
}
})
const result = generate(ast, {}, code)
console.log(result.code)
//输出
//var a = 'let';
//var b = 2;
将ES6转换成ES5
import { parse } from '@babel/parser'
import * as babel from '@babel/core'
import * as fs from 'fs'
const code = `let a = 'let'; let b = 2; const c = 3`
const ast = parse(code, { sourceType: 'module' })
const result = babel.transformFromAstAsync(ast, code, {
presets: ['@babel/preset-env']
})
result.then(res => {
fs.writeFileSync('./test.es5.js', res.code)
})
依赖分析
// 请确保你的 Node 版本大于等于 14
// 请先运行 yarn 或 npm i 来安装依赖
// 然后使用 node -r ts-node/register 文件路径 来运行,
// 如果需要调试,可以加一个选项 --inspect-brk,再打开 Chrome 开发者工具,点击 Node 图标即可调试
import { parse } from "@babel/parser"
import traverse from "@babel/traverse"
import { readFileSync } from 'fs'
import { resolve, relative, dirname } from 'path';
// 设置根目录
const projectRoot = resolve(__dirname, 'project_1')
// 类型声明
type DepRelation = { [key: string]: { deps: string[], code: string } }
// 初始化一个空的 depRelation,用于收集依赖
const depRelation: DepRelation = {}
function getProjectPath(path: string) {
return relative(projectRoot, path).replace(/\\/g, '/')
}
function collectCodeAndDeps(filepath: string) {
const key = getProjectPath(filepath) // 文件的项目路径,如 index.js
// 获取文件内容,将内容放至 depRelation
const code = readFileSync(filepath).toString()
// 初始化 depRelation[key]
depRelation[key] = { deps: [], code: code }
// 将代码转为 AST
const ast = parse(code, { sourceType: 'module' })
// 分析文件依赖,将内容放至 depRelation
traverse(ast, {
enter: path => {
if (path.node.type === 'ImportDeclaration') {
// path.node.source.value 往往是一个相对路径,如 ./a.js,需要先把它转为一个绝对路径
const depAbsolutePath = resolve(dirname(filepath), path.node.source.value)
// 然后转为项目路径
const depProjectPath = getProjectPath(depAbsolutePath)
// 把依赖写进 depRelation
depRelation[key].deps.push(depProjectPath)
}
}
})
}
// 将入口文件的绝对路径传入函数,如 D:\demo\fixture_1\index.js
collectCodeAndDeps(resolve(projectRoot, 'index.js'))
console.log('depRelation')
console.log(depRelation)
用递归进行嵌套依赖分析
//其他代码同上,在collectCodeAndDeps中调用自己即可!缺点:如果太深会导致
function collectCodeAndDeps(filepath: string) {
traverse(ast, {
enter: path => {
if (path.node.type === 'ImportDeclaration') {
...
depRelation[key].deps.push(depProjectPath)
collectCodeAndDeps(depAbsolutePath)
}
}
})
}
避免循环依赖
if (Object.keys(depRelation).includes(key)) {
console.warn(`duplicated dependency:${key}`)
return
}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!