手上有些項目用的element-ui
,恰好有空琢磨一下怎麼減少打包文件大小和打包速度方面,爲了演示實驗,用 vue-cli
生成初始項目,在這僅對 element-ui
主題和組件方面來優化。css
vue init webpack vuecli
完整地將 ui
和樣式引入。html
import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css'
在頁面簡單使用 2 個組件,看看效果。vue
<el-tabs v-model="activeName" @tab-click="handleClick"> <el-tab-pane label="用戶管理" name="first">用戶管理</el-tab-pane> <el-tab-pane label="配置管理" name="second">配置管理</el-tab-pane> <el-tab-pane label="角色管理" name="third">角色管理</el-tab-pane> <el-tab-pane label="定時任務補償" name="fourth">定時任務補償</el-tab-pane> </el-tabs> <el-steps :active="2" align-center> <el-step title="步驟1" description="這是一段很長很長很長的描述性文字"></el-step> <el-step title="步驟2" description="這是一段很長很長很長的描述性文字"></el-step> <el-step title="步驟3" description="這是一段很長很長很長的描述性文字"></el-step> <el-step title="步驟4" description="這是一段很長很長很長的描述性文字"></el-step ></el-steps>
再看一下打包後的資源大小狀況npm run build --report
。node
Hash: 40db03677fe41f7369f6 Version: webpack 3.12.0 Time: 20874ms Asset Size Chunks Chunk Names static/css/app.cb8131545d15085cee647fe45f1d5561.css 234 kB 1 [emitted] app static/fonts/element-icons.732389d.ttf 56 kB [emitted] static/js/vendor.a753ce0919c8d42e4488.js 824 kB 0 [emitted] [big] vendor static/js/app.8c4c97edfce9c9069ea3.js 3.56 kB 1 [emitted] app static/js/manifest.2ae2e69a05c33dfc65f8.js 857 bytes 2 [emitted] manifest static/fonts/element-icons.535877f.woff 28.2 kB [emitted] static/css/app.cb8131545d15085cee647fe45f1d5561.css.map 332 kB [emitted] static/js/vendor.a753ce0919c8d42e4488.js.map 3.26 MB 0 [emitted] vendor static/js/app.8c4c97edfce9c9069ea3.js.map 16.6 kB 1 [emitted] app static/js/manifest.2ae2e69a05c33dfc65f8.js.map 4.97 kB 2 [emitted] manifest index.html 506 bytes [emitted]
發現打包後提取公共模塊 static/js/vendor.js
有 824kb
webpack
再看一下各個模塊佔用狀況:git
發現 elment-ui.common.js
佔用最大。全部模塊資源總共有 642kb
。怎麼才能減少打包後的大小呢?很容易就會想到 ui
的引入和樣式的引入中,實際咱們只使用了三個組件,卻總體都被打包了,在這裏引入這三個組件便可。github
新建一個 element-variables.scss
文件(爲何是 SCSS
文件,後面自定義主題會用到)。web
/*icon字體路徑變量*/ $--font-path: "~element-ui/lib/theme-chalk/fonts"; /*按需引入用到的組件的scss文件和基礎scss文件*/ @import "~element-ui/packages/theme-chalk/src/base.scss"; @import "~element-ui/packages/theme-chalk/src/rate.scss"; @import "~element-ui/packages/theme-chalk/src/button.scss"; @import "~element-ui/packages/theme-chalk/src/row.scss";
新建一個 element-config.js
文件,將項目用到的 element
組件引入。vue-cli
import { Tabs, TabPane, Steps, Step } from 'element-ui' export default { install (V) { V.use(Tabs) V.use(TabPane) V.use(Steps) V.use(Step) } }
將以上 element-variables.scss
和 element-config.js
引入到 main.js
中。shell
import ElementUI from '@/assets/js/element-config' import '@/assets/css/element-variables.scss' Vue.use(ElementUI)
貌似上面一切都很瓜熟蒂落,打包後大小會減少。
Hash: 2ef987c23a5d612e00e1 Version: webpack 3.12.0 Time: 17430ms Asset Size Chunks Chunk Names static/css/app.3c70d8d75c176393318b232a345e3f0f.css 38.8 kB 1 [emitted] app static/fonts/element-icons.732389d.ttf 56 kB [emitted] static/js/vendor.caa5978bb1eb0a15b097.js 824 kB 0 [emitted] [big] vendor static/js/app.5ebb19489355acc3167b.js 3.64 kB 1 [emitted] app static/js/manifest.2ae2e69a05c33dfc65f8.js 857 bytes 2 [emitted] manifest static/fonts/element-icons.535877f.woff 28.2 kB [emitted] static/css/app.3c70d8d75c176393318b232a345e3f0f.css.map 53.9 kB [emitted] static/js/vendor.caa5978bb1eb0a15b097.js.map 3.26 MB 0 [emitted] vendor static/js/app.5ebb19489355acc3167b.js.map 17 kB 1 [emitted] app static/js/manifest.2ae2e69a05c33dfc65f8.js.map 4.97 kB 2 [emitted] manifest index.html 506 bytes [emitted]
結果可知,static/js/vendor.js
仍是 824kb
!
再看各個模塊佔用狀況:
WHAT? 居然模塊都沒什麼變化,豈不是竹籃打水,事與願違。
後來查到有人一樣遇到這個問題,提出一個issues#6362,原來只引入須要的element-ui
組件,webpack
仍是把總體的 UI
庫和樣式都打包了,須要一個 webpack
的 babel
插件 babel-plugin-component
,這樣才能真正按需引入打包。這塊其實被寫到官方文檔更換 自定義主題 的配置了。
因而 npm i babel-pugin-componet -D
安裝後,在增長 .babelrc
文件插件配置
{ "presets": [ ["env", { "modules": false, "targets": { "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] } }], "stage-2" ], "plugins": [ "transform-vue-jsx", "transform-runtime", [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ] ] }
頁面運行正常,再次打包。
Hash: f182f70cb4ceee63b5d5 Version: webpack 3.12.0 Time: 10912ms Asset Size Chunks Chunk Names static/css/app.95c94c90ab11fdd4dfb413718f444d0c.css 39.9 kB 1 [emitted] app static/fonts/element-icons.732389d.ttf 56 kB [emitted] static/js/vendor.befb0a8962f74af4b7e2.js 157 kB 0 [emitted] vendor static/js/app.5343843cc20a78e80469.js 3.86 kB 1 [emitted] app static/js/manifest.2ae2e69a05c33dfc65f8.js 857 bytes 2 [emitted] manifest static/fonts/element-icons.535877f.woff 28.2 kB [emitted] static/css/app.95c94c90ab11fdd4dfb413718f444d0c.css.map 93.5 kB [emitted] static/js/vendor.befb0a8962f74af4b7e2.js.map 776 kB 0 [emitted] vendor static/js/app.5343843cc20a78e80469.js.map 17.1 kB 1 [emitted] app static/js/manifest.2ae2e69a05c33dfc65f8.js.map 4.97 kB 2 [emitted] manifest index.html 506 bytes [emitted]
static/js/vendor.js
確實變小了,157kB
。再來看各個模塊分析圖。
模塊總共 157.93KB
,少了 5 倍!
element-ui
的 theme-chalk
使用 SCSS
編寫,若是在本身的項目中也是用 SCSS
,那麼能夠直接在項目中改變樣式變量,所以能夠在前面新建的 element-variables.scss
文件用新的主題顏色變量覆蓋便可。
/** * 覆蓋主題色 */ /*主題顏色變量*/ $--color-primary: #f0f; /*icon字體路徑變量*/ $--font-path: '~element-ui/lib/theme-chalk/fonts'; /* 引入所有默認樣式 會引入沒用到的組件樣式 */ // @import '~element-ui/packages/theme-chalk/src/index'; /* 按需引入用到的組件的scss文件和基礎scss文件 */ @import '~element-ui/packages/theme-chalk/src/base.scss'; @import '~element-ui/packages/theme-chalk/src/rate.scss'; @import '~element-ui/packages/theme-chalk/src/button.scss'; @import '~element-ui/packages/theme-chalk/src/row.scss';
如今咱們的主題就變成了預期效果
可能你已經注意到了,這裏推薦的是分別引入用到的組件樣式,而不是引入所有默認樣式,由於這樣會致使引入沒有使用到的組件樣式。好比當前案例中咱們沒有使用到 ColorPicker
組件,在打包輸出的 css
文件中確有該組件樣式。
經過以上優化能夠按需的將所用到組件打包,排除沒用到的組件,減小包的大小。可是,仍是存在一個小瑕疵:一個用到的組件樣式會被兩次打包,一次是默認的樣式,一次是覆蓋的樣式。
出現這個問題是因爲咱們在兩個地方對樣式進行引入了,一個是在 .babelrc
文件中經過 babel-plugin-component
插件按需引入 element-ui
組件及其默認樣式,一個是在 element-variables.scss
文件中覆蓋默認樣式生成的自定義樣式。
因此怎樣將兩者結合,即babel-plugin-component
插件按需引入的組件樣式改爲用戶自定義樣式,達成純淨樣式目標呢?這裏就要用到 element-ui
的主題工具進行深層次的主題定製。
首先安裝主題工具 element-theme
,能夠全局安裝也可安裝在項目目錄。這裏推薦安裝在項目錄,方便別人 clone
項目時能直接安裝依賴並啓動。
npm i element-theme -D
而後安裝白堊主題,能夠從 npm
安裝或者從 GitHub
拉取最新代碼。
# 從 npm npm i element-theme-chalk -D # 從 GitHub npm i https://github.com/ElementUI/theme-chalk -D
element-theme
支持的構建有 Node API
和 CLI
方式。
若是全局安裝能夠在命令行裏經過 et
調用工具,若是安裝在當前目錄下,須要經過 node_modules/.bin/et
訪問到命令。執行 -i
(--init
) 初始化變量文件。默認輸出到 element-variables.scss
,固然你能夠傳參數指定文件輸出目錄。若是你想啓用 watch 模式,實時編譯主題,增長 -w
(--watch
) 參數;若是你在初始化時指定了自定義變量文件,則須要增長 -c
(--config
) 參數,並帶上你的變量文件名。默認狀況下編譯的主題目錄是放在 ./theme
下,你能夠經過 -o
(--out
) 參數指定打包目錄。
# 初始化變量文件 et --init [file path] # 實時編譯 et --watch [--config variable file path] [--out theme path] # 編譯 et [--config variable file path] [--out theme path] [--minimize]
引入 element-theme
經過 Node API
形式構建
var et = require('element-theme') // 實時編譯模式 et.watch({ config: 'variables/path', out: 'output/path' }) // 編譯 et.run({ config: 'variables/path', // 配置參數文件路徑 默認`./element-variables.css` out: 'output/path', // 輸出目錄 默認`./theme` minimize: false, // 壓縮文件 browsers: ['ie > 9', 'last 2 versions'], // 瀏覽器支持 components: ['button', 'input'] // 選定組件構建自定義主題 })
在這裏,爲了讓主題的構建更加直觀和被項目共享,採用 Node API
方式構建,在項目根目錄下新建 theme.js
文件。
const et = require('element-theme') // 第一步生成樣式變量文件 // et.init('./src/theme.scss') // 第二步根據實際須要修改該文件 // ... // 第三步根據該變量文件編譯出自定義的主題樣式文件 et.run({ config: './src/theme.scss', out: './src/theme' })
在 package.json
中增長 scripts
指令
{ "scripts": { "theme": "node theme.js" } }
這樣就能夠經過 npm run theme
指令來編譯主題了。編譯過程:
theme.scss
。theme
目錄下。這樣就完成了全部自定義主題樣式的構建。要想將這些自定義樣式隨着組件按需引入,須要將 .babelrc
文件中按需引入插件 babel-plugin-component
參數 styleLibraryName
從本來的 element-ui
默認樣式目錄變成如今自定義目錄 ~src/theme
。
"plugins": [ "transform-vue-jsx", "transform-runtime", [ "component", { "libraryName": "element-ui", "styleLibraryName": "~src/theme" } ] ]
一切準備就緒,項目打包,打包後的 css
文件中只有惟一自定義樣式,沒有了默認樣式,也不存在沒被引入組件的樣式,實現了咱們預期的純淨的自定義樣式!
Hash: c442bcf9d471bddfdccf Version: webpack 3.12.0 Time: 10174ms Asset Size Chunks Chunk Names static/css/app.52d411d0c1b344066ec1f456355aa7b9.css 38.8 kB 1 [emitted] app static/fonts/element-icons.535877f.woff 28.2 kB [emitted] static/js/vendor.befb0a8962f74af4b7e2.js 157 kB 0 [emitted] vendor static/js/app.43c09c1f16b24d371e07.js 3.82 kB 1 [emitted] app static/js/manifest.2ae2e69a05c33dfc65f8.js 857 bytes 2 [emitted] manifest static/fonts/element-icons.732389d.ttf 56 kB [emitted] static/css/app.52d411d0c1b344066ec1f456355aa7b9.css.map 81.3 kB [emitted] static/js/vendor.befb0a8962f74af4b7e2.js.map 776 kB 0 [emitted] vendor static/js/app.43c09c1f16b24d371e07.js.map 17.1 kB 1 [emitted] app static/js/manifest.2ae2e69a05c33dfc65f8.js.map 4.97 kB 2 [emitted] manifest index.html 506 bytes [emitted]
因爲樣式是純淨的,css
文件大小從原來徹底引入的 234KB
變成 38.8KB
,進一步減少了打包大小。
經過以上實驗分析咱們能夠得知,element-ui
要想實現按需引入和純淨的主題樣式:
babel-plugin-component
插件進行按需引入。element-theme
工具生成樣變量文件。styleLibraryName
指向自定義樣式目錄。若是對樣式提取要求不高,可直接採起變量覆蓋形式(同時存在默認樣式)。
還有不清楚能夠戳這裏查看案例源碼,贈人 star,手有餘香。
完~ps:我的看法有限,歡迎指正。