Webpack高级概念

1,270 阅读4分钟

[TOC]

一. tree shaking

1.1 概念

在打包过程中,用来删除没有被使用到的文件,减小bundle.js的体积

1.2 使用

  • 在生产环境下

    • tree shaking默认已经配置好了,只需要添加如下配置即可
    • sideEffects配置的作用是,用来排除打包的时候,不需要使用 tree shaking的文件,
    • sideEffects设置为false的时候,是告诉webpack,所有文件都使用tree shaking
     //package.json
    //...
    //sideEffects: ["*.css","./src/some.js"]
    "sideEffects":false
    
  • 在开发环境下

    • 需要我们手动配置 tree shaking
    // webpack.config.js
    module.exports = {
        // ...
        optimization: {
            usedExports: true
        }
    }
    
    //package.json
    "sideEffects": false
    

详情参考webpack官网:tree-shaking

二. 开发和生产模式下的打包模式区分

可以分别配置开发和生产环境各自独立的配置文件

在打包的时候,通过package.json的scripts分别配置生产环境和开发环境各自的打包命令

// webpack.common.js

const path = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
    entry: path.resolve(__dirname,'./src/index.js'),
    output:{
        path: path.resolve(__dirname,'./dist'),
        filename: 'bundle.js'
    },
    plugins: [
        new CleanWebpackPlugin(),
        new htmlWebpackPlugin({
            title: 'prouction'
        })
    ]
}
// webpack.dev.js
const common = require('./webpack.common')
const merge = require('webpack-merge')

module.exports = merge(common,{
    mode: 'development',
    devtool: 'inline-source-map',
    devServer: {
        contentBase: './dist'
    }
})
// webpack.prod.js
const merge = require('webpack-merge')
const common = require('./webpack.common')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
const webpack = require('webpack')

module.exports = merge(common,{
    mode: 'production',
    plugins: [
        new  UglifyJSPlugin(),
        new webpack.DefinePlugin({
            'process.env.NODE_env': JSON.stringify('production')
        })
    ]
})
// package.json

scripts:{
    "dev": "webpack-dev-server --config webpack.dev.js",
    "prod": "webpack --config webpack.prod.js"
}

详情参考Webpack官网:development

三. code splitting

**作用:**代码分割,通过合理的代码分割,可以使代码性能更高

**核心:**提取不会更改的核心内库,避免修改后重复加载,影响页面响应性能

示例:

// webpack.config.js
module.exports = {
    optimization: {
        splitChunks:{
            chunks: 'all'
        }
    }
}  

详情参考webpack官网:code splitting

四. Caching

**问题描述:**一般情况下,为了使页面在每次版本更新之后,都会主动加载最新的代码,我们在打包文件的时候,一般会给文件加上特定的版本号,这样虽然解决了加载旧缓存的问题,但是带来了一个新问题,由于文件名发生了变化,每次修改代码都会重新加载整个资源文件,导致网页性能变差。

**思考:**资源文件中包含很多通用的代码,在打包的时候,提取运行时的文件(即通用的),将修改后需要重新加载的部分单独打包到一个文件,每次修改之后的更新,提取出来的运行时文件不变,这样可以使浏览器加载该文件的时候,直接从浏览器获取,提升页面性能

使用方法:

  1. 修改输出文件名,为每一个打包之后的输出文件加上特有的hash值
module.exports = {
    output:{
        path: path.resolve(__dirname,'./dist'),
        filename: '[name][contenthash].js'
    },
}
  1. 将bundle.js中的运行时文件拆分为单独的文件(每次打包的时候,提取的运行时文件不发生变化,直接从缓存中取即可,不用重复加载)
module.exports = {
     optimization: {
       runtimeChunk: 'single'
    }
}
  1. 结合代码分割一起使用,提升界面性能
module.exprots = {
    optimization: {
       runtimeChunk: 'single',
       splitChunks: {
           cacheGroups: {
               verdor: {
                   test: /[\\/]node_modules[\\/]/,
                   name: 'vendors',
                   chunks: 'all'
               }
           }
       }
    }
}

详情参考webpack官网:Caching

五. webpack打包分析

  • webpack打包分析官网
  • 在官网中有介绍到,要使用webpack打包分析,首先得生成一个JSON文件,可通过如下命令打包生成
webpack --profile --json > stats.json

使用该命令打包之后,会在项目目录下面生成一个stats.json的文件,该文件包含打包的一些信息

打开官网中推荐的链接,选择刚刚打包生成的 stats.json文件,即可查看webpack的打包分析

其它打包工具推荐

  • Webpack官网-----》 Guides ------》 Code Splitting ------》 BundleAnalysis
  • 该目录下推荐了好几种Webpack打包分析,使用方法跟上述方法一样,选择stats.json文件即可
  • 推荐:webpack-bundle-analyzer

六. Prefetching和Preloading

缓存解决的问题是: 非首次加载代码的时候,浏览器直接从缓存中获取文件,从而减少请求,提升效率

webpack的优化并不满足于此:Webpack希望第一次访问界面的时候,它的速度就是最快的(提升页面的代码使用率)

缓存带来的效率提升有限

Prefetching和Preloading的作用

  • 首次加载的时候,只需要加载核心代码
  • 在页面展示出来之后,即网络空闲的时候,加载后续界面调用需要用到的代码

区别:

  • prefetching:在界面界面核心代码加载完成之后,空闲的时候加载文件
  • preloading:和核心代码块一起加载

使用:

  • webpack推荐使用异步加载的方法,更利于网页的优化
  • import的文件路径前面加上 /* webpackPrefetch: true */即可使用prefetch
  • 前提是使用了 babel模块支持ES6语法
// index.js
//...
document.addEventListener('click', () =>{
	import(/* webpackPrefetch: true */ './click.js').then(({default: func}) => {
		func();
	})
});
// click.js
function handleClick() {
	const element = document.createElement('div');
	element.innerHTML = 'Dell Lee';
	document.body.appendChild(element);
}

export default handleClick;

七. Css 代码分割

默认情况下,webpack打包的时候,会将CSS文件打包到js文件中

**MiniCssExtractPlugin插件:**用来分割CSS代码,常用于线上打包环境

详细使用见webpack官网:mini-css-extract-plugin

八. Shimming

解决webpack打包过程中的兼容性问题

详见webpack官网:shimming

九. 环境变量的使用

在构建的命令行中传入 --env.production参数

在 webpack.common.js中根据参数判断打包类型

使用:

// package.json

 "scripts": {
    "dev-build": "webpack --config ./build/webpack.common.js",
    "prod-build": "webpack --env.production --config ./build/webpack.common.js"
  },
// webpack.common.js
const merge = require('webpack-merge');
const devConfig = require('./webpack.dev.js');
const prodConfig = require('./webpack.prod.js');
const commonConfig = {
	//...
}

module.exports = (env) => {
	if(env && env.production) {
		return merge(commonConfig, prodConfig);
	}else {
		return merge(commonConfig, devConfig);
	}
}