使用babel-plugin-import 实现自动按需引入方式
作者:swx980 发布时间:2024-04-27 16:00:42
babel-plugin-import 实现自动按需引入
Vant 支持一次性导入所有组件,引入所有组件会增加代码包体积,因此不推荐这种做法
babel-plugin-import 是一款 babel 插件,它会在编译过程中将 import 的写法自动转换为按需引入的方式。
1、下载
npm i babel-plugin-import -D
2、
(1)在.babelrc 中添加配置
注意:webpack 1 无需设置 libraryDirectory
{
"plugins": [
["import", {
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}]
]
}
(2)对于使用 babel7 的用户,可以在 babel.config.js 中配置
module.exports = {
plugins: [
['import', {
libraryName: 'vant',
libraryDirectory: 'es',
style: true
}, 'vant']
]
};
3、接着你可以在代码中直接引入 Vant 组件,插件会自动将代码转化为方式二中的按需引入形式
import { Button } from 'vant';
babel-plugin-import 的组件按需加载原理
对比webpack懒加载
webpack 懒加载是将源码中的 import、require 引入的文件编译之后再根据动态加载语法配置(通常以页面路由为基本单位)将较大的代码拆分并构建出较小的 chunk 包,运行时执行到相应业务逻辑时才去加载执行对应 chunk 代码。
webpack 懒加载主要发生在 JS 拆分出不同的 Chunk 这一过程中。
babel-plugin-import 按需加载是以组件为基本单位产出 js、css、less 文件,借助插件或者部分引入的写法,使得项目代码或 babel 编译后的代码中只包含使用到的组件的 js、css、less 等。
首先是执行时机不同,babel-plugin-import 按需加载是在源码编写阶段或者 babel 编译 js 阶段,而 webpack 懒加载则是在构建生成打包产物阶段。
其次是原理不同,babel-plugin-import 按需加载是在源码阶段就去掉了无关代码,而 webpack 懒加载则是将经过 tree-shaking 优化过后的大文件包进行拆分在适当的运行时进行按需加载。两者并不冲突,可以一前一后共同作用。
实现原理
babel-plugin-import 按需加载目的是减少项目构建打包产物的大小,提高项目线上首屏渲染速度,减少白屏时间,减少流量消耗。
若是采用手动引入需要使用到的组件以及其对应的样式文件,那么在 webpack 构件时组件库中其他未被引入的文件不会被打包。
import Button from 'lib/button';
import 'lib/lib/button/style';
若是自动引入:
npm i babel-plugin-import -D
module.exports = {
plugins: [
['import', {
libraryName,
libraryDirectory: 'es',
style: true
}, libraryName]
]
};
import { Button } from libraryName;
组件其实就是对一堆 js、css 以及 less 等文件的总称,自动引入的本质是将引入组件的写法通过插件来转换成手动引入组件对应的代码以及样式文件的写法。核心原理依然是对源码的 import 导入写法进行转换——词法语法分析,AST转换,代码生成。
该插件主要参数:
"libraryName": "", // 组件库名称,对应 import 语法中的包名
"libraryDirectory": "lib", // 编译之后各个组件单元所在文件夹名称
"style": true, // 是否引入组件对应样式文件,也可以传入 less 来引入 less 文件
"styleLibraryDirectory": "", // 编译之后引入的组件样式文件所在文件夹名称
"camel2DashComponentName": false, // 是否将驼峰命名的导入变量转换为对应的横线连接命名的文件名
"customName": (name, file) => { return `/lib/${name}` }, // 自定义编译之后引入的组件名
"customStyleName": (name, file) => { return `/lib/css/${name}` }, // 自定义编译之后引入样式文件的名称
插件中使用到的钩子函数有:
const methods = [
'ImportDeclaration', // import 导入声明
'CallExpression', // 函数调用
'MemberExpression',
'Property',
'VariableDeclarator',
'ArrayExpression',
'LogicalExpression',
'ConditionalExpression',
'IfStatement',
'ExpressionStatement',
'ReturnStatement',
'ExportDefaultDeclaration',
'BinaryExpression',
'NewExpression',
'ClassDeclaration',
'SwitchStatement',
'SwitchCase',
];
Visitor 对象上还配置了 Program 钩子,该钩子是在 babel 处理一个独立文件(或者叫做模块更合适,node 规范定义一个文件就是一个模块)时执行,其中若不按此方式具体指定则默认为 enter 钩子。
const Program = {
// 进入钩子
enter(path, options) {
// 1. 根据插件接受到的配置参数初始化插件 Plugin 数组
// 2. 遍历插件 Plugin 数组,依次执行各个插件的初始化方法 ProgramEnter
},
// 退出钩子
exit() {
// ...
}
}
转换 import 语法需要识别 ES6 模块规范的默认导入、部分导入以及整体导入等语法,主要逻辑包括鉴别是否是部分导入,只有部分导入才表示导入具体组件,转换导入变量名等。
// 1. 部分导入
import { Button } from '';
console.log(Button);
// 2. 默认导入
import default from '';
console.log(default.Button);
// 3. 全部导入
import * as D from '';
console.log(D.Button);
整体处理逻辑如下:
ImportDeclaration 钩子中将部分导入、默认导入和整体导入的语句记录到插件全局状态对象上,同时将节点的 path 对象记录至插件全局状态对象上;
插件全局状态对象上存储的 path 对象会在 Program 退出时遍历执行 remove 方法,从而移除了所有原始的导入语句;
在 MemberExpression、CallExpression、buildExpressionHandler、buildDeclaratorHandler等钩子函数中执行 importMethod 函数;
importMethod 函数会根据插件的配置参数计算出真实文件导入路径、是否导入样式文件、样式文件名、是否转换默认导入等配置,从而使用 @babel/helper-module-imports 提供的 addSideEffect 方法添加对应的部分导入语句。
重命名导入模块的变量描述符 Identifier。
以钩子函数为入口,根据不同的节点类型取找到不同节点与变量相关的属性;
校验变量的 name 是否存在于插件全局状态的 specfied 中,即变量是否是导入组件指向的变量;
通过 path.scope.hasBinding、path.scope.getBinding 排除掉其他作用域的变量;
借助 importMethod 方法计算转换后模块对应的变量名然后修改节点对应的变量名。
变量描述符 Identifier可能指向的钩子有:
Property
VariableDeclarator
ArrayExpression
LogicalExpression
ConditionalExpression
IfStatement
ExpressionStatement
ReturnStatement
ExportDefaultDeclaration
BinaryExpression
NewExpression
SwitchStatement
SwitchCase
ClassDeclaration
来源:https://blog.csdn.net/swx999/article/details/113174216


猜你喜欢
- 一、表命令1.查看所有表show tables;2.创建表CREATE TABLE table_name ( co
- python的开发工具有很多种,各有特点,本人一直使用的是pycharm,所以本篇内容仅限pycharm。1,设置python文件头模板当我
- 第一种方法Python的cv2库中自带彩色转灰度的方法,而且非常简单,代码就9行,核心代码就1行。大题思路就是先读取一张彩色图片,然后在窗口
- 在本教程中,我们将学习使用OpenCV跟踪对象。OpenCV 3.0开始引入跟踪API。我们将学习如何和何时使用OpenCV 4.2中可用的
- 一张表(ColumnTable)的结构如下图所示当前需要实现的功能:通过Number的值为67来获取当前的节点ID、父节点ID递归实现SQL
- pytorch显存越来越多的一个原因optimizer.zero_grad()loss.backward()optimizer.step()
- 在一般的MIS应用中,会有大量的报表,此时我们可以在后台数据库编写相应的视图或存储过程,用ASP通过ADO调用以完成报表工作。下面用一个例子
- 最近闲来无事, 于是就简单学习了下Go语言的基本的用法。由于实践才是最快的学习方法,所以这里就以下载网络图片或文件入手来学习Go语言文件下载
- 前言本文主要给大家介绍了关于Golang中数据结构Queue实现的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。
- 本文实例分析了ThinkPHP中的__initialize()和类的构造函数__construct()。分享给大家供大家参考。具体分析如下:
- 本文实例为大家分享了pycharm实现猜数游戏的具体代码,供大家参考,具体内容如下1. 设计界面如下所示,利用QTdesigner设计的界面
- 类中定义的方法大致可以分为两类:绑定方法和非绑定方法。其中绑定方法又可以分为绑定到对象的方法和绑定到类的方法。一、绑定方法1 对象的绑定方法
- 本文实例讲述了Go语言实现的简单网络端口扫描方法。分享给大家供大家参考。具体实现方法如下:package mainimport ( 
- 路由原理在Tornado框架中,路由是指将请求的URL映射到对应的处理函数上,这个过程需要通过正则表达式来实现。Tornado使用了一种叫做
- 一、类型数组是值类型,将一个数组赋值给另一个数组时,传递的是一份拷贝。切片是引用类型,切片包装的数组称为该切片的底层数组。我们来看一段代码/
- 此问题是由于最新的pycharm在安装时自动装了vimVim插件 你可以在tools Vim emulator将对勾去掉就可以了。来源:ht
- Vue 3.2 引入了语法,这是一种稍微不那么冗长的声明组件的方式。您可以通过向 SFC 的元素添加属性来启用它,然后可以删除组件中的一些样
- 用mysqldump和source可以使用这种方式导出数据:mysqldump -urott -P5678 --default-charac
- 本文实例为大家分享了python实现书法碑帖图片分割的具体代码,供大家参考,具体内容如下一、功能实现效果1、选择要分割的碑帖图片2、选择碑帖
- 1. 在apps包下新建一个utils的python包2. utils包中新建一个YunPian.py文件,文件中代码如下import re