博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
重构之路:webpack打包体积优化
阅读量:4085 次
发布时间:2019-05-25

本文共 8667 字,大约阅读时间需要 28 分钟。

开始

这一章讲打包体积优化,这个也算是最重要的一章了,我之前可是花了很多时间去查资料怎么优化打包体积的,不同版本的webpack之间还有一些区别,所以也算踩了很多的坑,所以这一章会比较长。

这边我大概写了一下页面具体布局,是下面这样的:

[图片上传中...(image-aa9cd7-1550917482106-27)]

<figcaption></figcaption>

我们再去看一下打包体积,有2.75M,已经算很大了:[图片上传中...(image-4f9213-1550917482106-26)]

<figcaption></figcaption>

我们使用一个打包可视化的插件来看看都有什么被打包进去了,我们执行:

yarn add webpack-bundle-analyzer -D复制代码

在webpack.config.prod.js的plugins里添加一行,注意端口可以修改,别冲突了:

new BundleAnalyzerPlugin({ analyzerPort: 8081 })复制代码

修改完成后,执行yarn run build命令,在浏览器弹出窗口,我的是这样的:

[图片上传中...(image-3c8555-1550917482106-25)]

<figcaption></figcaption>

可以清晰的看到antd和react-dom就占了一半多,下面来优化。

1. 修改mode

我们去webpack.config.prod.js里:

//mode:'development'mode:'production' //修改成开发环境复制代码

然后查看打包体积,瞬间减少了一半多,修改成开发环境webpack会自动的去优化包体积,比如压缩代码之类的:

[图片上传中...(image-c1463c-1550917482106-24)]

<figcaption></figcaption>

[图片上传中...(image-6ff266-1550917482106-23)]

<figcaption></figcaption>

2. antd按需加载

在控制台执行:

yarn add babel-plugin-import -D复制代码

然后去webpack.config.common.js配置:

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

在less的配置里修改:

{         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:

[图片上传中...(image-ca19be-1550917482106-22)]

<figcaption></figcaption>

[图片上传中...(image-c5326e-1550917482106-21)]

<figcaption></figcaption>

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文件夹里。然后再打包看看:

[图片上传中...(image-4c9235-1550917482106-20)]

<figcaption></figcaption>

[图片上传中...(image-f1bad6-1550917482106-19)]

<figcaption></figcaption>

我们发现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已经变小了:

[图片上传中...(image-3d11be-1550917482106-18)]

<figcaption></figcaption>

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复制代码

[图片上传中...(image-d9d95f-1550917482106-17)]

<figcaption></figcaption>

我们发现已经被打包出来了,我们还需要去public/index.html进行引入:

//在body最后新增复制代码

然后去执行yarn run build:

[图片上传中...(image-ef3b0b-1550917482105-16)]

<figcaption></figcaption>

[图片上传中...(image-f4d624-1550917482105-15)]

<figcaption></figcaption>

文件大小又变小了。

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:

[图片上传中...(image-cd0d8f-1550917482105-14)]

<figcaption></figcaption>

[图片上传中...(image-6f3329-1550917482105-13)]

<figcaption></figcaption>

这个时候打包体积变成了132kb,但是我在使用这种方法的时候,在ie11下可以正常显示,在ie10及以下就出现下面的错误了,:[图片上传中...(image-751734-1550917482105-12)]

<figcaption></figcaption>

目前我还没找到解决方法,有解决方法的麻烦也跟我说一下,谢谢了。如果你不需要兼容ie10或以下的话可以使用这种方法。

2.提取@baebl/polyfill

第二种方法,我们可以直接提取@babel/polyfill,就像react全家桶一样。我们去==webpack.config.dll.js==里配置:

//添加@babel/polyfillvendor:['react','react-dom','react-router-dom','@babel/polyfill']复制代码

然后去index.js的顶部添加:

import '@babel/polyfill'复制代码

然后我们去执行yarn run dll,可以看见vendor的包变大了:

[图片上传中...(image-850f37-1550917482105-11)]

<figcaption></figcaption>

然后我们执行yarn run build:[图片上传中...(image-ac1a1c-1550917482105-10)]

<figcaption></figcaption>

[图片上传中...(image-87d57c-1550917482105-9)]

<figcaption></figcaption>

我们发现包体积和之前的方法差不多,然后我们去ie下看看:[图片上传中...(image-187664-1550917482105-8)]

<figcaption></figcaption>

只有在==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 
Loading...
}});const B = Loadable({ loader: () => import('../pages/B/B'), loading:()=> { return
Loading...
}});复制代码

再去执行打包命令,然后查看:

[图片上传中...(image-c150bb-1550917482105-7)]

<figcaption></figcaption>

[图片上传中...(image-ad182b-1550917482105-6)]

<figcaption></figcaption>

我们发现包体积变大了,这是因为我现在项目没写什么东西,所以引入了插件后,包就变大了,在组件写多了之后,这个动态加载能减少很多的体积。

我们可以来看一下效果:

页面刚加载的时候是这样的

[图片上传中...(image-cbffee-1550917482105-5)]

<figcaption></figcaption>

点击一个路由后变成这样:[图片上传中...(image-eaa21d-1550917482105-4)]

<figcaption></figcaption>

可以看见动态的加载了一个js文件。

index.js体积解释

这里再说一下打包的图,其实我在src下写的代码很少,但是打包图的这里有个index.js却有将近90kb大,这是为什么?其实这个是antd按需加载打包进来的组件,我们可以试一下,这个是我现在主页上大部分使用到的antd组件代码:

{this.props.children}
复制代码

我们将使用到的antd组件都注释掉,只留下Header:

//import {Col,Row} from 'antd'
{/*
*/} {/**/} {/*
*/} {/**/} {/**/} {/*
*/} {/*{this.props.children}*/} {/*
*/} {/**/} {/*
*/}
复制代码

然后我们再去打包:

[图片上传中...(image-308206-1550917482105-3)]

<figcaption></figcaption>

[图片上传中...(image-2b76c-1550917482105-2)]

<figcaption></figcaption>

现在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         }    }}复制代码

然后再去执行打包命令:

[图片上传中...(image-33f621-1550917482105-1)]

<figcaption></figcaption>

[图片上传中...(image-45874-1550917482105-0)]

<figcaption></figcaption>

我们可以发现关于antd的js和css都被抽离出来了,chunk Names为vendors的就是,而为main的就是我们自己写的代码,我们自己写的其实很少。

虽然antd的组件比较大,但它们只会打包一次,而且在服务端配置gzip的情况下,体积又可以减少三分之一多,还是可以接受的。

结尾

最后我们将主包体积从2.75M优化到5kb左右,但其实我们是将一个大的包拆分成多个小包,并提取公共代码。

这里其实还有一个使用externals的优化方法,然后使用CDN引入,但我这边已经使用了DllPlugin了,就不使用那种方法了,两种方法大家可以合理使用。

这一章写了太多的东西了,而且稍微有点杂,但是应该也算是挺详细了,但是我觉得webpack打包体积优化的还不止这些,如果你们还有其他能优化的方法,也和我说一下,谢谢了。

(ps:如果文章哪里有错误,请在评论指出,谢谢)

作者:web999_Z

链接:
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的文章
Java8 HashMap集合解析
查看>>
自定义 select 下拉框 多选插件
查看>>
Linux常用统计命令之wc
查看>>
fastcgi_param 详解
查看>>
搞定Java面试中的数据结构问题
查看>>
React Native(一):搭建开发环境、出Hello World
查看>>
Winform多线程
查看>>
Spring AOP + Redis + 注解实现redis 分布式锁
查看>>
poj 1976 A Mini Locomotive (dp 二维01背包)
查看>>
《计算机网络》第五章 运输层 ——TCP和UDP 可靠传输原理 TCP流量控制 拥塞控制 连接管理
查看>>
二叉树深度优先遍历和广度优先遍历
查看>>
生产者消费者模型,循环队列实现
查看>>
获得github工程中的一个文件夹的方法
查看>>
《PostgreSQL技术内幕:查询优化深度探索》养成记
查看>>
PostgreSQL查询优化器详解之逻辑优化篇
查看>>
STM32中assert_param的使用
查看>>
为什么button在设置标题时要用一个方法,而不像lable一样直接用一个属性
查看>>
字符串的截取
查看>>
Tensorflow入门资料
查看>>
剑指_复杂链表的复制
查看>>