摘要:同時(shí)也要引入對(duì)應(yīng)版本的先引入引入組件庫(kù)因?yàn)橐蕾?lài)是從外部引入的,所以需要告知在打包時(shí),依賴(lài)的來(lái)源。然后在中加入一條命令執(zhí)行或者即可完成打包。因此將此次優(yōu)化記錄下來(lái),并傳上了中。
本文原文
前言公司有好幾個(gè)項(xiàng)目都有后臺(tái)管理系統(tǒng),為了方便開(kāi)發(fā),所以選擇了 vue 中比較火的 后臺(tái)模板 作為基礎(chǔ)模板進(jìn)行開(kāi)發(fā)。但是,開(kāi)始用的時(shí)候,作者并沒(méi)有對(duì)此進(jìn)行優(yōu)化,到項(xiàng)目上線(xiàn)的時(shí)候,才發(fā)現(xiàn),打包出來(lái)的文件都十分之大,就一個(gè) vendor 就有 770k 的體積(下圖是基礎(chǔ)模板,什么都沒(méi)加打包后的文件信息):
通過(guò) webpack-bundle-analyzer 進(jìn)行分析可得,體積主要來(lái)源于 餓了么UI(體積為 500k),因?yàn)闆](méi)對(duì)其進(jìn)行部分引入拆分組件,導(dǎo)致 webpack 把整個(gè)組件庫(kù)都打包進(jìn)去了。其次就是 vue 本身,體積也達(dá)到了 80k 之大。
所以,對(duì)其進(jìn)行打包優(yōu)化,是一件刻不容緩的事情。
優(yōu)化優(yōu)化主要目的有:
加快資源加載速度,減少用戶(hù)等待的時(shí)間和首頁(yè)白屏?xí)r間,提高用戶(hù)體驗(yàn)。
加快打包速度,不要將時(shí)間浪費(fèi)在等待打包上。
解決第一個(gè)問(wèn)題,很多人都會(huì)想到資源文件放在 CDN 上就好了,沒(méi)錯(cuò),這次我們就是通過(guò) CDN 來(lái)解決加載問(wèn)題。
CDN - 提高加載速度像 vue, element ui 這些比較成熟的框架/組件庫(kù),一般都有免費(fèi)、高速、公共的 cdn 供開(kāi)發(fā)者使用,鑒于大部分用戶(hù)均在國(guó)內(nèi),所以這次使用了 bootcdn 這個(gè)庫(kù)。該庫(kù)熱門(mén)資源比較齊全,各個(gè)版本都有,而且國(guó)內(nèi)訪(fǎng)問(wèn)速度很快,簡(jiǎn)直是開(kāi)發(fā)者的福音。
在 index.html 中引入 vue 和 餓了么組件。
vue-admin-template
因?yàn)橐蕾?lài)是從外部引入的,所以需要告知 webpack 在打包時(shí),依賴(lài)的來(lái)源。
修改 webpack.base.conf.js:
module.exports = { ... externals: { vue: "Vue", "element-ui":"ELEMENT" } }
再一次打包,確實(shí)能極大的壓縮了打包的體積,從 700k 驟減至 130k:
但是隨之而來(lái)的就有問(wèn)題了:
明明我在本地開(kāi)發(fā),但是由于引入了線(xiàn)上的生產(chǎn)版本的 vue 文件,因此 vue-dev-tools 就不能進(jìn)行調(diào)試。
因此,我們需要再次調(diào)整一下 webpack 的配置,webpack.base.conf.js,而且 webpack 注入的 js 總是在最后面的,因此,我們需要 html-webpack-include-assets-plugin 幫忙在注入 app.js 后,再注入相對(duì)應(yīng)的組件庫(kù) :
const HtmlWebpackIncludeAssetsPlugin = require("html-webpack-include-assets-plugin") const externals = { // 因?yàn)榇虬鼤r(shí),還沒(méi)注入,所以這里要去掉。 // "element-ui":"ELEMENT" } // 生產(chǎn)環(huán)境中使用生產(chǎn)環(huán)境的 vue // 開(kāi)發(fā)環(huán)境繼續(xù)使用本地 node_modules 中的 vue if (process.env.NODE_ENV === "production") { externals["vue"] = "Vue" // 如發(fā)現(xiàn)打包時(shí)依舊將 element-ui 打包進(jìn)入 vendor,可以在打包時(shí)將其加入外部依賴(lài)。 externals["element-ui"] = "ELEMENT" } // 生產(chǎn)環(huán)境默認(rèn)注入 vue // 開(kāi)發(fā)環(huán)境中不注入 const defaultJS = process.env.NODE_ENV === "production" ? [{ path: "https://cdn.bootcss.com/vue/2.4.2/vue.min.js", type: "js" }] : [] const plugins = [ new HtmlWebpackIncludeAssetsPlugin({ assets: defaultJS.concat([ { path: "https://cdn.bootcss.com/element-ui/2.3.2/index.js", type: "js" }, { path: "https://cdn.bootcss.com/element-ui/2.3.2/locale/zh-CN.min.js", type: "js" }, ]), // 是否在 webpack 注入的 js 文件后新增?true 為 append, false 為 prepend。 // 生產(chǎn)環(huán)境中,這些 js 應(yīng)該先加載。 append: process.env.NODE_ENV !== "production", publicPath: "", }) ] module.exports = { ... externals, plugins, ... }
OK,這時(shí)候,既能兼顧打包后的體積大小,也能在開(kāi)發(fā)模式中使用 vue-dev-tool 進(jìn)行調(diào)試。
DLL - 提高打包速度經(jīng)常打包的前端會(huì)發(fā)現(xiàn),很多時(shí)候,我們?yōu)榱诵迯?fù)某些bug(如 promise 在 ie Safari 下的 bug),而新引入了一個(gè) polyfill,然而,打包完后發(fā)現(xiàn),vendor 的 hash 值變了,而整個(gè) vendor 只新加了一個(gè) es6-promise 的依賴(lài),但是付出的代價(jià)就是,需要拋棄之前打包好的 vendor,用戶(hù)重新訪(fǎng)問(wèn)時(shí),需要再一次拉取一個(gè)全新的 vendor,這個(gè)代價(jià)就有點(diǎn)大了。
這時(shí)候,使用 dllPlugin 打包就有優(yōu)勢(shì)了。它可以將一些基礎(chǔ)依賴(lài)模塊統(tǒng)一先打包起來(lái),當(dāng)正式打包時(shí),則可以略過(guò)這些模塊,不再重復(fù)打包進(jìn)去 vendor,提高打包速度的同時(shí)也能減少 vendor 的體積。
如,后臺(tái)管理系統(tǒng)基礎(chǔ)模塊基本有以下幾個(gè):
axios: ajax 請(qǐng)求。
vuex: 全局狀態(tài)管理。
js-cookie: 前端處理 cookie。
vue-router: 路由管理。
這四個(gè)基礎(chǔ)模塊幾乎是必須的,那么可以先提取出來(lái)。
先在 build 文件夾下新建一個(gè)用于打包 dll 的配置文件 webpack.dll.conf.js:
const webpack = require("webpack"); const path = require("path"); const vueLoaderConfig = require("./vue-loader.conf") const utils = require("./utils") function resolve(dir) { return path.join(__dirname, "..", dir) } const vendor = [ // "vue/dist/vue.runtime.esm.js", // 由于 vue 在生產(chǎn)環(huán)境中使用的是 cdn 引入,所以也無(wú)需提前打包進(jìn) dll // "raven-js", // 前端監(jiān)控,若無(wú)此需求,可以忽略。 "es6-promise", // 修復(fù) promise 中某些 bug。 "vue-router", "js-cookie", "axios", "vuex", ]; const webpackConfig = { context: __dirname, output: { path: path.join(__dirname, "../static/js/"), filename: "[name].dll.js", library: "[name]_[hash]", }, entry: { vendor }, plugins: [ new webpack.DllPlugin({ context: __dirname, path: path.join(__dirname, ".", "[name]-manifest.json"), name: "[name]_[hash]", }), new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false }, sourceMap: true, // parallel: true }) ], module: { rules: [{ test: /.vue$/, loader: "vue-loader", options: vueLoaderConfig }, { test: /.js$/, loader: "babel-loader", include: [resolve("src"), resolve("test"), resolve("node_modules/webpack-dev-server/client")] }, { test: /.(png|jpe?g|gif|svg)(?.*)?$/, loader: "url-loader", options: { limit: 10000, name: utils.assetsPath("img/[name].[hash:7].[ext]") } }, { test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/, loader: "url-loader", options: { limit: 10000, name: utils.assetsPath("media/[name].[hash:7].[ext]") } }, { test: /.(woff2?|eot|ttf|otf)(?.*)?$/, loader: "url-loader", options: { limit: 10000, name: utils.assetsPath("fonts/[name].[hash:7].[ext]") } } ] } }; module.exports = webpackConfig
然后在 package.json 中加入一條命令:
{ "scripts": { ... "build:dll": "webpack --config build/webpack.dll.conf.js", ... } }
執(zhí)行 yarn build:dll 或者 npm run build:dll 即可完成打包 dll。執(zhí)行完成后:
yarn build:dll yarn run v1.5.1 $ webpack --config build/webpack.dll.conf.js Hash: f6894dff019b2e0734af Version: webpack 3.10.0 Time: 1295ms Asset Size Chunks Chunk Names vendor.dll.js 62.6 kB 0 [emitted] vendor [8] dll vendor 12 bytes {0} [built] + 32 hidden modules ? Done in 1.89s.
同時(shí),可以在 build 目錄下,找到各個(gè)模塊對(duì)應(yīng)關(guān)系文件 vendors-manifest.json 和 static/js 下的 vendor.dll.js。
打包后的 dll 文件需要手動(dòng)在 index.html 引入:
修改 build/webpack.prod.conf.js:
module.exports = { plugins: [ ... new webpack.DllReferencePlugin({ context: __dirname, manifest: require("./vendor-manifest.json") }), ... ] }
再次打包:
$ yarn build:report yarn run v1.5.1 $ npm_config_report=true node build/build.js Hash: b4ff51852866ed865cfd Version: webpack 3.10.0 Time: 6532ms Asset Size Chunks Chunk Names static/js/manifest.42b9584a653aec2b9c5e.js 1.5 kB 5 [emitted] manifest static/img/404.a57b6f3.png 98.1 kB [emitted] static/js/1.9e4133a25808e2101dd3.js 1 kB 1 [emitted] static/js/2.2a8a8e01c51473fab882.js 4.34 kB 2 [emitted] static/js/vendor.c7b076ef3341d4711402.js 39.4 kB 3 [emitted] vendor static/js/app.6d52c7a5bf1bacb5cc85.js 21.4 kB 4 [emitted] app static/js/0.cbc645864aab28ae8055.js 15.3 kB 0 [emitted] static/css/app.1b30f8eba210e245a5f96d7bf0d6fb6c.css 7.6 kB 4 [emitted] app favicon.ico 67.6 kB [emitted] index.html 986 bytes [emitted] static/js/vendor.dll.js 62.6 kB [emitted] Build complete. Tip: built files are meant to be served over an HTTP server. Opening index.html over file:// won"t work.
發(fā)現(xiàn) vendor 現(xiàn)在只有 40k 的體積,減少了一半的體積,而且打包速度也快了 2s,而相對(duì)于最開(kāi)始的基礎(chǔ)模板,打包速度快了 12s,這是很讓人欣慰。
后記使用了 cdn 和 dll 打包后,無(wú)論是打包速度還是頁(yè)面加載的速度都有很大的提升。因此將此次優(yōu)化記錄下來(lái),并傳上了 GitHub 中。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/95022.html
摘要:原文地址對(duì)于沒(méi)有了解過(guò)的童鞋,建議先去看看官方的教程傳送門(mén)新版本的新特性插件使用的插件,可以很快的搭建一個(gè)項(xiàng)目的結(jié)構(gòu)。使用時(shí)直接引入即可。的界面讓管理項(xiàng)目變得更加簡(jiǎn)單。如遷移過(guò)程中有任何疑問(wèn),可以留言一起探討。 原文地址 對(duì)于沒(méi)有了解過(guò) vue-cli3 的童鞋,建議先去看看官方的教程: 傳送門(mén) 新版本的新特性 1. 插件 使用 cli 的插件,可以很快的搭建一個(gè)項(xiàng)目的結(jié)構(gòu)。如 ax...
摘要:用戶(hù)體驗(yàn)的需求,完美地保留了瀑布流模態(tài)框的閱讀模式。不支持的話(huà),就不攔截瀑布流文塊的,也就是直接讓其跳轉(zhuǎn)。 背景 想當(dāng)年,我做了一個(gè)新媒體網(wǎng)站項(xiàng)目(AIISPO,已下線(xiàn))。跟普通資訊網(wǎng)站不一樣的是,老板要求PC端前臺(tái)的文章閱讀模式一定得是瀑布流+模態(tài)框。瀑布流指的是以瀑布流的形式將文章羅列出來(lái),而模態(tài)框則指的是點(diǎn)擊瀑布流中代表文章的某個(gè)文塊時(shí),直接在當(dāng)前頁(yè)面彈出模態(tài)框來(lái)顯示文章正文。 ...
摘要:用戶(hù)體驗(yàn)的需求,完美地保留了瀑布流模態(tài)框的閱讀模式。不支持的話(huà),就不攔截瀑布流文塊的,也就是直接讓其跳轉(zhuǎn)。 背景 想當(dāng)年,我做了一個(gè)新媒體網(wǎng)站項(xiàng)目(AIISPO,已下線(xiàn))。跟普通資訊網(wǎng)站不一樣的是,老板要求PC端前臺(tái)的文章閱讀模式一定得是瀑布流+模態(tài)框。瀑布流指的是以瀑布流的形式將文章羅列出來(lái),而模態(tài)框則指的是點(diǎn)擊瀑布流中代表文章的某個(gè)文塊時(shí),直接在當(dāng)前頁(yè)面彈出模態(tài)框來(lái)顯示文章正文。 ...
摘要:重構(gòu)總共耗時(shí)個(gè)工作日。第一個(gè)重構(gòu)原因就是沒(méi)有引入靜態(tài)類(lèi)型,導(dǎo)致查看一個(gè)對(duì)象結(jié)構(gòu)需要翻來(lái)覆去在多個(gè)文件中查找。第三是各個(gè)狀態(tài)模塊耦合度高,加大了代碼維護(hù)難度。但如果耦合度過(guò)高,往往是因?yàn)槟K沒(méi)有細(xì)分到位。這個(gè)項(xiàng)目也不列外。 showImg(https://segmentfault.com/img/remote/1460000019660483); 不知不覺(jué)已是2019年的7月,恍惚之間已...
閱讀 4012·2021-11-18 13:22
閱讀 1829·2021-11-17 09:33
閱讀 2886·2021-09-26 09:46
閱讀 1220·2021-08-21 14:11
閱讀 2896·2019-08-30 15:53
閱讀 2717·2019-08-30 15:52
閱讀 1914·2019-08-30 10:52
閱讀 1528·2019-08-29 15:30