渐进式配置webpack4单页面和多页面(二)

栏目: JavaScript · 发布时间: 4年前

内容简介:使用包的版本每个章节对应一个demo参考代码

使用包的版本

webpack ->4.3.0
babel-loader ->8.0.5
npm ->6.4.1
webpack-cli ->3.3.1
复制代码

每个章节对应一个demo

模块化拆包1

参考代码 demo8

什么是模块化拆包。比如我们在项目里面需要引入echarts、xlsx、lodash等比较大的包的时候。如果不做代码拆包,都会打包到一个js文件里面。如果每次打包发版都会生成一个新的js打包文件,用户重新请求页面的时候会再次请求echarts、xlsx、lodash这些不变的代码,就会降低用户体验。模块化拆包将这些不变的依赖包打包成一个新的js文件,每次打包发版的时候用户就不会再次请求echarts、xlsx、lodash这些不变的代码了。

代码更改

webpack-bundle-analyzer 可视化显示打包的JS引用的包

npm i webpack-bundle-analyzer -D
复制代码

在项目里面引入echarts、xlsx、lodash

npm i echarts xlsx lodash -S
复制代码

app.js

import "regenerator-runtime/runtime";
import _ from 'lodash';
import echarts from 'echarts';
import xlsx from 'xlsx';
console.log(echarts)
console.log(xlsx);
document.getElementById('app').innerHTML = _.ceil(2,3,4);

复制代码

webpack.base.conf.js 配置可视化现在打包文件。

var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

  plugins:[
    new BundleAnalyzerPlugin(),
    new htmlWebpackPlugin({
      filename:'index.html',
      template:'./index.html',
      inject:true,
      minify: {
        // 压缩 HTML 文件
        removeComments: isPord, // 移除 HTML 中的注释
        collapseWhitespace: isPord, // 删除空白符与换行符
        minifyCSS: isPord // 压缩内联 css
      },
    })
  ],
复制代码

运行打包命令

npm run build

复制代码
渐进式配置webpack4单页面和多页面(二)
渐进式配置webpack4单页面和多页面(二)

打包提示代码太大,需要进行拆包。

默认配置

optimization.splitChunks 是webpack4新的特性,默认进行代码拆包。

渐进式配置webpack4单页面和多页面(二)

上图是默认配置。

chunks:

  • all: 不管文件是异步还是同步引入,都可以使用splitChunks进行代码拆包。
  • async: 只将异步加载的文件分离,首次一般不引入,到需要异步引入的组件才会引入。
  • initial:将异步和非异步的文件分离,如果一个文件被异步引入也被非异步引入,那它会被打包两次(注意和all区别),用于分离页面首次需要加载的包。

minSize: 文件最小打包体积,单位byte,默认30000。

比如说某个项目下有三个入口文件,a.js和b.js和c.js都是100byte,当我们将minSize设置为301,那么webpack就会将他们打包成一个包,不会将他们拆分成为多个包。

automaticNameDelimiter: 连接符。

假设我们生成了一个公用文件名字叫vendor,a.js,和b.js都依赖他,并且我们设置的连接符是"~"那么,最终生成的就是 vendor~a~b.js

maxInitialRequests 入口点处的最大并行请求数,默认为3。

如果我们设置为1,那么每个入口文件就只会打包成为一个文件

maxAsyncRequests 最大异步请求数量,默认5

如果我们设置为1,那么每个入口文件就只会打包成为一个文件

优先级关系。

maxInitialRequest / maxAsyncRequests <maxSize <minSize。

cacheGroups 定制分割包的规则列表

test可以配置正则和写入function作为打包规则。其他属性均可继承splitChunks。

minChunks

依赖最少引入多少次才能进行拆包。

简单修改配置

复制默认配置,将 chunks 改为'all'。

optimization: {
    splitChunks: {
      chunks: 'all',
      minSize: 30000,
      maxSize: 0,
      minChunks: 1,
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      automaticNameDelimiter: '~',
      name: true,
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    }
  },
复制代码

运行打包命令

npm run build
复制代码
渐进式配置webpack4单页面和多页面(二)

多了一个vendors~app.js。这个js里面储层的就是需要拆分的代码。

再次拆包

vendors~app.js是一个1.71mb的文件,太大了,继续拆包。

添加一个新的拆包规则

渐进式配置webpack4单页面和多页面(二)
cacheGroups: {
        echarts:{ // 新增拆包规则
          name:'echarts', // 规则名字
          chunks:'all', // 同步引入和异步引入都可以使用该规则
          priority:10, 
          // 该规则的优先级,比如 webpack中进行拆包的时候,
          // echarts包会有先匹配priority高的规则,如果满足这个规则,
          // 则将代码导入到该规则里面,不会将代码导入到后面的规则里面了。
          test:/(echarts)/, // 正则匹配规则
          minChunks:1 // 代码里面最少被引入1次就可以使用该规则。
        },
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
复制代码

运行打包命令

npm run build
复制代码
渐进式配置webpack4单页面和多页面(二)

echarts包就被单独拆出来了储层在echarts.js。

其实这个就是Code Splitting的概念之一官方demo

模块化拆包2

参考代码 demo9

这一节只使用splitChunks的默认配置来实现异步加载,理解异步加载的好处。

。 使用react作为开发框架。

同步引入的拆包

redux -> 16.8.6
react-dom -> 16.8.6
react-router-dom -> 5.0.0
复制代码

安装 react

npm i react react-router-dom react-dom -S
复制代码

解析 jsx代码还需要@babel/preset-react

npm i @babel/preset-react -D
复制代码

详细代码请看 demo9

两个路由分别对应不同的组件。

import About from './src/view/about';
    import Inbox from './src/view/inbox';
    // ....
    
   <App>
        <Route path="/about" component={About} />
        <Route path="/inbox" component={Inbox} />
    </App>
复制代码

inbox.js引入了echarts并且使用了。

import React from 'react';
import echarts from 'echarts';
class Inbox extends React.Component {
  componentDidMount() {
    var myChart = echarts.init(document.getElementById('main'));
    var option = {
      tooltip: {
        show: true
      },
      legend: {
        data: ['销量']
      },
      xAxis: [
        {
          type: 'category',
          data: ["衬衫", "羊毛衫2", "雪纺衫222", "裤子111", "高跟鞋", "袜子"]
        }
      ],
      yAxis: [
        {
          type: 'value'
        }
      ],
      series: [
        {
          "name": "销量",
          "type": "bar",
          "data": [5, 20, 40, 10, 10, 20]
        }
      ]
    };

    // 为echarts对象加载数据 
    myChart.setOption(option);
  }
  render() {
    return (
      <div>
        <h2>Inbox</h2>
        <div style={{ height: '400px' }} id="main"></div>
      </div>
    )
  }
}
export default Inbox;
复制代码

splitChunks 使用默认配置

splitChunks: {
      chunks: 'async',
      minSize: 30000,
      maxSize: 0,
      minChunks: 1,
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      automaticNameDelimiter: '~',
      name: true,
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    }
复制代码

运行打包命令

npm run build
复制代码
渐进式配置webpack4单页面和多页面(二)
渐进式配置webpack4单页面和多页面(二)

打包的时候已经提示了,打包的代码太大影响性能。可以使用import()或require来限制包的大小。确保延迟加载应用程序的某些部分。

WARNING in webpack performance recommendations: 
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/
复制代码

我们在首页的时候,并没有/inbox路由,但是/inbox路由里面的代码都打包在了app.js这一个js里面。首屏渲染变的很慢。按照官方提示需要做组件的动态引入,只有路由切换到/inbox的时候才加载对应组件的代码。

异步引入拆包

异步引入组件需要用到babel的一个插件 @babel/plugin-syntax-dynamic-impor

{
	test: /\.(js|jsx)?$/,  // 正则匹配,所有的.js文件都使用这个规则进行编译
	exclude: /node_modules/, // 排除的文件夹。这个文件夹里面的的文件不进行转译
	loader: "babel-loader", // 转译的插件
	options: {  // 转译的规则
		presets: [ //转译器配置
			[
				"@babel/preset-env", {
					useBuiltIns: "usage",
					corejs: 3
				},
			],
			["@babel/preset-react"]
		],
		plugins: ["@babel/plugin-syntax-dynamic-import"] // 转译插件配置
	}
},
复制代码

新建AsyncComponent.js。

import React, { Component } from "react";

export default function asyncComponent(importComponent) {
  class AsyncComponent extends Component {
    constructor(props) {
      super(props);

      this.state = {
        component: null
      };
    }

    async componentDidMount() {
      const { default: component } = await importComponent();
    // 组件引入完成后渲染组件
      this.setState({
        component: component
      });
    }

    render() {
      const C = this.state.component;

      return C ? <C {...this.props} /> : null;
    }
  }

  return AsyncComponent;
}
复制代码

更换引入模式

//import Inbox from './src/view/inbox';
const Inbox = asyncComponent(() => import('./src/view/inbox'));
复制代码

运行打包命令

npm run build
复制代码
渐进式配置webpack4单页面和多页面(二)

echarts被引入到1.js里面了。

npm run server
复制代码

首页并没有加载1.js

渐进式配置webpack4单页面和多页面(二)

路由跳转后会引入。

渐进式配置webpack4单页面和多页面(二)

react的动态引入组件就OK了。 按照官方文档,还可以自定义chunk名称

const Inbox = asyncComponent(() => import(/* webpackChunkName: "echarts" */ './src/view/inbox'));
复制代码

其实还可以异步引入依赖包

async componentDidMount() {
    const {default:echarts}= await import('echarts');
    var myChart = echarts.init(document.getElementById('main'));
}
复制代码

总结

  • 一般情况下推荐 splitChunks.chunks: 'all' ,其他参数可以不变。'all'的意思是同步引入和异步引入都可以进行拆包。
  • 尽量小的引入所需要的插件,比如echarts官方提供了按需加载的方法。
  • 在首页没有用的某个插件的时候,尽量使用异步加载的方式进行引入。

JS Tree Shaking

参考代码 demo10

Tree Shaking

渐进式配置webpack4单页面和多页面(二)

树抖动是JavaScript上下文中常用于消除死代码的术语。 它依赖于ES2015模块语法的静态结构,即导入和导出。 名称和概念已由ES2015模块捆绑器汇总推广。

摇树的意思。在webpack4.0里面会自动的把不需要的js在打包的时候剔除。当然需要开发进行配合: 按需加载

我们拿 lodash 为例。 为了清楚我们摇掉了多少代码,先将react的包拆出来单独打包。

splitChunks: {
      chunks: 'all',
      minSize: 30000,
      maxSize: 0,
      minChunks: 1,
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      automaticNameDelimiter: '~',
      name: true,
      cacheGroups: {
        reactVendors: {
          chunks: 'all',
          test: /(react|react-dom|react-dom-router)/,
          priority: 100,
          name: 'react',
        },
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    }
复制代码

在about.js里面使用lodash

import React from 'react';
import _ from 'lodash';
class About extends React.Component {

    render() {
      const s = _.concat([1],[2,3,1,2,3,4,6,78,41]);
      return (
        <h3>{s}</h3>
      )
    }
  }
  export default About;
复制代码

运行打包命令

npm run build
复制代码
渐进式配置webpack4单页面和多页面(二)
合并引入的vendors有95kb。我们只使用了lodash的concat方法,其他的方法没使用。 我们使用lodash的模块化包 lodash-es

npm i lodash-es -S
复制代码

改变about.js的代码

import React from 'react';
//import _ from 'lodash';
import { concat } from 'lodash-es';
class About extends React.Component {

    render() {
      const s = concat([1],[2,3,1,2,3,4,6,78,41]);
      return (
        <h3>{s}</h3>
      )
    }
  }
  export default About;
复制代码

运行打包命令

npm run build
复制代码
渐进式配置webpack4单页面和多页面(二)

现在只有28kb。缩小的部分就是loader的按需加载的部分。

Gzip压缩。

Gzip压缩的好处。

打开 掘金首页

随便找一个js资源。

渐进式配置webpack4单页面和多页面(二)

Response Headers 里面的 content-encoding 代表着资源传输格式。说明这段资源使用的是Gzip文件。说明很多公司用的是Gzip进行资源传输,因为代码打包成Gzip传输时需要的资源很小。

其实Gzip传输是服务器需要配置的。即使我们上传代码没有进行Gzip压缩,服务器经过配置后会将资源进行Gzip压缩然后传输。例如nginx的Gzip配置。

Gzip配置都是服务器配置的工作,我们要做什么呢?其实服务器会寻找资源对应的gzip文件,如果没有则会进行Gzip压缩然后传输资源。这就多出了压缩的时间。如果我们通过webpack生成gzip文件,可以减少服务器生成gzip文件的时间,也减缓了服务器压力。

js打包压缩配置optimization.minimiz

这个属性的属性值可以是布尔、数组。

当属性值是布尔时

渐进式配置webpack4单页面和多页面(二)

在mode是 prduction 时,minimiz默认是true。自动使用 terser-webpack-plugin 进行压缩。

当属性值是数组时

渐进式配置webpack4单页面和多页面(二)

如图是默认配置。

配置Gzip压缩

默认的配置不用改,使用压缩插件 compression-webpack-plugin

npm i  compression-webpack-plugin -D
复制代码

配置 optimization.minimiz

minimizer: [
      new CompressionPlugin({
        filename: '[path].gz[query]', // 生成资源的名字 [path].gz[query] 是默认名字
        algorithm: 'gzip', // 压缩算法
        test: /\.(js|css|html|svg)$/, // 匹配的资源
        compressionOptions: { level: 8 }, // 压缩等级 默认9级
        threshold: 10240, // 多大资源使用才压缩 10kb
        minRatio: 0.8,
        //仅处理压缩比此比率更好的资源(minRatio =压缩尺寸/原始尺寸)。
        //示例:您拥有1024b大小的image.png文件,压缩版本的文件大小为768b,
        //因此minRatio等于0.75。换句话说,当压缩大小/原始大小值小于minRatio值时,
        //将处理资源。默认 0.8 。
        deleteOriginalAssets: false, // 是否删除原始资产。
      }),
      new TerserPlugin({
        parallel: true,
      }),
    ]
复制代码
渐进式配置webpack4单页面和多页面(二)

运行打包命令

npm run build
复制代码
渐进式配置webpack4单页面和多页面(二)
.zip

就是打包生成的gzip资源。对比原来的文件压缩了 38/121≈0.3。压缩了很多。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

XML Hacks

XML Hacks

Michael Fitzgerald / O'Reilly Media, Inc. / 2004-07-27 / USD 24.95

Developers and system administrators alike are uncovering the true power of XML, the Extensible Markup Language that enables data to be sent over the Internet from one computer platform to another or ......一起来看看 《XML Hacks》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具