重构之路: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:若是文章哪里有错误,请在评论指出,谢谢)

相关文章
相关标签/搜索