本小节主要给大家介绍如何提高代码的性能?我们从打包工具入手,然后到预提模块(Preloading),预加载模块(Prefetching)。

1.打包分析

打包分析是指当webpack对我们的代码打包过后,我们使用分析工具对打包后的文件进行一定的分析,帮助我们看打包后的代码有没有继续提升的空间。

生成stats.json

您可以通过运行webpack --profile --json> stats.json为此工具生成所需的JSON文件

package.json

{
 "scripts": {
    "dev": "npx webpack-dev-server --config webpack.config.js --mode=development --colors",
    "prod": "npx webpack --config webpack.config.js --mode=production",
    "build": "npx webpack --config webpack.config.js --mode=development --colors"
+    "analyse": "npx webpack --profile --json> stats.json --config webpack.config.js --mode=development --colors"
  },
}

运行webpack

yarn run analyse

ssl

在我们的项目下面生成了一个stats.json文件,将stats.json文件上传到官方分析工具中就可以了。

2.使用webpackBundleAnalyzer

安装webpack-bundle-analyzer

yarn add -D webpack-bundle-analyzer

webpack.config.js

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

module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

ssl

3.prefetch

在声明import时,使用下面这些内置指令,可以让webpack输出resource hint(资源提示)来告知浏览器:

上面我是看中文的文档,有英文能力的小伙伴可以看英文,这样理解比较准确。小菜本想在这里说说个人理解,但是写出来后,感觉语言描述的不是很清楚,那还是用代码来演示吧。

splitChunks: {
    chunks: 'all'
}

webpack官方默认chunks:async,官方为什么要默认chunks:async呢?当我们在引入loadsh,jquery库时,如果配置chunks: 'all',那么肯定会帮助我们把loadshjquery单独拆分开来,但是这样做并不能提升首页的代码性能,原因是在浏览器第一次加载时,还是需要我们加载loadshjquery库,只有当我们的代码第二次加载时,浏览器才会从缓存中去找,提高我们第二次页面加载访问速度。webpack是想让我们第一次加载时,访问速度就是最快。举个列子

未优化的代码

src/index.js

document.addEventListener('click',()=>{
    const element = document.createElement('div');

    let sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }

    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }
    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }
    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }
    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }
    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }
    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }
    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }

    element.innerHTML =  `0~100的和为${sum}`;
    document.body.appendChild(element)
})

编译webpack

yarn run build

打开dist/index.html,找到coverage。或者快捷方式Ctrl + Shift + P,输入coverage

ssl

打开后刷新页面,然后点击index.js

ssl

可以看到index.js未使用利用率27.9%,我们可以优化一下index.js代码

优化后

新建src/util/click.js

function handleClick(){
    const element = document.createElement('div');

    let sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }

    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }
    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }
    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }
    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }
    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }
    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }
    sum = 0;
    for(let i=1;i<=100;i++){
        sum +=i;
    }

    element.innerHTML =  `0~100的和为${sum}`;
    document.body.appendChild(element)
}

export default handleClick

src/index.js

document.addEventListener('click',()=>{
    import('./util/click').then(({default:func}) =>{
        func();
    })
})

运行webpack

yarn run build

ssl

从上面的截图可以了解到,index.js未使用率降低到了24.3%,小菜这里有个疑惑就是mian.js的未使用率上升了,按道理应该是要下降的。小菜也只能在这里猜测下,虽然index.js里面的代码被移到click.js里面,估计demo写的太简单,代码太少,webpack打包后,mian.js的代码代码量增加了,从而导致未使用的代码率上升。如果后面有机会的话,小菜会专门写一小节分析下,感兴趣的小伙伴也可以自己研究下,然后在评论区留言分享也行。

ssl

webpack打包后,会有一个1.js文件被分割出来(大家如果想改名字,请查看上一节)那么就会带来一个问题,比如在首页上有一个登陆按钮,首页加载好后,用户点击登陆,然后才会加载登陆程序,这样会不会影响用户体验,如果按照上面那种方式确实会有这个问题。我们希望当主程序加载完成后再去加载子程序,还是上面那个例子,当首页加载完成后,在浏览器空闲的时候去加载登陆程序,这样一来就解决上面那个问题。

4.使用prefetch优化

继上面demo我们做点小修改

src/index.js

document.addEventListener('click',()=>{
    import(/* webpackPrefetch: true */'./util/click').then(({default:func}) =>{
        func();
    })
})

运行webpack

yarn run build

ssl

打开浏览器的控制台,刷新页面,可以看到0.js文件被加载了。大家可以把魔法注释去掉,在刷新浏览器看看。

5.使用preload优化

src/index.js

document.addEventListener('click',()=>{
    import(/* webpackPreload: true */'./util/click').then(({default:func}) =>{
        func();
    })
})

ssl

打开浏览器的控制台,刷新页面,可以看到0.js文件也被加载了。

6.prefetch和preload区别

不正确地使用 webpackPreload 会有损性能,请谨慎使用

preload和 prefetch 指令相比,preload 指令有许多不同之处:

7.总结

webpack官方在配置中chunks: 'async'写的是异步,是想让我们编写异步程序来提高代码的性能,缓存能够带来的代码提升非常有限,我们后面写代码程序应该重点关注代码利用率,提高代码利用率才是真正提高代码性能,如果页面代码暂时不用,就采用异步懒加载的形势,主代码加载完成后利用空闲时间来加载其他子代码。

webpack4.x 教程

webpack 准备工作(1) webpack 手写最基本的配置(2) webpack 打包样式(3) webpack 让打包更便捷(4) webpack 打包图片(5) webpack iconfont打包(6) webpack devServer本地开发(7) webpack 处理ES6语法(8) webpack SourceMap配置(9) webpack Tree Shaking(10) webpack js代码分割(11) webpack 懒加载(12) webpack 打包分析,Preloading,Prefetching(13) webpack 模块化区分开发和生产(14) webpack 样式文件的代码分割(15) webpack 浏览器缓存(16) webpack shimming(17) webpack 环境变量(18) webpack Esline(19)