使用babel-plugin-import 实现自动按需引入方式

目录
  • babel-plugin-import 实现自动按需引入
  • babel-plugin-import 的组件按需加载原理
    • 对比webpack懒加载
    • 实现原理

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

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • iview在vue-cli3如何按需加载的方法

    iview在官方文档上,对于使用脚手架vue-cli3的项目的使用只有一句话:"我们为最新的 Vue CLI 3 提供了相应的 iView 插件,如果你正在用 Vue CLI 3,可以直接在插件中搜索 iview,安装插件来使用." 老实说,第一次看到这说明,我是懵逼的--废话不多说,直接撩起袖子撸 vue-cli3有个命令vue ui打开添加插件搜索 vue-cli-plugin-iview,点击安装 按需加载安装后,vue-cli-plugin-iview会自动帮我们做好以下的配置

  • vue 按需引入vant跟全局引入方式

    目录 一.按需引入 1.下载插件 2.自动按需引入组件 (推荐) 3.创建src文件跟js 4.全局main.js导入 5.使用 二.全局导入 一.按需引入 1.下载插件 第一步我们可以先打开vant的官网:vant 然后下载vant 用命令行下载 : 根据所需去配置 : 我配置的是vant2 Vue 2 项目,安装 Vant 2: npm i vant -S Vue 3 项目,安装 Vant 3: npm i vant@next -S 下载好以后我们去vue里面的根目 package.json

  • Vant的安装和配合引入Vue.js项目里的方法步骤

    1.安装vant npm i vant -S:这是简写形式. npm install vant --save:这是完整写法. 如果你网络很慢的话,可以使用淘宝的源,但是不建议使用cnpm来进行安装. npm install vant --save --registry=https://registry.npm.taobao.org 淘宝镜像,速度快,安装后查看package.json文件里看是否安装完成 2.1使用babel-plugin-import(推荐) babel-plugin-impo

  • 使用babel-plugin-import 实现自动按需引入方式

    目录 babel-plugin-import 实现自动按需引入 babel-plugin-import 的组件按需加载原理 对比webpack懒加载 实现原理 babel-plugin-import 实现自动按需引入 Vant 支持一次性导入所有组件,引入所有组件会增加代码包体积,因此不推荐这种做法 babel-plugin-import 是一款 babel 插件,它会在编译过程中将 import 的写法自动转换为按需引入的方式. 1.下载 npm i babel-plugin-import -

  • Vue组件如何自动按需引入详析

    目录 全局注册 局部注册 局部自动注册 不同方案对比 关于组件名 参考 总结 在Vue中我们可以通过全局组件.局部注册的方式来使用组件 全局注册 通过app.component来创建全局组件 import { createApp } from 'vue' import HelloWorld from './components/HelloWorld' const app = createApp({}) // 全局注册一个名为hello-wolrd的组件 app.component('hello-

  • webpack如何打包一个按需引入的vue组件库

    目录 前言 在项目中使用vue组件库的一般姿势 webpack实现可按需引入的组件库 接下来就是使用webpack打包 调试组件库 npm 发布 步骤非常简单,只需4步 调试组件库按需引入 总结 前言 在公司里一般有多个相同技术栈的项目,毕竟在多个项目间copy公共组件代码太繁琐,也不利于组件库的维护,所以怎么高效维护一套公共的组件代码很重要.这种情况,一般我们可以考虑封装成组件库,发布到npm上.在每个项目里只需要npm install xxx 即可使用,避免了在项目间相互copy.我们这就开

  • element-plus的自动导入和按需导入方式详解

    element-plus根据官网文档,推荐用户采用按需导入的方式进行导入. 我的项目是使用vite进行构建的,根据官网的文档,利用unplugin-vue-components插件进行自动按需导入. 当我们使用element的标签时,无需再使用import对组件进行导入. 例如: <el-button>test</el-button> 会自动引入ElButton组件. 不过当我们想要使用命令的方式创建element组件时,样式会无法自动引入. 我们以ElMessage为例. imp

  • vue3+vite项目中按需引入vant报错:Failed to resolve import的解决方案

    目录 问题描述 原因分析 解决方案 总结 问题描述 近日尝试使用vite+vue3+vant开发项目过程中,参考vant官网开发指南->快速上手->引入组件 按照上述配置好后,运行vite环境报错:Failed to resolve import 原因分析 根据报错信息,发现是vant的样式引入路径不对. 程序解析为:项目路径/node_modules/vant/lib/vant/es/组件/style 实际应该是:项目路径/node_modules/vant/lib/ vant/es/组件/

  • Nuxt配置Element-UI按需引入的操作方法

    Nuxt 使用 create-nuxt-app 创建项目时,选择使用 Element-UI 为默认组件库,发现 Nuxt 没有开启 Element-UI 的按需引入配置,需要自行配置. 安装依赖 在 create-nuxt-app 中没有选择 Element-UI 的先安装. npm install element-ui --save 或者 yarn add element-ui Element-UI 开启按需引入,必须安装 babel-plugin-component 插件. npm inst

  • vue3 element plus按需引入最优雅的用法实例

    全局导入 下载安装element plus后,在入口文件配置一下并挂载,就能畅通无阻的使用了.但问题是这样有很多用不上的组件都被打包进来了,导致包的体积非常大. 按需导入 采用按需导入的方法,其实是用解构的方式,从element的包中解构出来,再挂载到app上面.这样开发中用到什么组件就打包什么确实很好,减少了包的体积.但是又有一个新的问题,就是每次想要使用新的组件的时候,都要去解构一下,并且挂载.操作起来非常繁琐. 有什么办法能够像使用全局引入那样只配置一次,后面要用到什么组件,都会自己按需加

  • vue使用element-ui按需引入时踩过的那些坑

    众所周知,使用element-ui,为了达到减小项目体积的目的 ,我们在实际项目中更多的是采用按需引入的方法, 下面就来讲讲那些我踩过的坑. 步骤: 第一步:安装 element-ui 时把 element 也安装一下, 执行命令 npm i element-ui -S 和 npm i element -S 第二步:安装 babel-plugin-component , 执行命令 npm install babel-plugin-component -D 第三步 :踩坑一: element-ui

  • vue项目中如何实现element-ui组件按需引入

    目录 element-ui组件按需引入 按需引入 完整引入 vue项目搭建 + 引入element-ui 初始化单页系统 ElementUI整合项目 element-ui组件按需引入 按需引入 1.借助 babel-plugin-component ,引入我们需要的组件,减少项目体积 npm install babel-plugin-component -D 2.修改 babel.config.js 的内容 //babel.config.js 全文内容如下 module.exports = {

随机推荐