/**
* HMR: hot module replacement 热模块替换./ 模块热替换
* 需在devServer 添加hot属性
* 作用:一个模块发生变化,只会重新打包这一个模块,(而不是打包所有模块)
* 极大提升构建速度
* 样式文件:可以使用HMR 功能 :因为style-loader内部实现了
* js文件: 默认不能使用HMR 功能 ==》 需要修改js 代码,添加支持HMR功能的代码
* 注意:HMR 只能对js的处理,只能处理非入口文件js的其它文件
* html文件:默认不能使用HMR 功能,同时会导致问题:html 不能热更新了 (不需要做HMR功能)
* 解决:修改entry 入口 为数组, 将html 文件引入
*
*/
/**
* webpack 优化如下:
*
* 1.缓存:
* babel 缓存
* cacheDirectory:true
* ---> 让第二次打包构建速度更快
* 文件资源缓存
* hash:每次webpack构建时会程程一个唯一的hash的值
* 问题:因为js和css 同时使用一个hash值
* 如果重新打包,会导致所有缓存失效,(可我缺只改动了一个文件)
* chunkhash:根据chunk生成的hash值,如果打包来源于同一个chunk,那么hash值就一样
* 问题:js和css 的hash值还是一样的
* 因为css 是js中被引入的 所以同属于一个hash值
* contenthash:根据文件内容生成hash值,不同文件的hash值不一样
* ---> 让代码上线运行缓存更好使用
*
* 2.tree shaking (树摇) 去除无用代码
* 前提:1.必须使用es6模块化,2.开启production环境
* 作用:减少打包体积
* 注:
* 在package.json 中配置
* 'slideEffects':false, 所有代码都没有副作用,(都可以进行tree shaking)
* 问题:可能回把css/@babel/polyfill (副作用)文件干掉
* 改成'slideEffects':["*.css",'*.less'],
* 3.代码分割
*
*/
// node 中的变量
const {resolve}=require('path')
//拆分css 插件
const MiniCssExtractPlugin=require('mini-css-extract-plugin')
//对CSS代码进行压缩
const OptimizeCssAsetsWebpackPlugin=require('optimize-css-asets-webpack-plugin')
//引入html模板插件=>对html 处理
const HtmlWebpackPlugin=require('html-webpack-plugin')
//定义node.js 环境变量:决定使用browserslist的那个环境
process.env.NODE_ENV='production'
// 复用loader
const commonLoader=[
// 'style-loader',
// 这个loader 取代style-loader,作用:提取js中的css成单独文件
MiniCssExtractPlugin.loader,
'css-loader',
/** 对样式兼容性处理 */
{
//还需要在package.json 中定义browserslist兼容哪些浏览器
loader:'postcss-loader', //该loader 只能解析css 文件
options: {
postcssOptions:{
plugins: [[postcss-preset-env,{}]]
}
}
},
]
/**
* loader: 1. 下载 2. 使用(配置loader)
* pulgin:1. 下载 2. 引入 3. 使用
*/
module.exports={
//入口文件
// html文件:默认不能使用HMR 功能,同时会导致问题:html 不能热更新了 (不需要做HMR功能)
// * 解决:修改entry 入口 为数组, 将html 文件引入
// entry:['./src/js/index.js','./src/index.html'],
entry:'./src/js/index.js',
//输出对象
output:{
//输出文件名
filname:'js/build.js',
//输出文件目录,_dirname nodejs 的变量 代表当前文件的目录的绝对路径
path:resolve(__dirname,'build')
},
//loader加载器 =》翻译官
module:{
rules:[
//一下loader只会匹配一个
// 注意不能有两个配置处理同一种类型文件
// 优化:提高构建速度
// oneOf:[]
{
test:'/\.css$/',
// 使用多个loader 的时候 使用use 只有一个时候 就用laoder
use:[ //改数组的执行顺序是 从下往上执行
// // 'style-loader',
// // 这个loader 取代style-loader,作用:提取js中的css成单独文件
// MiniCssExtractPlugin.loader,
// 'css-loader',
// /** 对样式兼容性处理 */
// {
// //还需要在package.json 中定义兼容哪些浏览器
// loader:'postcss-loader', //该loader 只能解析css 文件
// options: {
// postcssOptions:{
// plugins: [[postcss-preset-env,{}]]
// }
// }
// }
...commonLoader
]
},
{
/***
*
* 注义: use:数组的执行顺序是 从下往上执行先执行less-loader 会将less 文件编译成css文件,经过postcss文件时
* 会将css文件做兼容性处理,再通过css-loader加载到js 中,再由minicssextractplugin插件从js中提取出来成为单独文件
*
*/
test:'/\.css$/',
use:[ //改数组的执行顺序是 从下往上执行
// 'style-loader',
// 这个loader 取代style-loader,作用:提取js中的css成单独文件
// MiniCssExtractPlugin.loader,
// 'css-loader',
// /** 对样式兼容性处理 */
// {
// //还需要在package.json 中定义browserslist兼容哪些浏览器
// loader:'postcss-loader', //该loader 只能解析css 文件
// options: {
// postcssOptions:{
// plugins: [[postcss-preset-env,{}]]
// }
// }
// },
...commonLoader, //取上面的定义的变量
'less-loader'
]
},
/**
* 正常来讲,一个文件只能被一个loader处理
* 当一个文件被多个loader处理,那么一定要指定老弟儿执行的先后顺序:
* 先执行eslint 在执行babel,需要设置 enforce参数
*
*/
{
/**
* 语法检查: eslint-loader eslint
* 注意:只检查自己写的源码,第三方的库是不会检查的
* 设置检查规则:
* package.json中eslintConfig中设置~
* eslintConfig:{
* 'extends':'airbnb-base'
* }
* aribnb --> eslint-config-airbnb-base eslint-plugin-import eslint
*/
test:/\.js$/,
//排除文件
exclude:/node_modules/,
//执行顺序=>优先执行 在所有loader中 优先执行
enforce:'pre',
loader:'eslint-loader',
options:{
//自动修复 eslint 的错误
fix:true,
},
},
{
/**js 兼容性处理:babel-loader @babel-core
* 1. 基本js兼容处理 --> @babel/preset-env
* 问 :只能转换基本语法,列如:箭头函数,再如:promise高级语法就不能转换
* 2.全部js兼容性处理 --> @babel-polyfill
* 直接在全局中 引入 import '@babel-polyfill'
* 问题:只需要解决部分兼容性问题,但是会将所有的兼容代码引入 ,体积太大
* 3.需要做兼容性处理的就做:按需加载 --> core-js
*/
test:/\.js$/,
//排除文件
exclude:/node_modules/,
loader:'babel-loader',
options:{
//y预设:指示babel做怎么样的兼容性处理
persets:[
'@babel/perset-env',
/**以下 方式 则 是第三种方案 => 按需加载 */
{
//按需加载
useBulitIns:'usage',
//指定core-js版本
corejs:{
version:3
},
//指定兼容性做到哪个版本浏览器
targets:{
chrome:'60',
firefox:'60',
ie:'9',
safari:'10',
edge:'17'
}
}
],
// 开启babel 缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory:true,
},
},
{
// 问题:默认处理不了html中的img 图片资源
test:/\.(jpg|png|gif)/,
loader:'url-loader',
options:{ //该字段为重新定义
limit:8*1024, // 小于8kb的文件进行base64处理, 优点:减少请求数量(减轻服务器压力),缺点:图片体积会更大 文件请求速度更慢
name:'[hash:10].[ext]', //给图片重命名,[hash:10]取图片的hash的前10位,[ext]取文件原来的扩展名
outputPath:'imgs', //s输出文件
//问题 因为url—loader 默认使用es6模块化解析,而html-loader引入图片时commonjs
//解析是出现问题:[object module]
//解决: 关闭url-loader 的es6模块化,使用commonjs 解析
esModule:false, //关掉es6 //如果是webpack 是5 的 esModule:false,放到html-loader那里就可以了
}
},
{
/** 为了专门处理html中的图片问题 (负责引入img , 从而被url-loader处理) */
test:/\.html*$/,
loader:'html-loader', // 此loader 使用的模板化是commonjs 而url loader 使用的是es6
// options: {
// esModule:false, //关掉es6 //如果是webpack 是5 需要此操作
// }
},
{
/** 其他文件处理 */
exclude:/\.(js|css|less|html|jpg|png|gif)/,
loader:'file-loader',
options:{
outputPath:'media' //s输出文件
}
},
]
},
plugins:{
//功能:拆分css 代码成一个单独文件
new MiniCssExtractPlugin({
//重命名目录
filname:'css/build.css',
}),
//功能:压缩css 代码
new OptimizeCssAsetsWebpackPlugin(),
//功能:默认会创建一个空的 html ,自动引入打包输出的所有资源(js/css)
new HtmlWebpackPlugin({
template:'./src/index.html', // 以指定html文件为模板创建新的html文件
//压缩html代码
monify:{
//移除空格
collapseWithspace:true,
//移除注释
removeComments:true,
}
}),
},
//解析模块的规则
resolve:{
//配置解析模块路径别名:优点点简写路径,缺点路径没有提示
alias:{
$css:resolve(__dirname,'src/css')
},
//配置省略文件路径的后缀名
extensions:['.js','.json','.css'],
//告诉webpack 解析模块是去找哪个目录
moudules:[ resolve(__dirname,'../../node_modules'),'node_modules']
},
/**
* 1.可以将node_modules 中代码单独打包一个chunk最终输出
* 2. 自动分析多入口chunk中,有没有公共的文件,如果有会打包成单一的chunk
* */
optimization:{
splitChunks:{
chunks:'all',
//以下模块不写不配置就会使用其默认值
// minSize:30*1024 , //分割的chunk 最小为30kb
// maxSize:0, //最大没有限制
// minChunks:1,// 要提取的chunk最少被引用1次
// maxAsyncRequests:5 ,// 按需加载时并行加载的文件的最大数量
// maxInitialReaquwsts:3 ,// 入口js文件最大请求数量
// automaticNameDelimiter:'~' ,// 名称链接符
// name:true, //可以使用命名规则
// cacheGroups:{ //分割chunk的组
// //node_modules 文件会被打包到vendors组的chunk中 ==》vendors~xxx.js
// //满足上面的规则,如:大小超过30kb,至少被引用一次
// vendors:{
// test:'/[\\/]node_modules[\\/]/',
// //优先级
// priority:-10,
// },
// default:{
// // 要提取chunk至少被引用2次
// minChunks:2,
// //优先级
// priority:-20,
// //如果是当前要导报的模块,和之前已经被提取的模块是同一个,就会复用,而不是重新打包模块
// reuseExistingChunk:true,
// }
// }
}
},
//生产环境下 webpack会自动压缩js代码 mode:'production'
mode:'development',
// 开发模式
devServer:{
//运行代码的目录
contentBase:resolve(__dirname,'build'),
//坚实contentBase目录下的所有文件,一旦文件变化就会reload
watchContentBase:true,
watchOptions:{
//忽略文件
ignored:/node_modules/
},
// 启动gzip压缩
compress:true,
// z指定端口号
port:3000, // 启动端口
host:'localhost',//域名
open:true, //是否默认打开浏览器
hot:true, // 开启HMR功能=> 热更新
clientLogLevel:'none',//b不显示启动服务器日志信息
quiet:true,// 除了一些基本启动信息以外,其他内容都不要显示
//如果出错了不要进行全屏提示
overlay:false,
// 服务器代理===》 解决开发环境跨域问题
proxy:{
//一旦devServer(5000) 服务器接收到/api/xxx 开头的请求,就会把请求转发到另一个服务器
'/api':{
target:'http://localhost:3000',
// 发送请求是,请求路径重写:讲/api/xxx ===>/xxx(去掉/api)
pathRewrite:{
'^/api':''
}
}
}
},
/**
* source-map: 一种提供源代码到构建后代吗映射 技术,(如果收件后代码出错了 通过映射可以追踪源代码错误)
*
* [inline-|hidden-|eval-][nosource-][cheap-[module-]] source-map
* source-map: 外部
* 1.错误代码准确信息和源代码的错误位置
* inline-source-map:内联
* 1.只生成一个内联source-map1
* 2.错误代码准确信息和源代码的错误位置
* hidden-source-map:外部
* 1.错误代码,错误原因,没有错误位置
* 2.不能跟踪准确信息,和错误位置
* eval-source-map:内联
* 1.每个文件都会生成一个source-map eval
* 2.错误代码准确信息和源代码的错误位置
* nosource-source-map:外部
* 1.能找错误的准确信息,但是没有任何源代码信息
* cheap-source-map:外部
* 1.错误代码准确信息和源代码的错误位置,只能精确到行
* cheap-module-source-map:外部
* 1.错误代码准确信息和源代码的错误位置,只能精确到行
*
*
* 内联和外联的区别:1.外部生成了文件,内联没有,2.内联构建速度更快
*
* 开发环境:速度快,调试更友好
* 1.速度快 eval>inline>cheap>eval-cheap-source-map>eval-source-map
* 2.调试更友好
* source-map>eval-cheap-source-map>cheap-source-map
*
* 结论:==》 eval-source-map/eval-cheap-moudle-souce-map
*
*
* 生成环境:源代码要不要隐藏?调试要不要达到更友好
* 内联:体积大,所以生产环境不用内联
* source-map
*/
devtool:'source-map'
}