你要是沒有抽象語法樹基礎的話,建議先看一下上一篇文章抽象語法樹 Abstract syntax tree這樣更有助於對下文的理解!node
背景:當咱們同時引入一個包中的兩個方法,有兩種形式webpack
第一種形式git
import {flatten,join} from 'lodash';
複製代碼
第二種形式github
import flatten from 'lodash/flatten';
import join from 'lodash/join';
複製代碼
對比兩種形式,咱們能夠看出:web
第一種方式的引入會把整個lodash包引進來 第二種方式是指引入整個包中的兩個方法npm
顯然咱們要用第二種json
可是通常的項目中 大部分都是以import解構的形式,因此在這裏咱們就寫一個插件,當咱們寫成第一種形式引入的時候,利用插件轉化成第二種形式bash
這是咱們要寫的插件的功能babel
npm i webpack webpack-cli babel-core babel-loader babel-preset-env babel-preset-stage-0 -D
複製代碼
在Webpack中,提供了mode變量,用於配置運行環境,mode的值能夠爲development,表示的是開發模式,或者是production,表示的是生產模式。post
在package.json中寫入編譯的命令
"scripts":{
"build":"webpack --mode production/development"
}
複製代碼
webpack-plugin // 項目名稱
dist // 打包輸出目錄
bundle.js // 打包輸出的文件
src // 主要邏輯
index.js // 項目的入口文件
./babelrc // 語法解析配置
package.json
webpack.config.js
複製代碼
const path = require('path');
module.exports = {
entry: './src/index.js',// 入口文件
output: {
path: path.join(__dirname, 'dist'), // 輸出路徑
filename: 'bundle.js' // 輸出的文件名稱
},
// 配置
module: {
// 配置加載器
rules: [
{
test: /\.js$/,
loader: 'babel-loader'
}
]
}
}
複製代碼
{
"presets": [
"env",
"stage-0"
],
"plugins": [
[
// "demand-loading", // 注:這個是咱們本身寫的插件名 顯示先不放,等咱們寫好插件後再加上
{
"library": "lodash", // 咱們在引用哪一個庫的時候使用咱們寫的這個插件,這裏的意思是當咱們引用lodash庫的時候使用咱們寫的這個插件
},
"syntax-decorators"
]
]
}
複製代碼
// import {flatten,join} from 'lodash'
import flatten from 'lodash/flatten'
import join from 'lodash/join'
複製代碼
先引入後面的這兩句,而後打包一下
Hash: fcb0bd5d9734b5f56676
Version: webpack 4.2.0
Time: 346ms
Built at: 2018-3-27 21:24:33
Asset Size Chunks Chunk Names
bundle.js 21.3 KiB main [emitted] main
Entrypoint main = bundle.js
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 823 bytes {main} [built]
[./src/index.js] 286 bytes {main} [built]
+ 15 hidden modules
複製代碼
看到這樣打包後的代碼,咱們發現這種方式引入 打包後的大小是。21.3k
而後註釋掉後兩行,只引入第一行
Hash: aa8b689e1072463fc1cd
Version: webpack 4.2.0
Time: 3277ms
Built at: 2018-3-27 21:30:22
Asset Size Chunks Chunk Names
bundle.js 483 KiB main [emitted] main
Entrypoint main = bundle.js
[./node_modules/webpack/buildin/amd-options.js] (webpack)/buildin/amd-options.js 82 bytes {main} [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 823 bytes {main} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 521 bytes {main} [built]
[./src/index.js] 47 bytes {main} [built]
+ 1 hidden module
複製代碼
此次打包後的大小是 483k
經過對比 證明了咱們所說的兩種引入方式的區別
先對比一下兩種引入方式的抽象語法樹的差異
經過對比咱們發現,只是ImportDeclaration不相同
const babel = require('babel-core');
const types = require('babel-types');
let visitor = {
// 這裏的ref是ImportDeclaration的第二個參數,這裏的值是.babelrc中的 {
// "library": "lodash"
//}, 這裏是指定 咱們在引用哪一個庫的時候使用這個插件
ImportDeclaration(path, ref={options:{}}) {
let node = path.node;
let specifiers = node.secifiers
if (options.library == node.soure.value && !types.isImportDeclaration(specifiers[0])) {
let newImport = specifiers.map((specifier) => (
types.importDeclaration([types.ImportDefaultSpecifier(specifier.local)], types.stringLiteral(`${node.soure.value}/${specifier.local.name}`))
));
path.replaceWithMultiple(newImport)
}
}
}
const code = "import {flatten, join} from 'lodash';";
let r = babel.transform(code, {
plugins: [
{visitor}
]
})
複製代碼
在建立替換邏輯的時候,types上的方法 用github上的這個網址,哪一個不會搜哪一個,媽媽不再用擔憂個人學習。嘻嘻
新建一個文件夾 babel-plugin-demand-loading 放到node_modules中,再新建一個index.js文件,將下面的代碼放進去,再而後進入這個文件夾 npm init -y初始化一個package.json文件,裏面的入口文件寫成index.js
須要注意的事項:
第一: babel插件的文件夾命名,必須以 babel-plugin-xxx(你寫的插件名)命名,不然引入不成功 第二: babel插件返回的是一個對象,裏面有一個訪問者模式的visitor對象,裏面是咱們的轉化代碼
const babel = require('babel-core');
const types = require('babel-types');
module.exports = {
visitor: {
// 這裏的ref是ImportDeclaration的第二個參數,這裏的值是.babelrc中的 {
// "library": "lodash"
//}, 這裏是指定 咱們在引用哪一個庫的時候使用這個插件
ImportDeclaration(path, ref={}) {
let { opts } = ref
let node = path.node;
let specifiers = node.specifiers
if (opts.library == node.source.value && !types.isImportDeclaration(specifiers[0])) {
let newImport = specifiers.map((specifier) => (
types.importDeclaration([types.ImportDefaultSpecifier(specifier.local)], types.stringLiteral(`${node.source.value}/${specifier.local.name}`))
));
path.replaceWithMultiple(newImport)
}
}
}
}
複製代碼
到這裏你是否是也會了呢?嘻嘻!
不要厭煩熟悉的事物,天天都進步一點;不要畏懼陌生的事物,天天都學習一點;