進(jìn)階篇——webpack進(jìn)階用法(二)

??上一章節(jié)主要介紹了webpack的進(jìn)階篇中的自動(dòng)清理構(gòu)建帖汞、補(bǔ)齊css前綴戴而、靜態(tài)資源內(nèi)聯(lián)。這一節(jié)主要介紹多頁面應(yīng)用打包翩蘸、使用sourcemap所意、提取頁面公共資源。

1.多頁面應(yīng)用打包通用方案

(1)什么是多頁面應(yīng)用

QQ截圖20200815160815.png

優(yōu)勢(shì):①每個(gè)頁面之間都是解耦的催首;②對(duì)于系統(tǒng)的SEO更加友好

(2)打包思路

QQ截圖20200815161142.png

上面圖是不是很熟悉?扶踊,我們?cè)?a href="http://www.reibang.com/p/f62ec884f214" target="_blank">基礎(chǔ)篇-webpack基礎(chǔ)用法(三)---html文件壓縮里講過,每個(gè)入口文件對(duì)應(yīng)一個(gè)html-webpack-plugin郎任。而且entry都是我們配置好的秧耗,每增加一個(gè)頁面我們就要增加一個(gè)entry和配置一個(gè)html-webpack-plugin,顯得過于繁瑣涝滴,不太友好绣版,有沒有更加通用化的方案呢?如下:
QQ截圖20200815162029.png

就是動(dòng)態(tài)獲取目錄文件歼疮,使用程序思維自動(dòng)配置好文件杂抽。已上圖為例,我們?cè)诖虬氨仨氼A(yù)定好文件必須放在src目錄下面韩脏,如:index.js缩麸、search.js
npm install glob -D
代碼如下

const glob = require('glob');
const path = require('path');

// 設(shè)置多頁面打包
const setMPA = () => {
    const entry = {};
    const htmlWebpackPlugins = [];

    const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js'));

    Object.keys(entryFiles)
        .map((index) => {
            const entryFile = entryFiles[index];

            const match = entryFile.match(/src\/(.*)\/index\.js/);
            const pageName = match && match[1];

            entry[pageName] = entryFile;
            htmlWebpackPlugins.push(
                new HtmlWebpackPlugin({
                    template: path.join(__dirname, `src/${pageName}/index.html`),
                    filename: `${pageName}.html`,
                    chunks: [pageName],
                    inject: true,
                    minify: {
                        html5: true,
                        collapseWhitespace: true,
                        preserveLineBreaks: false,
                        minifyCSS: true,
                        minifyJS: true,
                        removeComments: false
                    }
                }),
            );
        })

    return {
        entry,
        htmlWebpackPlugins
    }
}

module.exports = {
    entry: entry,
    ...
    
    plugins: [
        new MiniCssExtractPlugin({
            filename: '[name]_[contenthash:8].css'
        }),
        new OptimizeCSSAssetsPlugin({
            assetNameRegExp: /\.css$/g,
            cssProcessor: require('cssnano')
        }),
        
        new CleanWebpackPlugin()
    ].concat(htmlWebpackPlugins)
};

這樣我們每次添加頁面時(shí),就不用了手動(dòng)去修改webpack配置了赡矢。

2.使用sourceMap

我們?cè)谑褂脀ebpack進(jìn)行打包的時(shí)候杭朱,它會(huì)把我們的代碼打包成bundle文件,但是在打包的過程中可能會(huì)出現(xiàn)錯(cuò)誤吹散,我們會(huì)發(fā)現(xiàn)控制臺(tái)會(huì)把一大串的錯(cuò)誤代碼打印出來弧械,但是不會(huì)定位到具體的錯(cuò)誤文件,這時(shí)就要輪到我們的sourcemap登場(chǎng)了空民,具體作用如下

QQ截圖20200817202604.png

(1)關(guān)鍵字
QQ截圖20200817202757.png
(2)類型
QQ截圖20200817203040.png
① eval類型的sourcemap
QQ截圖20200817203605.png

npm run build打包之后刃唐,我們打開dist文件下的js文件如下


QQ截圖20200817203736.png

QQ截圖20200817204019.png

我們可以看到羞迷,eval把我們的js文件打包之后用eval()包裹了起來,后面用sourceURL制定文件路徑画饥。

② source map類型
QQ截圖20200817204301.png

導(dǎo)報(bào)之后


QQ截圖20200817204456.png

可以看到衔瓮,它把我們的js文件進(jìn)行了分離,生成了一個(gè)js文件一個(gè).map文件抖甘。我們打開js文件热鞍,拉倒最后一行,會(huì)出現(xiàn)如下一句話


QQ截圖20200817204718.png

這表示衔彻,該js文件要使用的是哪一個(gè)map文件薇宠。
③ inline-source-map類型

QQ截圖20200817204930.png

打包之后
QQ截圖20200817205053.png

可以看到,打包之后的dist文件目錄下已經(jīng)沒有.map文件了米奸,那么它跑到哪里去了呢昼接?
我們打開js文件,拉倒最后一行
QQ截圖20200817205335.png

直接使用sourceMappingURL給引進(jìn)來了悴晰,但是我們也會(huì)發(fā)現(xiàn)這個(gè)js也會(huì)變大許多。

④ 開發(fā)調(diào)試

打開webpack.dev.js文件逐工,如下代碼

'use strict';

const glob = require('glob');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

// 設(shè)置多頁面打包
const setMPA = () => {
    const entry = {};
    const htmlWebpackPlugins = [];

    const entryFiles = glob.sync(path.join(__dirname, './src/*/index.js'));

    Object.keys(entryFiles)
        .map((index) => {
            const entryFile = entryFiles[index];

            const match = entryFile.match(/src\/(.*)\/index\.js/);
            const pageName = match && match[1];

            entry[pageName] = entryFile;
            htmlWebpackPlugins.push(
                new HtmlWebpackPlugin({
                    template: path.join(__dirname, `src/${pageName}/index.html`),
                    filename: `${pageName}.html`,
                    chunks: [pageName],
                    inject: true,
                    minify: {
                        html5: true,
                        collapseWhitespace: true,
                        preserveLineBreaks: false,
                        minifyCSS: true,
                        minifyJS: true,
                        removeComments: false
                    }
                }),
            );
        })

    return {
        entry,
        htmlWebpackPlugins
    }
}

const { entry, htmlWebpackPlugins } = setMPA();

module.exports = {
    entry: entry,
    output: {
        path: path.join(__dirname, 'dist'),
        filename:  '[name].js'
    },
    mode: 'development',
    module: {
        rules: [
            {
                test: /.js$/,
                use: 'babel-loader'
            },
            {
                test: /.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /.less$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                test: /.(png|jpg|gif|jpeg)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 10240
                        }
                    }
                ]
            },
            {
                test: /.(woff|woff2|eot|ttf|otf)$/,
                use: 'file-loader'
            }
        ]
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new CleanWebpackPlugin()
    ].concat(htmlWebpackPlugins),
    devServer: {
        contentBase: './dist',   // 打印目錄下的信息
        hot: true     // 開啟熱更新
    },
    devtool: 'source-map'
};

運(yùn)行
npm run dev

QQ截圖20200817210658.png

可以看到這樣調(diào)試的話铡溪,就能看到源代碼了,而且非常方便調(diào)試泪喊。

⑤ cheap-source-map類型
QQ截圖20200817211017.png

在js文件下故意寫錯(cuò)一行代碼棕硫,如下

QQ截圖20200817211051.png

QQ截圖20200817211408.png

可以看到,cheap-source-map幫我們定位了錯(cuò)誤在哪一個(gè)文件哪一行袒啼,就會(huì)方便開發(fā)調(diào)試了哈扮。

3.提取頁面公共資源

我們?cè)陧?xiàng)目開發(fā)中,可能各個(gè)頁面中使用同一套的資源庫蚓再,或者各個(gè)頁面也有可能使用相同的css樣式滑肉,如果我們?cè)诖虬臅r(shí)候,就會(huì)把這些頁面中的資源都會(huì)打包一份摘仅,這樣就會(huì)降低打包速度靶庙、浪費(fèi)打包資源、是項(xiàng)目的整體資源過大等等娃属,因此我們需要將這些相同資源提取到一個(gè)公共文件中六荒,降低體積。這里我們一react為例矾端。

(1)基礎(chǔ)庫分離

QQ截圖20200818203456.png

entry:可以使第三鏈接掏击,也可以是本地資源地址

(2)利? SplitChunksPlugin 進(jìn)?公共腳本分離

QQ截圖20200818203636.png

minSize(字節(jié)):抽離的公共包最小的大小秩铆;
maxSize(字節(jié)):抽離的公共包最大的大醒馔ぁ;
minChunks:表示一個(gè)方法在項(xiàng)目中使用的最低次數(shù),如果設(shè)置成2钠惩,那就表示這個(gè)方法在項(xiàng)目最低使用2次柒凉,webpack才會(huì)將這個(gè)方法提取成公共方法;
maxAsyncRequests:瀏覽器每次請(qǐng)求一步資源的次數(shù)篓跛。比如瀏覽器在異步請(qǐng)求一個(gè)js時(shí)的次數(shù)超過指定的值時(shí)膝捞,就會(huì)提取成公共資源;

(3)利? SplitChunksPlugin 分離基礎(chǔ)包
QQ截圖20200818204824.png
(4)利? SplitChunksPlugin 分離??公共?件
QQ截圖20200818205004.png
(5)實(shí)戰(zhàn)演練
① html-webpack-externals-plugin

安裝 html-webpack-externals-plugin插件
npm install html-webpack-externals-plugin -D

QQ截圖20200818210449.png

在html中引入react愧沟、react-dom資源
QQ截圖20200818211549.png

構(gòu)建一下


QQ截圖20200818210602.png

對(duì)比以前的打包方式蔬咬,發(fā)現(xiàn)體積差不多小了100K左右。

② SplitChunksPlugin分離
QQ截圖20200818212009.png

構(gòu)建如下


QQ截圖20200818212133.png
③ SplitChunksPlugin分離??公共?件

我們?cè)陧?xiàng)目的根目錄下創(chuàng)建一個(gè)文件沐寺,export一個(gè)函數(shù)林艘,在不同的頁面分別引入一下,配置一下webpack混坞,如下


QQ截圖20200818214927.png

構(gòu)建一下項(xiàng)目


QQ截圖20200818215026.png

會(huì)把公共方法放在了common.js文件里面

總結(jié)

主要學(xué)習(xí)了多頁面應(yīng)用打包通用方案狐援、使用sourceMap、提取頁面公共資源這三個(gè)方面的指示點(diǎn)究孕,下一節(jié)學(xué)習(xí)tree shaking啥酱、scope hoisting、動(dòng)態(tài)分割和import等方法厨诸。
來源極客時(shí)間

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末镶殷,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子微酬,更是在濱河造成了極大的恐慌绘趋,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颗管,死亡現(xiàn)場(chǎng)離奇詭異陷遮,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)忙上,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門拷呆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人疫粥,你說我怎么就攤上這事茬斧。” “怎么了梗逮?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵项秉,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我慷彤,道長(zhǎng)娄蔼,這世上最難降的妖魔是什么怖喻? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮岁诉,結(jié)果婚禮上锚沸,老公的妹妹穿的比我還像新娘。我一直安慰自己涕癣,他們只是感情好哗蜈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坠韩,像睡著了一般距潘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上只搁,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天音比,我揣著相機(jī)與錄音,去河邊找鬼氢惋。 笑死洞翩,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的焰望。 我是一名探鬼主播菱农,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼柿估!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起陷猫,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤秫舌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后绣檬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體足陨,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年娇未,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了墨缘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡零抬,死狀恐怖镊讼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情平夜,我是刑警寧澤蝶棋,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站忽妒,受9級(jí)特大地震影響玩裙,放射性物質(zhì)發(fā)生泄漏兼贸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一吃溅、第九天 我趴在偏房一處隱蔽的房頂上張望溶诞。 院中可真熱鬧,春花似錦决侈、人聲如沸螺垢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽甩苛。三九已至,卻和暖如春俏站,著一層夾襖步出監(jiān)牢的瞬間讯蒲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國打工肄扎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留墨林,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓犯祠,卻偏偏與公主長(zhǎng)得像旭等,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子衡载,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355