webpack学习(三)
module:就是js的模块化webpack支持commonJS、ES6等模块化规范,简单来说就是你通过import语句引入的代码。
chunk: chunk是webpack根据功能拆分出来的,包含三种情况:
1、你的项目入口(entry)
2、通过import()动态引入的代码
3、通过splitChunks拆分出来的代码
chunk包含着module,可能是一对多也可能是一对一。
bundle:bundle是webpack打包之后的各个文件,一般就是和chunk是一对一的关系,bundle就是对chunk进行编译压缩打包等处理之后的产出。
一、优化
1.noParse: 不去解析属性值代表的库的依赖
表示在打包的时候不用再去深度解析某个第三方库中的依赖包,类似jq这类依赖库,一般会认为不会引用其他的包(特殊除外,自行判断)。所以,对于这类不引用其他的包的库,我们在打包的时候就没有必要去解析,这样能够增加打包速率。
2.IgnorePlugin
表示忽略第三方包指定目录,让这些指定目录不要被打包进去
这是webpack自带的一个插件
比如我们要使用moment这个第三方依赖库,该库主要是对时间进行格式化,并且支持多个国家语言。在打包的时候,是会将所有语言都打包进去的。这样就导致包很大,打包速度又慢我们可以用这个插件忽略掉这些语言的打包,然后手动引入需要的语言包
plugins:[
//webpack自带插件,从moment中引入的时候忽略掉语言
new webpack.IgnorePlugin(/\.\/locale/,/moment/),
new htmlWebpackPlugin({
template: './public/index.html'
})
]
index.js
import moment from 'moment'
//设置语言 忽略之后不再生效需要
// moment.locale('zh-cn')
//这时候需要手动引入需要的语言
import 'moment/locale/zh-cn'
let r = moment().endOf('day').fromNow() //距离今天结束还有几小时
console.log(r)
没有忽略语言包之前的大小
忽略掉语言包之后的大小
3. DllPlugin
这块没看懂,推荐这篇文章:https://www.cnblogs.com/tugenhua0707/p/9520780.html
4.Happypack 多进程打包
在使用 Webpack 对项目进行构建时,会对大量文件进行解析和处理。当文件数量变多之后,Webpack 构件速度就会变慢。由于运行在 Node.js 之上的 Webpack 是单线程模型的,所以 Webpack 需要处理的任务要一个一个进行操作。
而 Happypack 的作用就是将文件解析任务分解成多个子进程并发执行。子进程处理完任务后再将结果发送给主进程。所以可以大大提升 Webpack 的项目构件速度
由于 JavaScript 是单线程模型,要想发挥多核 CPU 的能力,只能通过多进程去实现,而无法通过多线程实现。
HappyPack 对file-loader、url-loader 支持的不友好,所以不建议对该loader使用。
之前打包js用的是这些loader
现在需要happypack
当项目体积庞大的时候用多进程打包会加快打包速率,小体积项目反而会降低打包速率,因为分配时进程本身也需要花费时间。
happypack原理请看这篇文章:https://segmentfault.com/a/1190000021037299?utm_source=tag-newest
5.webpack自带优化工具
- tree-shaking 会自动将没用到的代码删除掉
test.js
function sum (a, b) {
return a+b
}
function minus (a, b) {
return a-b
}
export default{
sum, minus
}
index.js
import calc from './test' console.log(calc.sum(1,2))
- scope hosting 作用域提升
let a = 1
let b = 2
let c = 3
let d = a+b+c //webpack会自动省略可以简化的代码
console.log(d+'------')
6.抽取公共代码
如果某个js文件被多个js代模块引用就可以将这个公共的代码块分割出去,打包成一个公共文件,代码分割是基于浏览器会缓存你的代码这一事实。每当你对某一文件做点改变,访问你站点的人们就要重新下载它。然而依赖却很少变动。如果你将(这些依赖)分离成单独的文件,访问者就无需多次重复下载它们了。
假设有两个页面index和other,现在这两个文件都需要引入a.js和b.j,如果不分割,这两个页面就都会有a.js的内容和b.js的内容,抽取之后这些公共内容将会放在一个common.js中,然后index和other各自的页面只包含自己的那部分内容,这个时候我们就可以这么配置了
entry: {
index: './src/index.js',
other: './src/other.js'
},
output: {
filename: '[name].js',
path:path.resolve(__dirname,'dist')
},
module:{
optimization:{
splitChunks:{ //分割代码
cacheGroups:{ //缓存组
common:{ //公共模块
chunks:'initial', //chunks有三个参数,initial表示只从入口模块进行拆分 async表示只从异步加载得模块(动态加载import())里面进行拆分 all表示以上两者都包括
minSize:0, //表示在压缩前的最小模块大小
minChunks:2 //只要超过2次以上引用就抽离
},
}
}
},
打包后的结果如下:
有时候我们还需要引入第三方模块,比如jquery等,这个时候也需要抽离这些第三方模块。如下配置:
entry: {
index: './src/index.js',
other: './src/other.js'
},
output: {
filename: '[name].js',
path:path.resolve(__dirname,'dist')
},
module:{
optimization:{
splitChunks:{ //分割代码
cacheGroups:{ //缓存组
common:{ //公共模块
chunks:'initial', //chunks有三个参数,initial表示只从入口模块进行拆分 async表示只从异步加载得模块(动态加载import())里面进行拆分 all表示以上两者都包括
minSize:0, //表示在压缩前的最小模块大小
minChunks:2 //只要超过2次以上引用就抽离
},
vendor:{ //抽离第三方模块
priority:1, //表示先抽离第三方模块再抽离公共模块,不加这个的话第三方模块将和公共模块放在一起,不太好
test:/node_modules/, //从node_modules里面抽取
chunks:'initial',
minSize:0, //表示在压缩前的最小模块大小
minChunks:2 //只要超过2次以上引用就抽离
}
}
}
打包结果:
7.懒加载
有时候我们会点击某个按钮再去加载对应的资源,也可以理解成是异步加载某个资源,如下代码:
let button = document.createElement('button')
button.innerHTML = 'hello'
//点击按钮加载资源
button.addEventListener('click',function(){
//es6草案语法 其原理是jsonp实现动态加载文件
import('./source.js').then(data=>{
console.log(data)
})
})
document.body.appendChild(button)
再点击按钮之后通过import加载了source.js文件,返回一个promise,就可拿到这个文件里的内容
8.热更新
我们希望在页面发生了变化的时候只更新那一部分变化了的内容,而不是整个全部刷新。
webpack.config.js配置
devServer:{
hot:true, //启用热更新
port:3000,
open:true,
contentBase: './dist'
},
plugins:[new webpack.HotModuleReplacementPlugin(), //热更新插件
new webpack.NamedModulesPlugin() //告诉哪个模块更新了
]
index.js
import str from './source.js'
console.log(str)
if(module.hot) {
module.hot.accept('./source.js',()=>{
//import只能写在页面的顶端
let str = require('./source.js')
console.log(str.default)
})
}
当source.js内容发生了变化就不会刷新整个页面了而是更新一部分
当然最好能搞懂热更新的原理