组件按需引入
安装插件babel-plugin-component,引入需要的组件,以达到降低项目体积。
目的
一般的组件引入的方式:import Button from “../UI/packages/button”
想要达成的引入方式:import {Button} from “../UI”
措施
前置知识babel-plugin-component插件
babel-plugin-component通过修改引入代码对应的AST树来达到极简的引入组件的目的
import { Alert } from 'xui'对应的AST树
1.首先在babel.config.js同级新增一个babel-plugin-component.js文件,作为我们插件文件,然后修改一下babel.config.js文件:
module.exports =
{ *// ...*
plugins: ['./babel-plugin-component.js'] }
复制代码
2.我们就是要修改babel.config.js使得import { Alert } from 'xui'对应的AST树转化成import {Alert from 'xui/packages/alert'对应的AST树。
通过观察import { Alert } from 'xui'代码对应的AST树,我们发现整体是一个importDeclaration,通过source.value判断导入的来源,specifiers数组可以找到导入的变量,每个变量是一个ImportSpecifier。根据这些信息,我们只需要修改source.value导入的来源,并修改specifiers.imported.name导入的组件名,就可以实现极简地引入组件。
3.目标明确后,得到代码
// babel-plugin-component.js
module.exports = ({
types
}) => {
return {
//Babel采用递归的方式访问所有的AST结点
visitor: {
//每个AST结点都有对应的节点类型,如Identifier(标识符),FunctionDeclaration(函数声明)
//一旦访问到相同类型的结点触发事件。通过path可以代表该结点的属性与该结点的相邻结点
//state代表插件的状态
ImportDeclaration(path) {
const {
node
} = path
// path是类型为ImportDeclaration的AST结点
const {
value
} = node.source // node.source是导入的来源
if (value === '../UI') {
// 找出引入的组件名称列表
let specifiersList = []
// specifiers数组里可以找到导入的变量,每个变量是一个ImportSpecifier
node.specifiers.forEach(spec => {
if (types.isImportSpecifier(spec)) {
if(spec.imported.name.toLowerCase()==='ui'){
return types.importDeclaration([
types.importDefaultSpecifier(types.identifier(spec.imported.name))
], types.stringLiteral('../UI')) //stringLiteral字符串字面量,@babel/types负责babel转换的步骤,对结点进行增删改
}
specifiersList.push(spec.imported.name)
//spec.imported.name是组件导入的名称,spec.local.name作为组件的别名
}
})
// 给每个组件创建一条导入语句
const importDeclarationList = specifiersList.map((name) => {
// 文件夹的名称首字母为小写
let lowerCaseName = name.toLowerCase();
// 构造importDeclaration节点
return types.importDeclaration([
types.importDefaultSpecifier(types.identifier(name))
], types.stringLiteral('../UI/packages/' + lowerCaseName))
})
// 用多节点替换单节点
path.replaceWithMultiple(importDeclarationList)
}
}
},
}
}
复制代码
在自己的项目中,需要改动if (value === 'xui')和types.stringLiteral('xui/packages/' + lowerCaseName))两段代码。改成自己项目的组件路径即可。
babel的处理步骤
主要有三个阶段:解析(parse), 转换 (transform),生成(generate)。
-
parse
将源码转成 AST,用到@babel/parser模块。
-
transform
对AST 进行遍历,在此过程中对节点进行添加、更新及移除等操作。因此这是bebel处理代码的核心步骤,是我们的讨论重点,主要使用@babel/traverse和@babel/types模块。
-
generate
打印 AST 成目标代码并生成 sourcemap,用到@babel/generate模块。






![[Spring]AnnotationAwareAspectJAutoProxyCreator-@AspectJ的解析器-一一网](https://www.proyy.com/skycj/data/images/2021-04-24/62b0b3de6af92d8fb255ba0b095c4c4e.jpg)

















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)