Webpack笔记(四)

五. webpack优化配置

webpack性能优化

        开发环境性能优化

                优化打包构建速度(HMR)

                优化代码调试(source-map)

        生产环境性能优化

                优化打包构建速度

                        oneOf

                        babel缓存

                        多进程打包

                        external

                        dll

                优化代码运行的性能

                        缓存(hash-chunkhash-contenthash)

                        tree-shaking

                        code split

                        懒加载/预加载

                        pwa

5.1 HMR

        HMR:hot module replacement 热模块替换/模块热替换

                作用:一个模块发生变化,只会重新打包只一个模块(而不是打包所有模块)

                        极大提升构建速度

                样式文件:可以使用HMR功能:因为style-loader内部实现了

                js文件:默认不能使用HMR功能

                需要修改js代码,在index.js入口文件添加支持HMR功能的代码

                注意:HMR功能对js的处理,只能处理非入口js文件的其他文件

if(module.hot){
        //一旦module.hot为true,说明开启了HMR功能  --> 让HMR功能代码生效
        module.hot.accept('./print.js',function(){
            //方法会监听print.js文件的变化,一旦发生变化,其他模块不会重新打包构               建,会执行后面的回调函数
			print()
        })
    }

                html文件:默认不能使用HMR功能,同时会导致问题:html文件不能热更新(响应)了

                        解决:修改entry入口,将html文件引入

                        (只有一个html文件,不需要HMR功能)

entry:['./src/js/index.js','./src/index.html'],

        修改配置文件:

const {resolve} = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')   

module.exports = {
  entry:['./src/js/index.js','./src/index.html'],
  output:{
    filename:'js/built.js',
    path:resolve(__dirname,'build')
  },
  module:{
    rules:[
      {
        test:/\.less$/,
        use:['style-loader','css-laoder','less-loader']
      },
      {
        test:/\.css$/,
        use:['style-loader','css-laoder']
      }
    ]
  },
  plugins:[
    new HtmlWebpackPlugin({
      template:'./src/index.html'
    })
  ],
  mode:'production',
  devServer:{
    contentBase:resolve(__dirname,'build'),
    compress:true,
    port:3000,
    open:true,
    //开启HMR功能
    // 当修改了webpack配置,新配置想要生效,必须重新webpack
    hot:true
  }
}

        运行 npx webpack-dev-server

5.2 source-map

package.json 中添加以下代码

	...
  },
  devtools:'eval-source-map'
}
/**
 * source-map:  一种提供源代码到构建后代码映射技术(如果构建后代码出错了,通过映射可以追踪源代码错误)
 *    
 *    [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
 * 
 *    source-map: 外部
 *        能够提示错误代码准确信息 和 源代码的错误位置
 *    inline-source-map:内联
 *        只生成一个内联source-map
 *        能够提示错误代码准确信息 和 源代码的错误位置
 *    hidden-source-map:外部
 *        提示错误代码的错误原因,但是没有错误位置
 *        不能追踪源代码错误,只能提示到构建后代码的错误位置 
 *    eval-source-map:内联
 *        每一个文件都生成对应的source-map,都在eval
 *        提示错误代码的准确信息 和 源代码的位置(包含哈希值)
 *    nosources-source-map:外部
 *        提示错误代码的准确信息,但是没有任何与源代码信息
 *    cheap-source-map:外部
 *        提示错误代码准确信息 和 源代码的错误位置
 *        只能精确到行
 *    cheap-module-source-map:外部
 *         提示错误代码准确信息 和 源代码的错误位置
 * 
 *     内联和外部的区别:1.外部生成了文件,内联没有 2.内联构建速度更快
 *    开发环境:速度快,调试更友好
 *      速度快(eval>inline>cheap>...)
 *        eval-cheap-source-map
 *        eval-source-map
 *      调试更友好
 *        source-map
 *        cheap-module-source-map
 *        cheap-source-map
 * 
 *        结论-->eval-source-map  /  eval-cheap-module-source-map
 *    生产环境:源代码要不要隐藏?调试要不要更友好
 *        内联会让代码体积变大,所以在生产环境不用内联
 *        nosources-source-map
 * 
 *        结论-->source-map / cheap-module-source-map
 */

5.3 oneOf

	module:{
		rules:[
            {
                test:/\.js$/,
                exclude:/node_modules/,
                loader:'eslint-loader',
                options:{
                    fix:true
                }
            },
            {
                //以下loader只会匹配一个
                //注意:不能有两个配置处理同一种类型文件
                oneOf:[
                    {
                        test:/\.less$/,
                        use:['style-loader','css-laoder','less-loader']
                    },
                    {
                        test:/\.css$/,
                        use:['style-loader','css-laoder']
                    },
                    /*
                    	正常来讲,一个文件只能被一个loader处理
                    	当一个文件要被多个loader处理,那么一定要指定loader执行的
                    	先后顺序,先执行eslint 在执行babel
                    */
                    {
                        test:/\.js$/,
                        exclude:/node-modules/,
                        loader:'babel-loader',
                        options:{ 
                            presets:[
                                '@babel/preset-env',
                                {
                                    useBuiltIns:'usage',
                                    corejs:{
                                        version:3
                                    },
                                    targets:{
                                        chrome:'60',
                                        firefox:'60',
                                        ie:'9',
                                        safari:'10',
                                        edge:'17'
                                    }
                                }
                            ]
                        }
                    }
                ]
            }
        ]
    }

5.4 缓存

{
    test:/\.js$/,
    exclude:/node-modules/,
    loader:'babel-loader',
    options:{ 
    	presets:[...],
        //开启babel缓存
        //第二次构建时,会读取之前的缓存
        cacheDirectory:true
    }
}
//文件资源缓存
//添加hash值
output: {
	filename: 'js/built.[contenthash:10].js',
	path: resolve(__dirname, 'build')
}
plugins: [
	new MiniCssExtractPlugin({
		filename: 'css/built.[contenthash:10].css'
	}),
]

/*
	缓存:
		babel缓存
			cacheDirectory:true
			--> 让第二次打包构建速度更快
		文件资源缓存
			hash:每次webpack构建时会生成一个唯一的hash值
				问题:因为js和css同时使用一个hash值
					如果重新打包,会导致所有缓存失效。(可能只改动一个文件)
			chunkhash:根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值就一样
				问题:js和css的hash值还是一样
					因为css是在js中被引入的,所以同属于一个chunk
			contenthash:根据文件的内用生成hash值。不同文件hash值一定不一样 
			--> 让代码上线运行  缓存更好使用
*/

5.5 tree shaking

        tree shaking : 去除无用代码 ​ 前提:1.必须使用ES6模块化(import export) ​ 2.开启production环境 ​ 作用:减少代码体积 ​

在package.json中配置
		"sideEffects" : false 所有代码都没有副作用(都可以进行tree shaking)
			问题:可能会把css / @babel/ployfill 文件干掉(副作用)
		"sideEffects" : ["*.css","*.less"]

5.6 code split

module.exports = {
	//单入口(单页面应用)
	//entry : './src/js/index.js'
	//多入口:有一个入口,最终输出就有一个bundle
	entry:{
		index:'./src/js/index.js',
		test:'./src/js/test.js'
	},
	output:{
	},
	plugins:{
	}
    /*
    	可以将node_modules中代码单独打包chunk最终输出
    	自动分析多入口chunk中,有没有公共的文件。如果有会单独打包成一个chunk
    */
    optimization:{
    	splitChunks:{
    		chunks:'all'
		}
	}
	...
}
    
/*
	通过js代码,让某个文件被单独打包成一个chunk
	import动态导入语法:能将某个文件单独打包(ES11)
*/
    import(/*webpackChunkName:'test' */ './test')
		.then(()=>{
			//文件加载成功
        	console.log(mul(2,5))
    	})
		.catch(()=>{
			console.log('文件加载失败')
    	})

5.7 懒加载

//js代码
	document.getElementById('btn').onclick = function(){
		//懒加载:当文件需要时才加载
        //预加载 prefetch:会在使用之前,提前加载js文件
        //正常加载可以认为是并行加载(同一时间加载多个文件)
        //预加载 pregetch:等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
        import(/* webpackChunkName: 'test' , webpackPrefetch: true */)
    }

5.8 PWA

//pwa:渐进式网络开发应用程序(离线可访问)
//workbox --> npm i workbox-webpack-plugin -D

plugins:{
    new WorkboxWebpackPlugin.GenerateSW({
        /*
			1.帮助serviceWorker快速启动
			2.删除旧的serviceWorker

			生成一个serviceWorker 配置文件
		*/
        clientsClaim: true,
        skipWaiting: true
    }) 
}
/*
	1.eslint不认识window、navigator全局变量
		解决:需要修改package.json中eslintConfig配置
			"env":{
				"browser":true //支持浏览器全局变量
			}
	2.sw代码必须运行在服务器上
		--> npm i serve -g
			serve -s build 启动服务器,将build目录下所有资源作为静态资源暴露出去
*/

//在入口文件index.js中

//注册serviceWorker
if('serviceWorker' in navigator){//处理兼容性问题
	window.addEventListener('load',()=>{
		navigator.serviceWorker.register('./service-worker.js')
        	.then(()=>{
				console.log('sw注册成功了')
        	})
        	.catch(()=>{
				console.log('sw注册失败了')
        	})
    })
}

5.9 多进程打包

test:/\.js$/,
    exclude:/node_modules/,
    use:[
        /*
        	开启多进程打包。
        	进程启动大概为600ms,进程通信也有开销
        	只有工作消耗时间比较长,才需要多进程打包
        */
        {
        	loader:'thread-loader',
            options:{
				workers:2 //进程2个
            }
        },
        {
            loader:'babel-loader',
            options:{...}
        }
    ]
module.exports = {
	entry:...
    output:...
    plugins:...,
    module:...,
    plugins:...,
    mode:'production',
    externals:{
    	//拒绝jQuery被打包进来
    	jQuery:"jQuery"
	}
}

5.11 dll

        新建文件webpack.dll.js

/*
	使用dll技术,对某些库(第三方库:jquery,react,vue...)进行单独打包
		当你运行webpack时,默认查找webpack.config.js配置文件
		需求:需要运行webpack.dll.js文件
			--> webpack --config webpack.dll.js
*/
const {resolve} = require('path')
const webpack = require('webpack')

module.exports = {
	entry:{
		//最终打包生成的[name] --> jquery
        //['jquery'] --> 要打包的库是jquery
        jquery:['jquery']
    },
    output:{
		filename:'[name].js',
        path:resolve(__dirname,'dll'),
        library:'[name]_[hash]'//打包的库里面向外暴露出的内容叫什么名字
    },
    plugins:[
        //打包生成一个manifest.json --> 提供和jquery映射 
        new webpack.DllPlugin({
            name:'[name]_[hash]',//映射库的暴露的内容名称
            path:resolve(__dirname,'dll/manifest.json')//输出文件路径
        })
    ]
}

           

        新建webpack.config.js

module.exports = {
	entry:'./src/index.js',
    output:{
		filename:'build.js',
        path:resolve(__dirname,'build')
    },
    plugins:[
        new HtmlWebpackPlugin({
			template:'./src/index.html'
        }),
        //告訴webpack那些库不参与打包,同时使用时名称也得变
        new Webpack.DllReferencePlugin({
			manifest:resolve(__dirname,'dll/manifest.json')
        })
        //将某个文件打包输出去,并在html中自动引入该资源
        new AddAssetHtmlWebpackPlugin({
			filepath:resolve(__dirname,'dll/jquery.js')
        })
    ],
    mode:'production'
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值