webpack成神(2)
Yu Lei 2019-3-26
webpack
webpack 环境配置
使用环境变量
在开发环境 使用 dev 上线环境使用 production 测试环境使用 test,可以使用 webpack 自带插件 webpack.DeffinePlugin
```javascript
plugins: [new webpack.DefinePlugin(
# 第一种 方法
DEV:"'dev'"//要用双引号 内部嵌套一个单引号,因为如果只写一个引号相当于 console。log(dev)这个时候dev 是未定义的
# 第二种方法
DEV:JSON.stringify('production'),//输出字符串
FLAG:'true',//输出boolean 的true
EXPORESSION:'1+1' //输出2//在内部可以直接使用这些值
)]
```
区分环境变量
创建三个配置文件,webpack.base.js webpack.production.js webpack.development.js
使用 webpack-merge
```javascript
# 安装
npm i webpack-merge -D
# 在开发环境中使用
let {smart} = require('webpack-merge')
let base = require('./webpack.base.js')
module.export=smart(base,{//集成了base中的所有配置 并且把mode 环境配置更改为development
mode:'development',
devserver,
devtool...
})
# 在生产环境中使用
let {smart} = require('webpack-merge')
let base = require('./webpack.base.js')
module.export=smart(base,{//集成了base中的所有配置 并且把mode 环境配置更改为development
mode:'production',
minimizer...
})
```
webpack 的优化
webpack 的忽略解析
配置不去解析特定包,看到包就忽略掉 在 module 选项下 配置noParse:/jquery/
,这样可以根据通配符
找到 jquery 而不去解析 jquery 中的依赖项
配置 js 时默认会默认解析 node-modules
这个时候需要配置 babel 的排除和包含关系,排除 exclude 包含 include
```javascript
{
test:/\.js/,
exclude:/node_modules/,//排除node-modules 目录
include:path.resolve('src'),//包含 src目录,意思时只在src 中进行寻找
use:{
loader:'babel-loader',
options:{
presets:[
'@babel/preset-env',
'@babel/preset-react'
]
}
}
}
```
关于某些库的优化
忽略掉第三方库内引用了却在实际开发中没有使用的代码块,使用 webpack.IgnorPlugin()
```javascript
# 使用
plugins:[
new webpack.IgnorePlugin(/\./locale/,/monent/)//如果在moment中引用了。locale 这个文件夹 就忽略掉这个打包请求
]
# 自己手动引用忽略的包 这样就可以减小打包体积
```
动态链接库
如果在开发过程中需要某些第三方的库,这些库在后期过程中时根本不会产生变动并且这些库又很大,所以这分割时候
可以在打包的过程中先抽离打包出这个库,然后把这些库作为后续开发的依赖引入。
```javascript
# 新建配置文件webpack.config.react.js,这个配置文件作为打包第三方库依赖的配置文件
let path = require('path')
const webpack =require('webpack')
module.export={
mdoe:'development',
extry:{
react:['react','react-dom']
}
output:{
filename:'_dll_[name].js',//打包生成第三方库的文件名称
path:path.resolve(__dirname,'dist'),//生成路径
library:'_dll_[name]',//生成第三方模块的入口变量名称
libaryTarget:'var'//caonst commenjs ... 生成第三方库的导出方式 一般是使用var 默认不写是var
},
plugins:[
new webpack.DLLPlugin({
name:'_dll_[name]',//这个名字和libary 名字要相同,打包出依赖的第三方库
path:path.resolve(__dirname,'dist','manifest.json')//生成第三方库 在我们些的js 中引用和依赖的地图
})
]
}
//根据上面文件打包会出现一个 manifest.json 关系对应地图 和一个_dll_react.js的文件
//使用上面的文件 在html 中引入 ./_dll_react.js
//然后再wenpack。config。js 中指定如果在打包过程中华又依赖关系到react 或者react-dom 那么去动态链接库中查找 而不是重新对node-modules 打包
//
plugins:{
new webpack.DLLReferencePlugin({
manifest:path.resolve(__dirname,'dist','minifest.json') //引用重新打包的依赖地图
})
}
```
多线程打包实现快速打包
当项目比较大的时候使用多线程打包会加快速度 ,
使用 happypack
```javascript
//安装
npm i happypack -D
//使用
const HappyPackPlugin = reuqire('happypack')
//在module中需要使用多线程快速打包的地方
module:{
noParse:/jquery/,
rules:[
{
test:/\.js$/,
exclude:/node_modules/,
use:'HappyPackPlugin/loader?id=js'
},
{
test:/\.css$/,
use:'HappyPackPlugin/loader?id=css'
}
]
},
//在plugins 中指定happypack
plugins:[
new HappyPackPlugin({//通过id=js 找到上面的use 然后是u用happy 中定义的规则解析器进行打包
id:'js',
use:[
{
loader:'babel-loader',
options:{
presets:[
'@babel/preset-env',
'@babel/preset-react'
]
}
}
]
}),
new HappyPackPlugin({//通过id=css 找到上面的use 然后是u用happy 中定义的规则解析器进行打包
id:'css',
use:[
{
loader:MinicssWebpackPlugin.loader,
options:{
}
},
'css-loader',
'postcss-loader'
]
})
]
```
webpack 中的自带优化打包,
- webpack 在打包的时候默认在生产环境下会去除掉 import 却没有使用的代码块,而在开发环境下不会,这种叫做 tree-shaking
把没用到的代码自动删除掉,而如果使用 require 打包的时候会把没用到的代码也打包,也就是 require 不支持 tree-shaking
- scope hosting 在 webpack 中会自动省略一些可以简化的代码
抽取公用代码
多用于多入口,与动态链接库有很大的差别,动态链接库最好不要使用与线上环境和整体性比较差的库。
```javascript
// 在多入口多界面的时候如果 A 界面和B 界面又公用的部分 我们希望把他们单独抽取出来这样在A页面加载的时候加载出来 在B页面就不要再进行加载了
//首先配置多入口
module.exports = {
mode: 'production',
entry: {
index: __dirname + '/src/index.js',
other: __dirname + '/src/other.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
optimization: {
splitChunks: {
//分割代码块
cacheGroups: {//缓存组
common: {//配置公共代码块的规则
chunks:'initial',//从入口处就开始提取代码 后面还有异步模块
miniSize:0,//超过大小就会被抽离
miniChunks:2,//引用多少次会被抽离 至少引用2次就会被抽离
},
verder:{//第三方模块被重复引用也会被抽离单个打包
priority:1,//优先抽离的权重,配置为1 权重越高先抽离 抽离 好单独的第三方然后再抽离 公用自定义代码 生成单独文件
test:/node_modules/,//正则匹配,可以使用es 正则匹配返回值形式
chunks:'initial',//从入口处就开始提取代码 后面还有异步模块,all async
miniSize:0,//超过大小就会被抽离
miniChunks:2,//引用多少次会被抽离 至少引用2次就会被抽离,默认为1次 2次是抽离公用代码的最小颗粒度
}
}
}
}
}
```
懒加载
```javascript
let btn = document.createElement('button')
btn.innerHTML = 'click'
btn.addEventListener('click', function() {
import('./source.js').then(data => {
data.dafault
})
})
document.body.appendChild(btn)
```
如果要实现上面的懒加载功能--点击按钮异步加载一个 js 代码块 然后自己执行
实现上面功能需要 babel 的语法自动导入的插件 @babel/plugin-syntax-dynamic-import 需要再 wabpack 中设置
```javascript
//安装
npm i @babel/plugin-syntax-dynamic-import -D
//使用
{
test:/.js$,
use:[
{
loader:'babel-loader',
options:{
presets:[
'@babel/preset-env',
'@babel/preset-react'
],
plugins:[
'@babel/plugin-syntax-dynamic-import' //实现动态加载 ,在 引入的地方在defalt 上拿出来使用
]
}
}
]
}
// vue react 等的路由的懒加载都是通过这种方法来实现的 实质上是jsonp
```
在实际生产中打包会生成两个 js 文件一个是正常页面使用的 index。js 还会生成一个 懒加载请求的 1.js 当执行懒加载的时候才会请求到 1.js
热更新
在开发过程中,每次保存或者代码有改变的时候会重新更新 代码重启服务器
注意:这个插件和 cleanwebpackplugin 插件同时使用会出现问题
```javascript
devServer:{
port:3000,
hot:true,//开启热更新
open:true,
contentBase:'./dist'
},
plugins:[
new webpack.NameModulePlugin(),//告诉我们热更新的模块的名称,打印更新的模块路径
new webpack.HotModlePrplacementPlugin()//wenpack 热更熊模块支持
]
//使用 热更新模块引入后会自动起作用 而NameModulePlugin 则要配合使用
//在js中可以写
import str from './index.js'
console.log(str)
if(module.hot){
module.hot.accept('./index',()=>{//这个就是namemodule的作用
console.log('文件更新了')
let str = require('./index.js')
console.log(str)
})
}
```