90、使用webpack打包的项目优化方案

作者:jcmp      发布时间:2021-04-24      浏览量:0
一、根据可视化工具查看项目打包webpa

一、根据可视化工具查看项目打包

webpack-bundle-analyzer可视化工具

Webpack进行打包,到底打了多少包,每个包有多大?webpack-bundle-analyzer这款插件可以帮助我们清晰展示。针对多余的包文件过大,剔除首次影响加载的效率问题进行剔除修改。

模块功能:

安装和使用:

npm install --save-dev webpack-bundle-analyzer。

//在webpack.config.js中:let BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;module.exports = { plugins: [new BundleAnalyzerPlugin()]}

在vue-cli3中配置如下

//vue.config.jslet BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;module.exports = {configureWebpack: { plugins: [ new BundleAnalyzerPlugin() ] },}

默认的可选配置对象:

启动服务:

生产环境查看:npm run build --report 或 正常build 即可启动查看器。

开发环境查看:webpack -p --progress 或启动正常devServer服务即可启动查看器!

官方请看: webpack-bundle-analyzer。

Speed-Measure-Plugin可视化工具

通过这个插件,我们可以清楚的看到,打包整体的时间,各plugin,loader处理时间,以有利于我们针对打包速度取做优化。

安装和使用:

npm install --save-dev speed-measure-webpack-plugin。

//webpack配置 const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");const smp = new SpeedMeasurePlugin();const webpackConfig = smp.wrap({ plugins: [ new MyPlugin(), new MyOtherPlugin() ]});

官方请看: Speed Measure Plugin

analyse

先使用 Webpack 打包指令生成 Webpack stats 分析文件。

webpack --profile --json > stats.json。

然后到官方提供的网页上传stats.json

Webpack analyse

就可以通过一些可视化资料来分析打包结果

webpack

二、webpack外部扩展

列出了项目中较大的包,剩下的事情就是想办法如何减小这些包的体积(将一个大包拆成多个小包)。 项目中产生较大的包的原因可以从两个方面去考虑:

1. 项目中引入的依赖包过于庞大; 2. 业务代码集中在一块写,或者是业务代码写的比较繁琐;

对于这两个问题,我们可以从两个方面着手解决:

1. 抽离项目中公共依赖的、不常变动的、体积较大的包; 2. 将一个较大的业务代码文件,拆成多个较小的文件,异步加载(或者优化业务代码)。

我们来讨论第一种方法,在不改动业务代码的情况下,如何减小公共依赖。 要知道这些依赖是我们需要的,不可能排除不引入。 但是他们都是全局依赖的,万年不变的,可以使用浏览器自己的缓存来实现不重复加载。 具体做法就是: 将项目中需要的一些公共依赖包,并且不常变动的,单独取出,不再每次都打包编译(如React,Redux等)。 而是通过使用script标签形式cdn引入,这样在有缓存的情况下,这些资源均走缓存,不必加载。

具体做法:

总结需要抽离的公共依赖

这些依赖需要满足一定的条件:

* 体积较大; * 不常更新; * 依赖较多; * 是前置依赖;

常见的满足这类条件的包有:

* react * react-dom * redux * react-redux * moment * jquery。

另外一些包文件如 Antd库文件,整个包较大,但是每次用什么取什么的话,库文件也会按需加载,不必单独取出。 还有这类库文件不建议单独取出,因为里面可能会有bug,需要更新。

使用CDN引入资源

将抽离出来文件放到cnd上,注意,这些文件要是压缩版本,并且是用ES5编写的,否则浏览器报错。

React Starter Kit

配置webpack.conf.js

资源已经引入,接下来需要配置webpack,使其打包的时候不在将这些资源打包。

const webpackConfig = { name: 'client', target: 'web', devtool: config.compiler_devtool, resolve: { root: paths.client(), extensions: ['', '.js', '.jsx', '.json'], }, externals: { 'react': 'React', 'react-dom': 'ReactDOM', 'react-router': 'ReactRouter', 'redux': 'Redux', 'history': 'History' }, module: {},}

这里externals告诉webpack那些资源从哪里寻找。

该对象的键表示 require 或者 import 时候的字符串。

值表示的当前环境下的变量,比如引入React之后,React被作为全局对象,webpack就回去寻找React对象。

如果其中有一个找不到,打包就会失败。

配置vendor.js 接下来配置vendor,使vendor也不打包该些JS。

compiler_vendors : [ // 'react', // 'react-redux', // 'react-router', // 'redux',],

三、DLL方式

dll方式也就是通过配置,告诉webpack指定库在项目中的位置,从而直接引入,不将其打包在内。

上面介绍的方式是将包放到cdn上,build的时候不在引入对应的包;

dll方式就是指定包在项目中,build的时候不在打包对应的包,使用的时候引入。

webpack通过webpack.DllPlugin与webpack.DllReferencePlugin两个内嵌插件实现此功能。

新建webpack.dll.config.js

const webpack = require('webpack');module.exports = { entry: { bundle: [ 'react', 'react-dom', //其他库 ], }, output: { path: './build', filename: '[name].js', library: '[name]_library' }, plugins: [ new webpack.DllPlugin({ path: './build/bundle.manifest.json', name: '[name]_library', }) ]};

webpack.DllPlugin选项:

* path:manifest.json文件的输出路径,这个文件会用于后续的业务代码打包; * name:dll暴露的对象名,要跟output.library保持一致; * context:解析包路径的上下文,这个要跟接下来配置的 webpack.config.js 一致。

运行:

webpack --config webpack.dll.config.js。

生成两个文件,一个是打包好的bundlejs,另外一个是bundle.mainifest.json,大致内容如下:

{ "name": "bundle_library", "content": { "./node_modules/react/react.js": 1, "./node_modules/react/lib/React.js": 2, "./node_modules/process/browser.js": 3, "./node_modules/object-assign/index.js": 4, "./node_modules/react/lib/ReactChildren.js": 5, "./node_modules/react/lib/PooledClass.js": 6, "./node_modules/react/lib/reactProdInvariant.js": 7, //其他引用}

配置webpack.config.js

const webpack = require('webpack');var path = require('path'); module.exports = { entry: { main: './main.js', }, output: { path: path.join(__dirname, "build"), publicPath: './', filename: '[name].js' }, module: { loaders:[ { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}, { test: /\.jsx?$/, loaders: ['babel-loader?presets[]=es2015&presets[]=react'], include: path.join(__dirname, '.') } ] }, plugins: [ new webpack.DllReferencePlugin({ context: '.', manifest: require("./build/bundle.manifest.json"), }), ]};

webpack.DllReferencePlugin的选项中:

* context:需要跟之前保持一致,这个用来指导webpack匹配 * manifest.json中库的路径; * manifest:用来引入刚才输出的manifest.json文件。