關(guān)于優(yōu)化的建議和配置補充

想了很久暇唾,在之前的webpack教程中,也僅僅只是教了大家独泞,如何使用webapck4手?jǐn)]一份vue可用的配置呐矾,但是在我的實際工作中,會遇到很多需要優(yōu)化的地方懦砂,例如:cdn加速蜒犯, gzip等這些操作,再加上荞膘,原本的那一份教程罚随,在css和css預(yù)處理器的操作上,有很多的不足和細(xì)微的問題∮鹱剩現(xiàn)在一點點的捋出來淘菩,希望能夠幫到大家。

  • 首先就是關(guān)于css和css預(yù)處理器的設(shè)置上屠升,由于當(dāng)時時間問題潮改,很草率地就直接自己寫上了,問題是沒有問題腹暖,但是相比vue-cli2生成的那個配置汇在,我還是有很多的不足,現(xiàn)在我就在vue-cli2的基礎(chǔ)上脏答,對其進(jìn)行修改糕殉,接上篇的配置信息亩鬼,我們還需要在utlis.js中添加對css的處理代碼如下

關(guān)于部分css類的loader的優(yōu)化方案

// 將css類loader放到這里一并處理,不再寫在dev和prod中了
exports.cssLoaders = function (options) {
    options = options || {}

    const cssLoader = {
        loader: 'css-loader',
        options: {
            sourceMap: options.sourceMap
        }
    }

    const postcssLoader = {
        loader: 'postcss-loader',
        options: {
            sourceMap: options.sourceMap
        }
    }

    // 這里就是生成loader和其對應(yīng)的配置
    function generateLoaders(loader, loaderOptions) {
        const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]

        if (loader) {
            loaders.push({
                loader: loader + '-loader',
                options: Object.assign({}, loaderOptions, {
                    sourceMap: options.sourceMap
                })
            })
        }

        // 當(dāng)配置信息中開啟此項時阿蝶,啟用css分離壓縮
        // 這一項在生產(chǎn)環(huán)境時雳锋,是默認(rèn)開啟的
        if (options.extract) {
            return [MiniCssPlugin.loader].concat(loaders)
        } else {
            // 如果不開啟則讓vue-style-loader來處理
            return ['vue-style-loader'].concat(loaders)
        }
    }

    // https://vue-loader.vuejs.org/en/configurations/extract-css.html
    return {
        css: generateLoaders(),
        postcss: generateLoaders(),
        less: generateLoaders('less'),
        sass: generateLoaders('sass', { indentedSyntax: true }),
        scss: generateLoaders('sass'),
        stylus: generateLoaders('stylus'),
        styl: generateLoaders('stylus')
    }
}

// 根據(jù)上面的函數(shù)遍歷出來的各個css預(yù)處理器的loader進(jìn)行最后的拼裝
exports.styleLoaders = function (options) {
    const output = []
    const loaders = exports.cssLoaders(options)

    for (const extension in loaders) {
        const loader = loaders[extension]
        output.push({
            test: new RegExp('\\.' + extension + '$'),
            use: loader
        })
    }

    return output
}
  • 完整的utils.js呢,我也放上來吧羡洁,以免有的朋友不大知道這段代碼該加在什么位置
'use strict'
const path = require('path')
const packageConfig = require('../package.json')
const config = require('../config')
// 這里為什么要引入這個呢玷过,由于webpack4的原因,需要用到這個插件的loader
const MiniCssPlugin = require('mini-css-extract-plugin');

// 將資源文件合并到config文件中的配置項中
exports.assetsPath = function (_path) {
    const assetsSubDirectory = process.env.NODE_ENV === 'production'
        ? config.build.assetsSubDirectory
        : config.dev.assetsSubDirectory

    return path.posix.join(assetsSubDirectory, _path)
}
// 將css類loader放到這里一并處理焚廊,不再寫在dev和prod中了
exports.cssLoaders = function (options) {
    options = options || {}

    const cssLoader = {
        loader: 'css-loader',
        options: {
            sourceMap: options.sourceMap
        }
    }

    const postcssLoader = {
        loader: 'postcss-loader',
        options: {
            sourceMap: options.sourceMap
        }
    }

    // 這里就是生成loader和其對應(yīng)的配置
    function generateLoaders(loader, loaderOptions) {
        const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]

        if (loader) {
            loaders.push({
                loader: loader + '-loader',
                options: Object.assign({}, loaderOptions, {
                    sourceMap: options.sourceMap
                })
            })
        }

        // 當(dāng)配置信息中開啟此項時冶匹,啟用css分離壓縮
        // 這一項在生產(chǎn)環(huán)境時,是默認(rèn)開啟的
        if (options.extract) {
            return [MiniCssPlugin.loader].concat(loaders)
        } else {
            return ['vue-style-loader'].concat(loaders)
        }
    }

    // https://vue-loader.vuejs.org/en/configurations/extract-css.html
    // 返回對應(yīng)的loader
    return {
        css: generateLoaders(),
        postcss: generateLoaders(),
        less: generateLoaders('less'),
        sass: generateLoaders('sass', { indentedSyntax: true }),
        scss: generateLoaders('sass'),
        stylus: generateLoaders('stylus'),
        styl: generateLoaders('stylus')
    }
}

// 根據(jù)上面的函數(shù)遍歷出來的各個css預(yù)處理器的loader進(jìn)行最后的拼裝
// 這里的options就是在調(diào)用的時候向內(nèi)傳遞一些loader的配置信息咆瘟,比如map文件等
exports.styleLoaders = function (options) {
    const output = []
    const loaders = exports.cssLoaders(options)

    for (const extension in loaders) {
        const loader = loaders[extension]
        output.push({
            test: new RegExp('\\.' + extension + '$'),
            use: loader
        })
    }

    return output
}
// 當(dāng)出現(xiàn)報錯時嚼隘,彈出系統(tǒng)彈窗告知出現(xiàn)錯誤
exports.createNotifierCallback = () => {
    const notifier = require('node-notifier')

    return (severity, errors) => {
        if (severity !== 'error') return

        const error = errors[0]
        const filename = error.file && error.file.split('!').pop()
        // 這里是設(shè)置當(dāng)出現(xiàn)錯誤時,給你的袒餐,標(biāo)題飞蛹,錯誤信息,錯誤文件地址灸眼,以及圖標(biāo)
        notifier.notify({
            title: packageConfig.name,
            message: severity + ': ' + error.name,
            subtitle: filename || '',
            // icon: path.join(__dirname, 'logo.png')
        })
    }
}

// 獲取本地局域網(wǎng)ip
exports.getNetworkIp = () => {
    const os = require('os');
    let needHost = ''; // 打開的host
    try {
        // 獲得網(wǎng)絡(luò)接口列表
        let network = os.networkInterfaces();
        for (let dev in network) {
            let iface = network[dev];
            for (let i = 0; i < iface.length; i++) {
                let alias = iface[i];
                if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
                    needHost = alias.address;
                }
            }
        }
    } catch (e) {
        needHost = 'localhost';
    }
    return needHost;
}
  • 然后我們需要在原webpack.dev.js和webpack.prod.js中去修改我們之前的rules:
    //  開發(fā)環(huán)境下
    ...
    mode: 'development',
    devtool: config.dev.devtool,
    module: {
        // 將之前的rules數(shù)組直接替換成下面的樣子
        rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
    },
    output: {
        filename: '[name].js',
    }
    ...
    // 生產(chǎn)環(huán)境下
    mode: 'production',
    devtool: config.build.productionSourceMap ? config.build.devtool : false,
    module: {
        // 將之前的rules數(shù)組直接替換成下面的樣子
        rules: utils.styleLoaders({
            // 是否開啟css的map映射
            sourceMap: config.build.productionSourceMap,
            // 該選項是是否開啟css分離壓縮的選項
            extract: true,
            // 是否使用postcss-loader添加瀏覽器前綴
            usePostCSS: true
        })
    },
    output: {
        path: config.build.assetsRoot,
    },
    ...
  • 好啦卧檐,大家應(yīng)該就很清楚了,在這里我們使用了utlis中的styleLoaders函數(shù)焰宣,由上面的代碼我們就就可以知道霉囚,該函數(shù)接收至多三個對象 sourceMapextract匕积,usePostCSS盈罐;他們均是一個布爾值,從左到右分別表示闪唆,是否打開css的map文件盅粪,是否開啟css抽取壓縮,是否為一些css樣式添加瀏覽器前綴悄蕾。至此票顾,我們就可以徹底的放心大膽的使用市面上已有的css預(yù)處理器,因為在utlis中的cssLoaders函數(shù)中帆调,我們看到奠骄,它會返回你設(shè)置好的所有的預(yù)處理器loader,這樣我們就不用再兩個webpack文件中都要去設(shè)置番刊,只需要當(dāng)出了新的css預(yù)處理器的時候含鳞,加到這里就好了。

當(dāng)依賴庫十分龐大時撵枢,dev緩慢的問題

很多時候民晒,項目的依賴非常的多,這就導(dǎo)致了每次更改之后熱更新需要等很久的時候锄禽,那么此時潜必,我們就需要使用dll來解決這個問題了,當(dāng)然沃但,和win上的dll文件是有很大的區(qū)別的磁滚,我們需要使用的是 webpack自帶的 DllPlugin插件,現(xiàn)在附上我的代碼:


const path = require('path');
const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const webpackbar = require('webpackbar')
module.exports = {
    mode: 'development',
    entry: {
        // 這里就是添加
        vendor: ['axios', 'element-ui', 'vue', 'vue-router', 'echarts']
    },
    output: {
        filename: '[name].dll.js',
        path: path.resolve(__dirname, 'dist'),
        library: '_dll_[name]',
    },
    plugins: [
        new CleanWebpackPlugin(),//clean dist
        new webpack.DllPlugin({
            name: '_dll_[name]',
            path: path.join(__dirname, 'dist', '[name].manifest.json'),
        }),
        new webpackbar({
            name: "抽取依賴中",
        })
    ],
};
  • 然后我們在package.json中添加腳本 "dll":"webpack --config webpack.vendor.js"在每次添加了大型依賴之前可以將其加入vendor數(shù)組內(nèi)宵晚,并且執(zhí)行 npm run dll垂攘,這樣每次編譯的時候,就不會帶上那些大型依賴淤刃,也就不會導(dǎo)致每次更改一個字編譯都要等很久的囧場景了~

關(guān)于cdn加速的一些建議

隨著需求越來越多晒他,各種依賴庫也越來越多,如果是跨平臺應(yīng)用還好逸贾,資源加載都在本地陨仅,不需要用戶從我們服務(wù)器下載,但是铝侵,線上的站怎么辦灼伤,我們的服務(wù)器帶寬有限,壓根就沒法顧及這些咪鲜,此時狐赡,cdn會給我們一些幫助,使用cdn可以將我們的一些依賴放在他們的服務(wù)器中分發(fā)疟丙,好處不言而喻颖侄,在去除了依賴庫的情況下,我們的代碼再加上進(jìn)行了壓縮隆敢,分包等一系列處理发皿,不僅僅只是縮短了首屏啟動的時間,那么現(xiàn)在來貼代碼:

// 在原打包分析下添加或者除配置對象中的任意位置
// 這里有涉及到config文件夾中index文件的build對象
// 那么我們肯定也要在config文件中做對應(yīng)的設(shè)置了
if (config.build.cdn) {
    // 此處是從config中讀取NeedCdnModuleName
    options.externals = config.build.NeedCdnModuleName
    // 這里按需加載了一個依賴拂蝎,所以穴墅,您需要安裝它
    const WebpackCdnPlugin = require('webpack-cdn-plugin');
    options.plugins.push(new WebpackCdnPlugin({
        modules: config.build.NeedCdnModuleAddress
    }))
}
  • 關(guān)于config文件夾中index文件的內(nèi)容則是在其build對象下新添代碼
build:{
        // 此處配置可使用插件自動配置需要cdn加速的模塊
        // 你可能需要執(zhí)行 npm i webpack-cdn-plugin -D 命令來安裝這個依賴
        cdn: false,
        // 需要說明的是,這個里温自,用于配置需要被webpack忽略的依賴包名
        // 左邊是npm安裝時的名字玄货,而右邊則是該包對全局暴漏的名字
        // 如果不知道全局名稱怎么辦,
        // 詳情配置請參考:https://webpack.docschina.org/configuration/externals/
        // 該插件默認(rèn)走的是https://unpkg.com cdn服務(wù)器
        NeedCdnModuleName: {
            vue: 'Vue',
            'vue-router': 'VueRouter',
        },
        // 這里則是被webpack忽略之后悼泌,加載cdn
        // name表示該模塊在npm中的命名松捉,var表示該模塊全局變量名稱,應(yīng)當(dāng)和上面右側(cè)設(shè)置一致
        // path則代表是該模塊在unpkg中的文件路徑馆里,如果不清楚清去該站點自行查詢隘世。
        // 詳情配置請參考:https://www.npmjs.com/package/webpack-cdn-plugin
        NeedCdnModuleAddress: [{
            name: 'vue',
            var: 'Vue',
            path: 'dist/vue.runtime.min.js',
        }, {
            name: 'vue-router',
            var: 'VueRouter',
            path: 'dist/vue-router.min.js',
        }],
}

這里需要提一下可柿,在vue中,當(dāng)你在main中引入了依賴庫的css時丙者,如果你沒有判斷就直接使用import的話复斥,css則部分時沒有加入cdn的,這里需要注意一下械媒,在demo中目锭,我會追加跟多本文中額外的信息,畢竟很多東西只看文章還是太抽象纷捞,結(jié)合代碼學(xué)習(xí)痢虹,是最快的。

關(guān)于啟用gzip

有時候主儡,我們即使使用了cdn加速奖唯,剔除了所有的依賴,但是我們站本身的代碼就非常的龐大缀辩,分包之后依舊還有100k以上的大小時臭埋,(可能你們會說100k沒什么嘛,可以忽略了臀玄,那么這個就可以忽略查看)我們可以啟用gzip瓢阴,將我們的代碼放到壓縮包中在傳到用戶計算機上時,由瀏覽器解壓執(zhí)行健无;此時我們需要使用 compression-webpack-plugin荣恐,該插件支持三種壓縮算法 brotliCompressgzip 還有 zopfli 至于哪種更好,就不在本文的闡述范圍內(nèi)了累贤,上代碼:

// 您可以選擇添加在cdn下面
// 當(dāng)config中對應(yīng)項為true時,啟用gzip功能
if (config.build.gzip) {
    const CompressionPlugin = require('compression-webpack-plugin');
    options.plugins.push(new CompressionPlugin({
        // 這里如果算法為brotliCompress的話,需要將gz改為br
        filename: '[path].gz[query]',
        // 壓縮算法,這里的話,你可以選擇brotliCompress和gzip還有zopfli,當(dāng)然這一切要取決于用戶的瀏覽器支持哪種壓縮模式
        // 若要使用brotliCompress算法,需要nodejs11.7以上.并且后綴名為.br
        algorithm: 'gzip',
        // 根據(jù)config文件設(shè)置的情況對什么文件進(jìn)行壓縮
        test: new RegExp(
            '\\.(' +
            config.build.productionGzipExtensions.join('|') +
            ')$'
        ),
        // 超過該大小就會壓縮(單位:字節(jié))
        threshold: 10240,
        // 壓縮比,官方給的解釋設(shè)置0.8是最佳了.至于計算公式,就是minRatio = 壓縮后的大小 / 原來的大小
        // 當(dāng)壓縮比比這個低的話,就會進(jìn)行壓縮處理,如果設(shè)置成1的話,就是全部都處理了.
        minRatio: 0.8,
        // 是否刪除原文件(默認(rèn)也是false)
        // 這這里并不推薦刪除源文件,因為需要照顧到不支持gzip的瀏覽器
        deleteOriginalAssets: false,
    })
    )
}
  • 同樣附上config中的代碼
// 此處配置是是否使用gzip功能對代碼進(jìn)行高強度的壓縮(值得注意的是gzip功能需要nginx做出對應(yīng)的配置,謹(jǐn)慎開啟)
// 你可能需要執(zhí)行 npm i compression-webpack-plugin -D 命令來安裝這個依賴
// 因為本包中可能會不帶這項依賴叠穆,畢竟不是每個人都需要
gzip: false,
// 這里設(shè)置需要被壓縮的文件后綴默認(rèn)是只壓縮css和js
productionGzipExtensions: ['js', 'css']
  • 這里,注釋中也說明了臼膏,需要nginx或者您所知道您項目中所使用承載頁面具備 httpServer 的服務(wù)器中去配置硼被,開啟gzip或是其他的壓縮選項。

關(guān)于控制臺的友好化輸出

在Nuxt中我發(fā)現(xiàn)其控制臺的進(jìn)度條不僅僅可以給開發(fā)者一個進(jìn)度告知渗磅,并且還會顯示當(dāng)前正在加載什么嚷硫,幸運的是,他們將這個插件開源了出來始鱼,廢話不多說仔掸,開整!

  • 首先是安裝該插件 npm i webpackbar -D 然后在我們的webpack公共配置中加入
const webpackbar = require('webpackbar')
/*這里是其他代碼*/
// 在插件數(shù)組中加入
plugins: [
    // 該插件支持一個名稱医清,可用于控制臺輸出
        new webpackbar({
            name: "",
        })
    ],

然后我們重啟一次webpack起暮,就看到對應(yīng)的效果了。其實還有更多的webpack的操作臺輸出插件会烙,但是它們在win上表現(xiàn)非常差负懦,所以我就不再介紹~

本系列教程已經(jīng)綜合到github中筒捺,您可以訪問這里,查看完整文檔纸厉,以及示例代碼焙矛。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市残腌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌贫导,老刑警劉巖抛猫,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異孩灯,居然都是意外死亡闺金,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門峰档,熙熙樓的掌柜王于貴愁眉苦臉地迎上來败匹,“玉大人,你說我怎么就攤上這事讥巡∠颇叮” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵欢顷,是天一觀的道長槽棍。 經(jīng)常有香客問我,道長抬驴,這世上最難降的妖魔是什么炼七? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮布持,結(jié)果婚禮上豌拙,老公的妹妹穿的比我還像新娘。我一直安慰自己题暖,他們只是感情好按傅,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著芙委,像睡著了一般逞敷。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上灌侣,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天推捐,我揣著相機與錄音,去河邊找鬼侧啼。 笑死牛柒,一個胖子當(dāng)著我的面吹牛堪簿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播皮壁,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼椭更,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蛾魄?” 一聲冷哼從身側(cè)響起虑瀑,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎滴须,沒想到半個月后舌狗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡扔水,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年痛侍,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片魔市。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡主届,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出待德,到底是詐尸還是另有隱情君丁,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布将宪,位于F島的核電站谈截,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏涧偷。R本人自食惡果不足惜簸喂,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望燎潮。 院中可真熱鬧喻鳄,春花似錦、人聲如沸确封。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽爪喘。三九已至颜曾,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間秉剑,已是汗流浹背泛豪。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人诡曙。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓臀叙,卻偏偏與公主長得像,于是被迫代替她去往敵國和親价卤。 傳聞我的和親對象是個殘疾皇子劝萤,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 人到中年 有些人說床嫌,人到中年,人生不再有夢想胸私,于是便每天重復(fù)“昨天”的故事既鞠。美國管理學(xué)家德魯克卻強調(diào),人的一生要不...
    蔣銘國江西樂平閱讀 171評論 0 1
  • 九年(公元204年) 1、 春龄恋,正月疙驾,曹操渡過黃河,阻遏淇水郭毕,將河水引入白溝它碎,作為運輸糧草的運河。 二月显押,袁尚再次...
    華杉2009閱讀 1,508評論 1 12
  • 今天第一個任務(wù)扳肛,就是助那無用補天之石,讓他去富貴鄉(xiāng)里經(jīng)歷一番乘碑。而第二個任務(wù)是什么呢挖息?請往下看: 1、和尚道士下世的...
    向陽春麗閱讀 266評論 0 0
  • 818高三寄語9月16日 【高考倒計時】今天是2019年9月16日兽肤,距離2020年高考還剩265天! 孩子成長的每...
    快樂星貓_55fd閱讀 431評論 0 1
  • 初識三毛: 我清晰的記得套腹,拿起三毛的第一本書是《雨季不再來》,文中盡數(shù)描寫了三毛逃課资铡、去墳?zāi)苟训鹊胤街皇菫?..
    憶聽雨軒閱讀 852評論 2 11