作者:余韵之LazyLoading什么是懒加载Chunk?我们可以使用懒加载来引入模块,比如当触发某个条件时,通过import引入模块。这样可以使项目的性能更好。比如:我们在点击页面的时候,会引入lodash模块。这里,import()返回promiseasyncfunctiongetComponent(){const{default:_}=awaitimport(/*webpackChunkName:"lodash"*/'lodash')constelement=document.createElement('div')element.innerHTML=_.join(['y','kk'],'-');returnelement;}document.addEventListener('click',()=>{getComponent().then(element=>{document.body.appendChild(element)})})同理懒加载路由的意思是当我们监听路由的变化时,我们会引入相应的页面模块。那么我们可以知道,什么是Chunk?打包生成几个JS文件,也就是几个ChunkShimmingShimming:在打包的过程中,有时候需要兼容代码。这种兼容性不限于浏览器的高版本和低版本。比如每个文件都是一个模块,每个模块都应该引入自己的依赖来使用依赖。import$from'jquery'exportfunctionsetBackground(){$('body').css('background','red')}但在这种情况下,每个文件都必须写import$from'jquery'所以它可以使用shims的方式自动配置插件:[newwebpack.ProvidePlugin({$:'jquery',_join:['lodash','join']})]当我们配置上面的内容时,意味着当运行code当你看到符号$时,它会自动将jquery导入到node_modules中。他的原理是自动帮我们加上导入步骤。看到_join会自动找到lodash中的join方法,所以我们可以直接使用这些文件模块使用exportfunctionsetBackground(){$('body').css('background',_join(['green'],''))}webpack和浏览器缓存(caching)我们在打包生成index.htmlmain.jsvendors.js的时候,客户端从服务器端拿到两个js文件,保存在浏览器中。客户端刷新后,浏览器会先从缓存中获取。当开发者修改代码,重新打包,生成上述三个同名文件时,用户刷新后,原来的代码仍然没有更新。如何解决这个问题?1.在打包文件中添加contentHash。因为开发环境是热更新的,本地调试不需要添加。生产环境改成在output:{filename:'[name].[contentHash].js',chunkFilename:'[name].[contentHash].js'}contentHash的意思是只要源的内容code不改变,contentHash生成的hash值也不会改变。如果代码被拆分成不同的chunk,某个chunk没有被修改,则该chunk的文件名contentHash不会被修改。同时最好配置optimization.splitChunks.cacheGroup.vendors.filename='vendors.[contentHash].js'2.兼容旧版本。即使旧版本不改变内容,contentHash值也会改变。这时候可以配置优化:{runtimeChunk:{name:'runtime'}}把这个runtimeChunk添加到新版本就没有问题了。这时,包中会多出一个runtime.xxxxxxx.js文件。到底是怎么回事?因为旧的webpack版本中main.js(业务逻辑)和vendors.js(第三方库)有关系,所以这部分处理代码放在了mainfest中,虽然代码没变,但是在旧版本的webpack每次打包时,mainfest包和包的关系可能会发生变化。我们在配置runtimeChunk的时候,把mainfest关系相关的代码抽取出来放在runtime.js中,这样就解决了老版本的兼容问题。如果css代码拆分正常打包,将css文件打包在一起的main.js文件,如何拆分css代码?1.使用一个插件:mini-css-extract-plugin,但是这个插件有个缺点。目前不支持热更新,适合线上环境做打包配置。安装依赖yarnaddmini-css-extract-plugin在生产环境webpack.config.js配置constMiniCssExtractPlugin=require('mini-css-extract-plugin')module:{rules:[{test:/\.scss$/,使用:[MiniCssExtractPlugin.loader,{loader:'css-loader',options:{importLoaders:2}},'sass-loader','postcss-loader']},{test:/\.css$/,use:[MiniCssExtractPlugin.loader,'css-loader','postcss-loader']}]},plugins:[newMiniCssExtractPlugin({filename:"[name].css",//直接从index导入文件。htmlchunkFilename:"id.css"//间接引用文件})]注意,此时如果使用treeshaking,查看package.json中的sideEffects配置。如果为false,则不会拆分css代码。需要排除csstreeshaking。修改如下:"sideEffects":["*.css"],2.接下来合并CSS代码压缩安装依赖yarnaddoptimize-css-assets-webpack-plugin-DproductionenvironmentconstOptimizeCSSAssetsPlugin=require('optimize-css-assets-webpack-plugin')optimization:{minimizer:[newOptimizeCSSAssetsPlugin({})]}包分析生成webpack包分析jsonwebpack--profile--json>stats.json--config./build/webpack.dev.js然后把生成的stats.json放到相关分析网站就可以看到可视化数据了。当然你也可以在webpack.config.js配置中配置analyzer安装依赖npminstallwebpack-bundle-analyzer--save-devconstBundleAnalyzerPlugin=require('webpack-bundle-analyzer').BundleAnalyzerPlugin;module.exports={...configureWebpack:{plugins:[newBundleAnalyzerPlugin({//可以是`server`、`static`或`disabled`。//在`server`模式下,分析器将启动一个HTTP服务器来显示捆绑报告。//在“静态”模式下,生成一个包含报告的HTML文件。//在“禁用”模式下,您可以使用此插件生成WebpackStatsJSON文件,并将“generateStatsFile”设置为“true”.analyzerMode:'server',//将在“服务器”模式下使用的主机启动HTTP服务器。analyzerHost:'127.0.0.1',//将在“服务器”模式下使用的端口上启动HTTP服务器。analyzerPort:8888,//路径包,将在`static`模式下生成的报告文件。//相对于包输出目录。reportFilename:'report.html',//模块大小默认显示在报告中。//应该是`stat`、`parsed`或`gzip`之一。//有关详细信息,请参阅“定义”部分。defaultSizes:'parsed',//在默认浏览器中自动打开报告openAnalyzer:true,//如果为true,WebpackStatsJSON文件将在包输出目录中生成generateStatsFile:false,//如果`generateStatsFile`为true`,将生成WebpackStatsJSON文件的名称。//相对于包输出目录。statsFilename:'stats.json',//stats.toJson()方法的选项。//例如,您可以使用`source:false`选项来排除统计文件中模块的来源。//在此处查看更多选项:https://github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21statsOptions:null,logLevel:'info'//日志级别。可以是“信息”、“警告”、“错误”或“静音”。})]},...};添加--reportnpmrunserve--reportnpmrunbuild--reportprefetching&&预加载注意代码使用:不要加载一开始不会执行的代码。相反,在交互之后加载它。webpack希望在第一次加载时尽量使用异步加载模块来提升性能,而同步加载是第二次加载,增加缓存对性能的提升有限。document.addEventListener('click',()=>{import('./click.js').then(({default:func})=>{func()})})注意有个问题这个,也就是用户点击交互的时候下载代码可能会有一点延迟。如何解决这个问题呢?解决方法是:prefetching/preloadingprefetching会等到内核最先显示的代码加载完毕,等到宽带空闲的时候再继续下载。只需在代码中添加以下内容:document.addEventListener('click',()=>{import(/*webpackPrefetch:true*/'./click.js').then(({default:func})=>{func()})})当用户点击的时候,click.js文件还是会被下载,但是使用时间会很短,因为之前已经下载过了,已经缓存了。预加载将与主代码同时下载。document.addEventListener('click',()=>{import(/*webpackPreload:true*/'./click.js').then(({default:func})=>{func()})})因此,性能优化最好考虑代码的更高使用率。对电子感兴趣?请关注我们的开源项目ElectronPlayground,带你快速上手Electron。每周五我们都会挑选一些有趣的文章和新闻与大家分享。快来关注我们的小风周刊吧。我们是好未来小黑板的前端技术团队。我们会经常与您分享最新最酷的行业技术知识。欢迎知乎、掘金、Segmentfault、CSDN、简书、开源中国、博客园关注我们。
