作者的挖坑之旅
作者本人在工作之餘喜歡自己寫一些東西玩玩, 雖然不是資深程式設計師, 不過也還是能夠完成前端頁面+後端介面+服務端部署的整個流程了。
如果不願意看分析過程,可以直接拉到最後看結果。
開始入坑
歡迎來我的Vue技術群交流:887516034
首先前端頁面使用了Vue作為前端開發框架,我相信點這個標題進來看文章的都用過這個框架的吧。。。
- 首先肯定是要引入element這個ui元件庫,但是作者是個很講究的人,雖然自己瞎倒騰的頁面沒多少東西,但是有些東西還是要規範處理的↓↓↓
- 為了專案整體內容不過於龐大,按需載入是許多第三方的庫和外掛必不可少的,於是使用了官方提供的按需載入外掛babel-plugin-component↓↓↓
- 先看看官方的程式碼按需載入
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
複製程式碼
這是.babelrc配置引數,component是babel外掛的名字,物件是引數。
import Vue from 'vue';
import {
Dialog,
Autocomplete,
Dropdown,
...
} from 'element-ui';
Vue.use(Pagination);
Vue.use(Dialog);
Vue.use(Autocomplete);
...
//這裡提個醒
//MessageBox,Message,Notification這三個元件只能掛載Vue原型上呼叫,
//不能使用Vue.use();否則專案執行會預設執行一次,即使沒有使用它們
複製程式碼
這樣就可以愉快的按需載入使用自己想要的元件了,接下來給大家看一下這個按需載入外掛的部分原始碼,看它到底幹了什麼
- 位置在node_modules/babel-plugin-component/lib/core.js
var _options = options,
_options$libDir = _options.libDir,//這是元件所在根目錄下的路徑element-ui/lib/
libDir = _options$libDir === void 0 ? 'lib' : _options$libDir,
_options$libraryName = _options.libraryName,//這是ui庫的名字--elementui
libraryName = _options$libraryName === void 0 ? defaultLibraryName : _options$libraryName,
_options$style = _options.style,
style = _options$style === void 0 ? true : _options$style,
styleLibrary = _options.styleLibrary,//這是引入元件時,所需要引入對應元件樣式的配置物件
_options$root = _options.root,
root = _options$root === void 0 ? '' : _options$root,
_options$camel2Dash = _options.camel2Dash,
camel2Dash = _options$camel2Dash === void 0 ? true : _options$camel2Dash;
var styleLibraryName = options.styleLibraryName;//這是元件所需樣式的路徑(相對於上面的lib)
var _root = root;
var isBaseStyle = true;
var modulePathTpl;
var styleRoot;
var mixin = false;
var ext = options.ext || '.css';//這是載入樣式的字尾,預設css
複製程式碼
就這一部分程式碼,我們已經知道在執行按需載入時已經配置了對應樣式的載入,所以如果在.babelrc
檔案配置過styleLibraryName
屬性的,不要在全域性引入element的css樣式了,如果你不在乎打包體積的話,請無視我。
踩坑
- 作者當時第一次在看element官網時,就發現了定製主題,很有趣,改個scss變數,整個主題色就變了,來看下官方的程式碼
/* 改變主題色變數 */
$--color-primary: teal;
/* 改變 icon 字型路徑變數,必需 */
$--font-path: '~element-ui/lib/theme-chalk/fonts';
@import "~element-ui/packages/theme-chalk/src/index";//注意此處引入了所有元件的scss樣式
複製程式碼
-
看到這裡你們發現什麼了嗎?是的,沒錯,這裡引入了全部的scss,上面我們剛說babel-plugin-component會在按需載入元件時,同時引入對應元件的css樣式,有人會說那這裡就不引入這個
index.scss
檔案,如果沒有元件的scss,那這個$--color-primary
變數會有效嗎? 答案當然是不可能有效的。 -
既然我們
node_modules
裡面有所有元件的scss樣式檔案,我們是不是就可以讓babel-plugin-component在引入元件時,就引入對應的scss檔案呢?答案是完全ojbk的,不然還寫這文章幹嘛。。。
爬坑
- 我們回到按需載入外掛的原始碼,之前看到程式碼是配置了載入樣式的部分程式碼的,我們現在看一下具體怎麼載入的(這段程式碼是作者連蒙帶猜的。。有錯請指出)
if (styleLibrary && _typeof(styleLibrary) === 'object') {//這個是樣式的一些配置
styleLibraryName = styleLibrary.name;
isBaseStyle = styleLibrary.base;
modulePathTpl = styleLibrary.path;
mixin = styleLibrary.mixin;
styleRoot = styleLibrary.root;
}
if (styleLibraryName) {//是否在.babelrc配置了styleLibraryName
if (!cachePath[libraryName]) {//是否存在配置好的樣式獲取路徑
var themeName = styleLibraryName.replace(/^~/, '');
cachePath[libraryName] = styleLibraryName.indexOf('~') === 0 ?//路徑是否相對於element-ui/lib
resolve(process.cwd(), themeName) :
"".concat(libraryName, "/").concat(libDir, "/").concat(themeName);
}//如果是相對於lib 組合路徑---element-ui/lib/theme-chalk/ 這個目錄下是75個css檔案
//這裡將這一段路徑儲存在了cachePath[libraryName] 後續會用到
if (libraryObjs[methodName]) {//作者也沒搞清楚這裡是什麼 不過沒關係,事實證明這裡走了false
/* istanbul ingore next */
if (cache[libraryName] === 2) {
throw Error('[babel-plugin-component] If you are using both' + 'on-demand and importing all, make sure to invoke the' + ' importing all first.');
}
if (styleRoot) {//這裡預設是沒有配置的 所有走false
path = "".concat(cachePath[libraryName]).concat(styleRoot).concat(ext);
} else {
path = "".concat(cachePath[libraryName]).concat(_root || '/index').concat(ext);
}//這裡會預設先載入index.css 因為ext沒設定就會預設css
cache[libraryName] = 1;
} else {//走了else
if (cache[libraryName] !== 1) {//這裡肯定是不等於1,因為上面一行才會賦值1
/* if set styleLibrary.path(format: [module]/module.css) */
var parsedMethodName = parseName(methodName, camel2Dash);
if (modulePathTpl) {
var modulePath = modulePathTpl.replace(/\[module]/ig, parsedMethodName);
path = "".concat(cachePath[libraryName], "/").concat(modulePath);
} else {//這裡走了else 也就是樣式路徑後續為模組名.[ext]
path = "".concat(cachePath[libraryName], "/").concat(parsedMethodName).concat(ext);
}//所有這裡的路徑就是element-ui/lib/
if (mixin && !isExist(path)) {
path = style === true ? "".concat(_path, "/style").concat(ext) : "".concat(_path, "/").concat(style);
}
if (isBaseStyle) {
addSideEffect(file.path, "".concat(cachePath[libraryName], "/base").concat(ext));
}
cache[libraryName] = 2;
}
}
addDefault(file.path, path, {
nameHint: methodName
});
} else {
if (style === true) {
addSideEffect(file.path, "".concat(path, "/style").concat(ext));
} else if (style) {
addSideEffect(file.path, "".concat(path, "/").concat(style));
}
}
}
複製程式碼
- 好的,這就過了一遍了,連蒙帶猜知道是怎麼回事了,我們進入正題,如何變為載入對應元件的scss
//第一步不用說了 先把ext字尾改為scss
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk",
"ext":".scss"
}
]
//-------------------
//第二步呢 就是配置路徑 比較重要的
//有一段程式碼需要看的 雖然作者也看不懂,不過大概知道這一段是載入模組的
if (libraryObjs[methodName]) {
path = "".concat(libraryName, "/").concat(libDir).concat(_root);
//需要注意這裡的libDir,之前的程式碼我們看到 載入樣式也會基於libDir
//所以我們無法通過.babelrc的option去修改libDir,
//那樣的話元件載入就有問題我們不能影響最基本的元件載入
if (!_root) {
importAll[path] = true;
}
} else {
path = "".concat(libraryName, "/").concat(libDir, "/").concat(parseName(methodName, camel2Dash));
}
//所以我們只能通過修改core.js的原始碼解決,這是我目前的辦法
複製程式碼
- 既然我們要修改按需載入對應的scss樣式,那首先先找到檔案位置,這裡我直接說了element-ui/packages/theme-chalk/src/ 和預設載入css一樣75個檔案,哇,檔案數量都一樣,是不是瞬間感覺很放心了呢。
- 我們對比一下,
- 預設的是element-ui/lib/theme-chalk
- 要修改成element-ui/packages/theme-chalk/src
libDir
是不能改的 我們說了 所以看原始碼
//這是上面提到的三目運算
if (!cachePath[libraryName]) {
var themeName = styleLibraryName.replace(/^~/, '');
cachePath[libraryName] = styleLibraryName.indexOf('~') === 0 ?
resolve(process.cwd(), themeName) :
"".concat(libraryName, "/").concat(libDir, "/").concat(themeName);
}//我們把這裡------------------------libDir修改為 "packages"
現在路徑從element-ui/lib/theme-chalk--->element-ui/packages/theme-chalk
複製程式碼
- 我們再看看,還少了個src
- element-ui/packages/theme-chalk
- element-ui/packages/theme-chalk/src
- 老規矩,看原始碼
//咳咳,還是那個三目運算
if (!cachePath[libraryName]) {
var themeName = styleLibraryName.replace(/^~/, '');
cachePath[libraryName] = styleLibraryName.indexOf('~') === 0 ?
resolve(process.cwd(), themeName) :
"".concat(libraryName, "/").concat("packages", "/").concat(themeName);
}
//我們看packages後面的路徑是個變數themeName
//這個themeName就是styleLibraryName,你懂了嗎,你懂怎麼修改了嗎
複製程式碼
- 如下
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk/src",//這裡把theme-chalk-->theme-chalk/src
"ext":".scss"
}
]
複製程式碼
- 至此,已經完成。快去跑專案玩玩看吧。
總結
.babelrc
"plugins": [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk/src",
"ext":".scss"
}
]
]
複製程式碼
node_modules/babel-plugin-component/lib/core.js
//95-98行左右
if (!cachePath[libraryName]) {
var themeName = styleLibraryName.replace(/^~/, '');
cachePath[libraryName] = styleLibraryName.indexOf('~') === 0 ? resolve(process.cwd(), themeName) : "".concat(libraryName, "/").concat("packages", "/").concat(themeName);
}
複製程式碼
由於隨便修改官方提供的外掛原始碼並不合理,作者我fork了官方的npm包,並且修改了對應位置的程式碼,合理的做法是安裝我提供的babel-plugin-component-scss,當不需要scss時,仍可使用官方的外掛
需要注意的是,當使用babel-plugin-component-scss時,babel.config.js
or.babelrc
的配置需要如下:
"plugins": [
[
"component-scss",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk/src",
"ext":".scss"
}
]
]
複製程式碼
over
歡迎來我的Vue技術群交流:887516034
如果覺得對你有用,就打賞一下吧。