使用babel-plugin-import?實現(xiàn)自動按需引入方式
babel-plugin-import 實現(xiàn)自動按需引入
Vant 支持一次性導(dǎo)入所有組件,引入所有組件會增加代碼包體積,因此不推薦這種做法
babel-plugin-import 是一款 babel 插件,它會在編譯過程中將 import 的寫法自動轉(zhuǎn)換為按需引入的方式。
1、下載
npm i babel-plugin-import -D
2、
(1)在.babelrc 中添加配置
注意:webpack 1 無需設(shè)置 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 組件,插件會自動將代碼轉(zhuǎn)化為方式二中的按需引入形式
import { Button } from 'vant';
babel-plugin-import 的組件按需加載原理
對比webpack懶加載
webpack 懶加載是將源碼中的 import、require 引入的文件編譯之后再根據(jù)動態(tài)加載語法配置(通常以頁面路由為基本單位)將較大的代碼拆分并構(gòu)建出較小的 chunk 包,運行時執(zhí)行到相應(yīng)業(yè)務(wù)邏輯時才去加載執(zhí)行對應(yīng) chunk 代碼。
webpack 懶加載主要發(fā)生在 JS 拆分出不同的 Chunk 這一過程中。
babel-plugin-import 按需加載是以組件為基本單位產(chǎn)出 js、css、less 文件,借助插件或者部分引入的寫法,使得項目代碼或 babel 編譯后的代碼中只包含使用到的組件的 js、css、less 等。
首先是執(zhí)行時機不同,babel-plugin-import 按需加載是在源碼編寫階段或者 babel 編譯 js 階段,而 webpack 懶加載則是在構(gòu)建生成打包產(chǎn)物階段。
其次是原理不同,babel-plugin-import 按需加載是在源碼階段就去掉了無關(guān)代碼,而 webpack 懶加載則是將經(jīng)過 tree-shaking 優(yōu)化過后的大文件包進行拆分在適當(dāng)?shù)倪\行時進行按需加載。兩者并不沖突,可以一前一后共同作用。
實現(xiàn)原理
babel-plugin-import 按需加載目的是減少項目構(gòu)建打包產(chǎn)物的大小,提高項目線上首屏渲染速度,減少白屏?xí)r間,減少流量消耗。
若是采用手動引入需要使用到的組件以及其對應(yīng)的樣式文件,那么在 webpack 構(gòu)件時組件庫中其他未被引入的文件不會被打包。
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 等文件的總稱,自動引入的本質(zhì)是將引入組件的寫法通過插件來轉(zhuǎn)換成手動引入組件對應(yīng)的代碼以及樣式文件的寫法。核心原理依然是對源碼的 import 導(dǎo)入寫法進行轉(zhuǎn)換——詞法語法分析,AST轉(zhuǎn)換,代碼生成。
該插件主要參數(shù):
"libraryName": "", // 組件庫名稱,對應(yīng) import 語法中的包名 "libraryDirectory": "lib", // 編譯之后各個組件單元所在文件夾名稱 "style": true, // 是否引入組件對應(yīng)樣式文件,也可以傳入 less 來引入 less 文件 "styleLibraryDirectory": "", // 編譯之后引入的組件樣式文件所在文件夾名稱 "camel2DashComponentName": false, // 是否將駝峰命名的導(dǎo)入變量轉(zhuǎn)換為對應(yīng)的橫線連接命名的文件名 "customName": (name, file) => { return `/lib/${name}` }, // 自定義編譯之后引入的組件名 "customStyleName": (name, file) => { return `/lib/css/${name}` }, // 自定義編譯之后引入樣式文件的名稱
插件中使用到的鉤子函數(shù)有:
const methods = [ 'ImportDeclaration', // import 導(dǎo)入聲明 'CallExpression', // 函數(shù)調(diào)用 'MemberExpression', 'Property', 'VariableDeclarator', 'ArrayExpression', 'LogicalExpression', 'ConditionalExpression', 'IfStatement', 'ExpressionStatement', 'ReturnStatement', 'ExportDefaultDeclaration', 'BinaryExpression', 'NewExpression', 'ClassDeclaration', 'SwitchStatement', 'SwitchCase', ];
Visitor 對象上還配置了 Program 鉤子,該鉤子是在 babel 處理一個獨立文件(或者叫做模塊更合適,node 規(guī)范定義一個文件就是一個模塊)時執(zhí)行,其中若不按此方式具體指定則默認為 enter 鉤子。
const Program = { // 進入鉤子 enter(path, options) { // 1. 根據(jù)插件接受到的配置參數(shù)初始化插件 Plugin 數(shù)組 // 2. 遍歷插件 Plugin 數(shù)組,依次執(zhí)行各個插件的初始化方法 ProgramEnter }, // 退出鉤子 exit() { // ... } }
轉(zhuǎn)換 import 語法需要識別 ES6 模塊規(guī)范的默認導(dǎo)入、部分導(dǎo)入以及整體導(dǎo)入等語法,主要邏輯包括鑒別是否是部分導(dǎo)入,只有部分導(dǎo)入才表示導(dǎo)入具體組件,轉(zhuǎn)換導(dǎo)入變量名等。
// 1. 部分導(dǎo)入 import { Button } from ''; console.log(Button); // 2. 默認導(dǎo)入 import default from ''; console.log(default.Button); // 3. 全部導(dǎo)入 import * as D from ''; console.log(D.Button);
整體處理邏輯如下:
- ImportDeclaration 鉤子中將部分導(dǎo)入、默認導(dǎo)入和整體導(dǎo)入的語句記錄到插件全局狀態(tài)對象上,同時將節(jié)點的 path 對象記錄至插件全局狀態(tài)對象上;
- 插件全局狀態(tài)對象上存儲的 path 對象會在 Program 退出時遍歷執(zhí)行 remove 方法,從而移除了所有原始的導(dǎo)入語句;
- 在 MemberExpression、CallExpression、buildExpressionHandler、buildDeclaratorHandler等鉤子函數(shù)中執(zhí)行 importMethod 函數(shù);
- importMethod 函數(shù)會根據(jù)插件的配置參數(shù)計算出真實文件導(dǎo)入路徑、是否導(dǎo)入樣式文件、樣式文件名、是否轉(zhuǎn)換默認導(dǎo)入等配置,從而使用 @babel/helper-module-imports 提供的 addSideEffect 方法添加對應(yīng)的部分導(dǎo)入語句。
- 重命名導(dǎo)入模塊的變量描述符 Identifier。
以鉤子函數(shù)為入口,根據(jù)不同的節(jié)點類型取找到不同節(jié)點與變量相關(guān)的屬性;
校驗變量的 name 是否存在于插件全局狀態(tài)的 specfied 中,即變量是否是導(dǎo)入組件指向的變量;
通過 path.scope.hasBinding、path.scope.getBinding 排除掉其他作用域的變量;
借助 importMethod 方法計算轉(zhuǎn)換后模塊對應(yīng)的變量名然后修改節(jié)點對應(yīng)的變量名。
變量描述符 Identifier可能指向的鉤子有:
Property VariableDeclarator ArrayExpression LogicalExpression ConditionalExpression IfStatement ExpressionStatement ReturnStatement ExportDefaultDeclaration BinaryExpression NewExpression SwitchStatement SwitchCase ClassDeclaration
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Javascript vue.js表格分頁,ajax異步加載數(shù)據(jù)
這篇文章主要介紹了Javascript vue.js表格分頁,ajax異步加載數(shù)據(jù)的相關(guān)資料,需要的朋友可以參考下2016-10-10vue靜態(tài)配置文件不進行編譯的處理過程(在public中引入js)
這篇文章主要介紹了vue靜態(tài)配置文件不進行編譯的處理過程(在public中引入js),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03Vue3中Watch、Watcheffect、Computed的使用和區(qū)別解析
Watch、Watcheffect、Computed各有優(yōu)劣,選擇使用哪種方法取決于應(yīng)用場景和需求,watch?適合副作用操作,watchEffect適合簡單的自動副作用管理,computed?適合聲明式的派生狀態(tài)計算,本文通過場景分析Vue3中Watch、Watcheffect、Computed的使用和區(qū)別,感興趣的朋友一起看看吧2024-07-07vite配置別名并處理報錯:找不到模塊“xxx”或其相應(yīng)的類型聲明方法詳解
我在學(xué)習(xí)vue3+vite+ts的時候,在配置別名這一步的時候遇到了一個問題,這篇文章主要給大家介紹了關(guān)于vite配置別名并處理報錯:找不到模塊“xxx”或其相應(yīng)的類型聲明的相關(guān)資料,需要的朋友可以參考下2022-11-11vue菜單欄聯(lián)動內(nèi)容頁面tab的實現(xiàn)示例
本文主要介紹了vue菜單欄聯(lián)動內(nèi)容頁面tab的實現(xiàn)示例,左側(cè)菜單欄與右側(cè)內(nèi)容部分聯(lián)動,當(dāng)點擊左側(cè)的菜單,右側(cè)會展示對應(yīng)的tab,具有一定的參考價值,感興趣的可以了解一下2024-01-01