重構之路:webpack打包體積優化(超詳細)

開始

這一章講打包體積優化,這個也算是最重要的一章了,我以前但是花了不少時間去查資料怎麼優化打包體積的,不一樣版本的webpack之間還有一些區別,因此也算踩了不少的坑,因此這一章會比較長。javascript

這邊我大概寫了一下頁面具體佈局,是下面這樣的:css

在這裏插入圖片描述
咱們再去看一下打包體積,有2.75M,已經算很大了:
在這裏插入圖片描述
咱們使用一個打包可視化的插件來看看都有什麼被打包進去了,咱們執行:

yarn add webpack-bundle-analyzer -D
複製代碼

在webpack.config.prod.js的plugins裏添加一行,注意端口能夠修改,別衝突了:html

new BundleAnalyzerPlugin({ analyzerPort: 8081 })
複製代碼

修改完成後,執行yarn run build命令,在瀏覽器彈出窗口,個人是這樣的: java

在這裏插入圖片描述
能夠清晰的看到antd和react-dom就佔了一半多,下面來優化。

1. 修改mode

咱們去webpack.config.prod.js裏:node

//mode:'development'
mode:'production' //修改爲生產環境
複製代碼

而後查看打包體積,瞬間減小了一半多,修改爲開發環境webpack會自動的去優化包體積,好比壓縮代碼之類的: react

在這裏插入圖片描述
在這裏插入圖片描述

2. antd按需加載

在控制檯執行:webpack

yarn add babel-plugin-import -D
複製代碼

而後去webpack.config.common.js配置:web

plugins:[
               	"@babel/plugin-transform-runtime",
                 ['import',{
                     libraryName:'antd',
                     libraryDirectory: 'es',
                     style:true
                 }]
             ]
複製代碼

在less的配置裏修改:json

{
         loader:'less-loader',
           options:{
              javascriptEnabled: true
           }
    }
複製代碼

而後咱們去使用到antd組件的地方,修改爲如下這樣的形式引入:瀏覽器

// import Col from 'antd/lib/col';
// import Row from 'antd/lib/row';
// import "antd/dist/antd.css"; //css也去掉
import {Col,Row} from 'antd'
複製代碼

再執行打包命令,變成601kb:

在這裏插入圖片描述
在這裏插入圖片描述

3. mini-css-extract-plugin提取css

咱們使用mini-css-extract-plugin來將css從js裏分離出來。在控制檯執行:

yarn add mini-css-extract-plugin -D
複製代碼

在webpack.config.prod.js裏配置:

//在頂部引入
const MiniCssExtractPlugin=require('mini-css-extract-plugin');

//在plugins裏添加
new MiniCssExtractPlugin({//提取css
            filename:'css/main.css'
        }),
複製代碼

這樣咱們能夠將css單獨分離到css文件夾裏。而後再打包看看:

在這裏插入圖片描述
在這裏插入圖片描述
咱們發現js包變小,css也被分離出來了,可是css竟然有223kb,打開css文件,咱們發現css沒有被壓縮掉。

咱們在控制檯執行,這兩個插件前者是壓縮css的,後者是壓縮js的,原本在生產環境下會壓縮js的,可是使用optimize-css-assets-webpack-plugin會致使壓縮js無效,因此咱們須要額外引入一個壓縮js的插件:

yarn add optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D
複製代碼

咱們在webpack.config.common.js裏配置:

//這個配置和module,plugins是同級的
optimization:{
        minimizer:[
            new UglifyJsPlugin({//壓縮js
                cache:true,
                parallel:true,
                sourceMap:true
            }),
            new OptimizeCSSAssetsPlugin()//壓縮css
        ]
    },
複製代碼

而後咱們去打包,咱們發現css已經變小了:

在這裏插入圖片描述

4. DllPlugin和DllReferencePlugin

在以前的打包圖咱們能夠看見包體積大部分是被react全家桶和babel佔用了,如今咱們把這些給拿出來單獨放到一個js文件裏,由於這些東西咱們是不會去改變它的。

咱們在根目錄下新建一個==webpack.config.dll.js==,而後在裏面配置,由於DllPLugin是webpack下的,因此咱們不用下載:

const path=require('path')
const webpack =require('webpack')
const CleanWebpackPlugin  = require('clean-webpack-plugin');

//只須要使用yarn run dll一次就行
module.exports={
    mode:'production',
    entry:{
    	//這裏把react方面的東西和babel放到這裏
        vendor:['react','react-dom','react-router-dom']
    },
    output:{
        filename:'dll/_dll_[name].js',
        path:path.resolve(__dirname,'dist'),
        library:'_dll_[name]'
    },
    plugins:[
        new webpack.DllPlugin({
            name:'_dll_[name]',
            path:path.resolve(__dirname,'dist/dll','mainfist.json')
        }),
        new CleanWebpackPlugin(['./dist/dll']),//刪除dll目錄下的文件
    ]
}
複製代碼

再去==webpack.config.common.js==裏配置:

//在plugins下新增
new webpack.DllReferencePlugin({
     manifest: path.resolve(__dirname, 'dist/dll', 'mainfist.json')
}),
複製代碼

而後去package.json.裏配置:

//在scripts下面新增一條這個
"dll": "webpack --config webpack.config.dll.js"
複製代碼

在控制檯執行:

yarn run dll
複製代碼

在這裏插入圖片描述
咱們發現已經被打包出來了,咱們還須要去public/index.html進行引入:

//在body最後新增
<script src="dll/_dll_vendor.js"></script>
複製代碼

而後去執行yarn run build:

在這裏插入圖片描述
在這裏插入圖片描述
文件大小又變小了。

5. @babel/polyfill

咱們在以前的圖裏能夠看見,core-js佔用了很大的一部分體積,這個就是babel/polyfill使用的庫。這裏我提供兩種方法。

1.@baebl/polyfill按需加載

咱們可使用useBuiltIns這個屬性,這個屬性是babel7新增的,咱們須要這樣配置:

presets:[
    [
        '@babel/preset-env',
        {
            "targets": {
                "browsers": [
                    "ie >=9",
                    "last 2 version",
                    "> 5%",
                    "not dead"
                ]
            },
            "useBuiltIns":"usage"
        }
    ],
    '@babel/preset-react'
],
複製代碼

當咱們這樣配置以後,咱們就能夠把index.js頂部的

//import '@babel/polyfill' //能夠去掉這一行了
複製代碼

而後咱們再打包,執行yarn run build:

在這裏插入圖片描述
在這裏插入圖片描述
這個時候打包體積變成了132kb,可是我在使用這種方法的時候,在ie11下能夠正常顯示,在ie10及如下就出現下面的錯誤了,:
在這裏插入圖片描述
目前我還沒找到解決方法,有解決方法的麻煩也跟我說一下,謝謝了。若是你不須要兼容ie10或如下的話可使用這種方法。

2.提取@baebl/polyfill

第二種方法,咱們能夠直接提取@babel/polyfill,就像react全家桶同樣。咱們去==webpack.config.dll.js==裏配置:

//添加@babel/polyfill
vendor:['react','react-dom','react-router-dom','@babel/polyfill']
複製代碼

而後去index.js的頂部添加:

import '@babel/polyfill'
複製代碼

而後咱們去執行yarn run dll,能夠看見vendor的包變大了:

在這裏插入圖片描述
而後咱們執行yarn run build:
在這裏插入圖片描述
在這裏插入圖片描述
咱們發現包體積和以前的方法差很少,而後咱們去ie下看看:
在這裏插入圖片描述
只有在==ie8==下會出現這樣的錯誤,ie9及以上都是正常顯示的,兼容性算是很不錯了,因此這兩種方法如何取捨就看本身項目需不須要兼容ie了。

6. react-router動態加載(react組件懶加載)

以前咱們是所有的組件都在頁面上加載出來,這樣咱們還沒點擊的組件也會加載,這樣就致使浪費了。咱們使用動態加載來讓點擊到的組件才進行加載就好多了。

咱們在控制檯執行:

yarn add react-loadable babel-plugin-syntax-dynamic-import -D
複製代碼

如何在==webpack.config.common.js==裏配置:

plugins:[
    "@babel/plugin-transform-runtime",
    'babel-plugin-syntax-dynamic-import',//增長這一行
    ['import',{
        libraryName:'antd',
        libraryDirectory: 'es',
        style:true
    }]
]
複製代碼

而後咱們去使用路由的地方修改:

import Loadable from 'react-loadable';//注意要加上這一行
// import A from '../pages/A/A'
// import B from '../pages/B/B'

//修改爲這樣子的寫法
const A = Loadable({
    loader: () => import('../pages/A/A'),
    loading:()=> {
        return <div>Loading...</div>
    }
});
const B = Loadable({
    loader: () => import('../pages/B/B'),
    loading:()=> {
        return <div>Loading...</div>
    }
});
複製代碼

再去執行打包命令,而後查看:

在這裏插入圖片描述
在這裏插入圖片描述
咱們發現包體積變大了,這是由於我如今項目沒寫什麼東西,因此引入了插件後,包就變大了,在組件寫多了以後,這個動態加載能減小不少的體積。

咱們能夠來看一下效果:

頁面剛加載的時候是這樣的

在這裏插入圖片描述
點擊一個路由後變成這樣:
在這裏插入圖片描述
能夠看見動態的加載了一個js文件。

index.js體積解釋

這裏再說一下打包的圖,其實我在src下寫的代碼不多,可是打包圖的這裏有個index.js卻有將近90kb大,這是爲何?其實這個是antd按需加載打包進來的組件,咱們能夠試一下,這個是我如今主頁上大部分使用到的antd組件代碼:

<div>
    <Header/>
    <Row>
        <Col xs={24} sm={24} md={6} lg={4} xl={4} xxl={4}>
            <Aside/>
        </Col>
        <Col xs={24} sm={24} md={18} lg={20} xl={20} xxl={20}>
            <div className="content">
                {this.props.children}
            </div>
        </Col>
    </Row>
</div>
複製代碼

咱們將使用到的antd組件都註釋掉,只留下Header:

//import {Col,Row} from 'antd'

<div>
    <Header/>
    {/*<Row>*/}
        {/*<Col xs={24} sm={24} md={6} lg={4} xl={4} xxl={4}>*/}
            {/*<Aside/>*/}
        {/*</Col>*/}
        {/*<Col xs={24} sm={24} md={18} lg={20} xl={20} xxl={20}>*/}
            {/*<div className="content">*/}
                {/*{this.props.children}*/}
            {/*</div>*/}
        {/*</Col>*/}
    {/*</Row>*/}
</div>
複製代碼

而後咱們再去打包:

在這裏插入圖片描述
在這裏插入圖片描述
如今src下的這個包已經變的很小了。

7. splitChunks

而後咱們將antd之類的第三方庫從主要的包裏分離出來。

咱們在==webpack.config.common.js==裏的optimization裏配置,在和以前咱們寫js和css壓縮的==minimizer==的同級的地方:

splitChunks:{
    cacheGroups:{
        vendors:{//node_modules裏的代碼
            test:/[\\/]node_modules[\\/]/,
            chunks: "initial",
            name:'vendors', //chunks name
            priority:10, //優先級
            enforce:true 
        }
    }
}
複製代碼

而後再去執行打包命令:

在這裏插入圖片描述
在這裏插入圖片描述
咱們能夠發現關於antd的js和css都被抽離出來了,chunk Names爲vendors的就是,而爲main的就是咱們本身寫的代碼,咱們本身寫的其實不多。

雖然antd的組件比較大,但它們只會打包一次,並且在服務端配置gzip的狀況下,體積又能夠減小三分之一多,仍是能夠接受的。

結尾

最後咱們將主包體積從2.75M優化到5kb左右,但其實咱們是將一個大的包拆分紅多個小包,並提取公共代碼。

這裏其實還有一個使用externals的優化方法,而後使用CDN引入,但我這邊已經使用了DllPlugin了,就不使用那種方法了,兩種方法你們能夠合理使用。

這一章寫了太多的東西了,並且稍微有點雜,可是應該也算是挺詳細了,可是我以爲webpack打包體積優化的還不止這些,若是大家還有其餘能優化的方法,也和我說一下,謝謝了。

(ps:若是文章哪裏有錯誤,請在評論指出,謝謝)

相關文章
相關標籤/搜索