1.单页面配置 是指一个完整的项目为了首屏优化可以以下操作:1.增加loading动画;
2.按需加载(a.根据路由 打包配置不同的js文件;b根据公共模块进行拆分)
1.单页面配置
webpack配置内容与其他页面没有关联 可以单独打包配置 1.关闭其他路由单个打 2.多页面多个包打
2.共有模块拆分
entry: {
"vendor1": ["react", "react-dom", "react-router", "react-router-redux", "react-redux", "redux"],
"vendor2": ["crypto-js", "fastclick"], "app": "./js/index.js"
},
...
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ["vendor2","vendor1"],
minChunks: Infinity
})
],
第一个要注意的地方,在CommonsChunkPlugin里面,vender的顺序要反着来,总之,要和加载顺序相反。比如你想按vendor1,vendor2的顺序加载,entry里面写的是vendor1,vendor2,在CommonsChunkPlugin里面要写vendor2,vendor1。
第二个要注意的地方,output.filename一定不要写死了,要配置成可替换的,类似filename: '[name].js’形式。
转载链接:https://blog.csdn.net/wang1006008051/article/details/78066810
vue+webpack实现页面的按需加载
通过vue写的单页应用时,可能会有很多的路由引入。当打包构建的时候,javascript包会变得非常大,影响加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样就更加高效了。这样会大大提高首屏显示的速度,但是可能其他的页面的速度就会降下来。结合Vue的异步组件和webpackde code splitting feature,轻松实现路由组件的懒加载。
就像图片的懒加载一样,如果客户根本就没有看到那些图片,而我们却在打开页面的时候全部给加载完了,这样会大大的增加请求的时间,降低用户的体验程度。懒加载在很多的网站都有用到,比如淘宝、京东等等这样的购物网站,上面的图片链接等等都很多,如果你把滚轴迅速的往下拉的时候,你可能会看到图片加载的情况。
单页应用也是一样,用户可能没有通过点击跳转到其他的的页面,而是只在主页面进行了停留,那么我们就没有必要把其他页面的资源全部加载过来。如果用户点进去再加载。这样就可以大大提高请求时间,提高用户的体验程度。
webpack中提供了require.ensure()来实现按需加载。以前引入路由是通过import 这样的方式引入,改为const定义的方式进行引入。
不进行页面按需加载引入方式:import home from '../../common/home.vue'
进行页面按需加载的引入方式:const home = r => require.ensure( [], () => r (require('../../common/home.vue')))
下面的内容讲解的更为详细(引自:https://cnodejs.org/topic/586823335eac96bb04d3e305)
webpack ensure相信大家都听过。有人称它为异步加载,也有人说做代码切割,那这个家伙到底是用来干嘛的?其实说白了,它就是把js模块给独立导出一个.js文件的,然后使用这个模块的时候,webpack会构造script dom元素,由浏览器发起异步请求这个js文件。
场景分析:
比如应用的首页里面有个按钮,点击后可以打开某个地图。打开地图的话就要利用百度地图的js,于是我们不得不在首页中把百度地图的js一起打包进去首页,一个百度地图的js文件是非常大的,假设为1m,于是就造成了我们首页打包的js非常大,用户打开首页的时间就比较长了。
有没有什么好的解决方法呢?
解决1
既然打包成同一个js非常大的话,那么我们完全可以把百度地图js分类出去,利用浏览器的并发请求js文件处理,这样的话,会比加载一个js文件时间小得多。嗯,这也是个不错的方案。为baidumap.js配置一个新的入口就行了,这样就能打包成两个js文件,都插入html即可(如果baidumap.js被多个入口文件引用的话,也可以不用将其设置为入口文件,而且直接利用CommonsChunkPlugin,导出到一个公共模块即可)可以参考我之前文章webpack模块打包
那还有没有更好的解决方案呢?
解决2
当然还是有的!我们细想,百度地图是用户点击了才弹出来的,也就是说,这个功能是可选的。那么解决方案就来了,能不能在用户点击的时候,我在去下载百度地图的js.当然可以。那如何实现用户点击的时候再去下载百度地图的js呢?于是,我们可以写一个按钮的监听器
mapBtn.click(function() {
//获取 文档head对象
var head = document.getElementsByTagName(‘head’)[0];
//构建
ok,那么我们就利用webpack的api去帮我们完成这样一件事情。点击后才进行异步加载百度地图js,上面的click加载js时我们自己写的,webpack可以轻松帮我们搞定这样的事情,而不用我们手写
mapBtn.click(function() {
require.ensure([], function() {
var baidumap = require(’./baidumap.js’) //baidumap.js放在我们当前目录下
})
})
搞定!当然还是分析一下。require.ensure这个函数是一个代码分离的分割线,表示 回调里面的require是我们想要进行分割出去的,即require(’./baidumap.js’),把baidumap.js分割出去,形成一个webpack打包的单独js文件。当然ensure里面也是可以写一些同步的require的,比如
var sync = require(‘syncdemo.js’) //下面ensure里面也用到
mapBtn.click(function() {
require.ensure([], function() {
var baidumap = require(’./baidumap.js’) //baidumap.js放在我们当前目录下
var sync = require(‘syncdemo.js’) //这个不会独立出去,因为它已经加载到模块缓存中了
})
})
也就是说,ensure会把没有使用过的require资源进行独立分成成一个js文件. require.ensure的第一个参数是什么意思呢?[], 其实就是 当前这个 require.ensure所依赖的其他 异步加载的模块。你想啊?如果A 和 B都是异步加载的,B中需要A,那么B下载之前,是不是先要下载A啊?,所以ensure的第一个参数[]是它依赖的异步模块,但是这里需要注意的是,webpack会把参数里面的依赖异步模块和当前的需要分离出去的异步模块给一起打包成同一个js文件,这里可能会出现一个重复打包的问题, 假设A 和 B都是异步的, ensure A 中依赖B,ensure B中 依赖A,那么会生成两个文件,都包含A和B模块。 如果想加载A require.ensure([‘A.js’],function) 即可
说完了上面的原理。下面就实践一下
entry.js 依赖三个 js。
Abtn-work.js 是封装了 abtn按钮点击后,才执行的业务逻辑
Bbtn-work.js 是封装了 bbtn按钮点击后,才执行的业务逻辑
util.js 是封装了 entry.js需要利用的工具箱
针对上面的需求,优化方案
假设 Abtn-work.js Bbtn-work.js util.js都是非常大的文件因为 Abtn-work.js Bbtn-work.js 都不是entry.js必须有的,即可能发生的操作,那么我们把他们利用异步加载,当发生的时候再去加载就行了
util.js是entry.js立即马上依赖的工具箱。但是它又非常的大,所以将其配置打包成一个公共模块,利用浏览器的并发加载,加快下载速度。ok,构思完成,开始实现
index.html
index然后看看 entry.js
var util_sync = require(’./util-sync.js’)
alert(util_sync.data)
document.getElementById(“aBtn”).onclick = function() {
require.ensure([], function() {
var awork = require(’./workA-async.js’)
alert(awork.data)
//异步里面再导入同步模块–实际是使用同步中的模块
var util1 = require(’./util-sync.js’)
})
}
document.getElementById(“bBtn”).onclick = function() {
require.ensure([], function() {
var bwork = require(’./workB-async.js’)
alert(bwork.data)
})
}
可以看到,workA-async.js, workB-async.js 都是点击后才ensure进来的。什么时候加载完成呢?就是 require.ensure() 第二个函数参数,即回调函数,它表示当下载js完成后,发生的因为逻辑
webpack打包后,形成
其实, 1.1… 2.2…就是我们ensure导出来的js文件
我们看看代码是如何加载的执行的,点击打包插入js后的html
可以看到,并没有加载 ensure导出来的 1.1…js 2.2…js
点击 abtn,
发现浏览器下载并加载了 1.1…js
点击 bbtn
发现浏览器下载并加载了 2.2…js
vue项目优化,还有通过减少向服务器请求的次数来减少等待的时间。比如,一个页面的数据包括图片、文字等用户都已经加载完了,然后用户通过点击跳转到了另外一个界面。然后从另外一个界面通过返回又回到了原先的界面。如果没有设置的话,那么原先界面的信息就要重新向服务器请求得到。而通过vue提供的keep-alive可以是页面的已经请求的数据得以保存,减少请求的次数,提高用户的体验程度。具体怎么使用,大家可以看我写的另外一个博客: vue项目优化之通过keep-alive数据缓存(vue+webpack)
篇开始学习webpack打包的构建配置,所用版本为webpack 4.16.1和webpack-cli 3.2.3。
由于主要开发电商项目,所以对webpack配置生成多页面html更感兴趣。
配置生成html的插件采用html-webpack-plugin,主要作用是:根据模板生成页面/无模板生成页面、自动引入js等外部资源、设置title/meta等标签内容。
还是从最简单的单入口配置开始,安装相应包的过程略,直接给出webpack.config.js配置:
const path = require( "path" );
const HtmlWebpackPlugin = require( "html-webpack-plugin" );
const CleanWebackPlugin = require( "clean-webpack-plugin" );
module.exports = {
entry: {
app: __dirname + "/src/index.js"
},
output: {
filename: "[name].[chunkhash].bundle.js",
path: path.resolve( __dirname, "dist" )
},
devtool: "inline-source-map",
mode: "development",
module: {
rules:[
]
},
plugins: [
new HtmlWebpackPlugin( {
title: "开发测试页面"
} ),
new CleanWebackPlugin( ["dist"] )
],
}
接下来是多入口页面配置。
多页面演示模型如下:
webpack.config.js配置如下:
const path = require( "path" );
const webpack = require( 'webpack' );
const HtmlWebpackPlugin = require( "html-webpack-plugin" );
const CleanWebpackPlugin = require( "clean-webpack-plugin" );
module.exports = {
entry: {
main: __dirname + "/src/js/main.js",
about: __dirname + "/src/js/about.js",
list: __dirname + "/src/js/list.js"
},
output: {
filename: "js/[name].[chunkhash].bundle.js",
path: path.resolve( __dirname, "dist" )
},
devtool: "inline-source-map",
module: {
rules: [
]
},
plugins: [
new HtmlWebpackPlugin( {
// html文件 title标签的内容
title: "main",
// 输出的文件名,可配置路径
filename: "views/main.html",
// 采用的模板文件名,可配置路径
template: "src/views/main.html",
// 生成的html文件中引入的js文件名,与entry入口和slpitChunks分离等配置的js文件名相同
chunks: [ "main", "manifest", "vendors", "common" ]
} ),
new HtmlWebpackPlugin( {
title: "about",
filename: "views/about.html",
template: "src/views/about.html",
chunks: [ "about", "manifest", "vendors", "common" ]
} ),
new HtmlWebpackPlugin( {
title: "list",
filename: "views/list.html",
template: "src/views/list.html",
chunks: [ "list", "manifest", "vendors", "common" ]
} ),
new webpack.ProvidePlugin( {
// npm i jquery -S 安装jquery,然后利用ProvidePlugin这个webpack内置API将jquery设置为全局引入,从而无需单个页面import引入
$: "jquery"
} ),
new CleanWebpackPlugin( ["dist"] )
],
// 提取公共模块,包括第三方库和自定义工具库等
optimization: {
// 找到chunk中共享的模块,取出来生成单独的chunk
splitChunks: {
chunks: "all", // async表示抽取异步模块,all表示对所有模块生效,initial表示对同步模块生效
cacheGroups: {
vendors: { // 抽离第三方插件
test: /[\\/]node_modules[\\/]/, // 指定是node_modules下的第三方包
name: "vendors",
priority: -10 // 抽取优先级
},
utilCommon: { // 抽离自定义工具库
name: "common",
minSize: 0, // 将引用模块分离成新代码文件的最小体积
minChunks: 2, // 表示将引用模块如不同文件引用了多少次,才能分离生成新chunk
priority: -20
}
}
},
// 为 webpack 运行时代码创建单独的chunk
runtimeChunk:{
name:'manifest'
}
}
}
多页面多入口场景中,使用以上配置可以正常打包。
上例加上JQuery这个第三方库,为方便各页面引用,利用webpack内置API中的ProvidePlugin对象将jquery设置成全局对象以供使用,无需在各页面import了。
另外也多处引用有一个util.js的自定义工具库。
上例通过optimization.splitChunks配置将第三方库分离打包到vendors.js文件中,将自定义工具库util.js分离打包到common.js文件中。
如下是多入口项目完整目录截图,dist目录为打包后目录:
本篇实现单入口/多入口打包功能。采用html生成插件为html-webpack-plugin。分离共用模板插件为SplitChunksPlugin。
转载:https://cloud.tencent.com/developer/article/1495249