const {resolve} = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
//浏览器兼容性问题默认设置的是生产环境
// 若要设置为开发环境,此处添加 process.env.NODE_ENV = 'development'
//压缩css
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
/*
PWA:渐进式网络开发应用程序(离线可访问)
workbox --> workbox-webpack-plugin
*/
const WorkboxWebpackPlugin = require('workbox-webpack-plugin')
/*
tree shaking : 去除无用代码
前提:1.必须使用ES6模块化 2.开启production环境
作用:减少代码体积
在package.json中配置
"sideEffects": false 所有代码都没有副作用 (都可以进行 tree shaking)
问题: 可能会把 css / @babel/polyfill (副作用)文件干掉
"sideEffects": ["*.css","*.less"] 使不会对css文件处理
*/
/*
缓存:
babel缓存
cacheDirectory:true
-->让第二次打包构建速度更快
文件资源缓存
hash:每次webpack构建时会生成一个唯一的hash值。
问题:因为js和css同时使用一个hash值。
如果重新打包,会导致所有缓存失效(可能我值改动一个文件)
chunkhash(代码块hash,以同一个入口文件):根据chunk生成的hash值。如果打包来源于同一个chunk,那么hash值旧一样
问题:js和css的hash值还是一样的
因为css是在js中被引入的,所以同属于一个chunk
contenthash:根据文件内容生成hash值,不同文件hash值一定不一样
-->让代码上线运行缓存更好使用
*/
//正常来说一个文件那只能被一个loader处理,如果需要被多个loader处理,需要指定loader的执行顺序
// 先执行eslint 再执行babel ebforce:'pre'
module.exports = {
entry: {
// 多入口
index: './src/js/index.js',
test: './src/js/test.js'
},
output: {
// [name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
// 单入口
// entry: './src/index.js',
// output: {
// filename: 'built.[contenthash:10].js',
// path: resolve(__dirname, 'build')
// },
module: {
rules: [
// oneOf提升构建速度,使一个文件不会被所有loader匹配
{
// 以下loader只会匹配一个
oneOf: [
{
// ...
}
]
},
{
// 语法检查 eslint-loader eslint
// 值检查自己写的代码,第三方库不用检查的
// 设置检查规则 在package.json中eslintConfig中设置
//"eslintConfig": {
// "extends": "airbnb-base"
// }
// 使用airbnb规则需要下载 --> eslint-config-airbnb-base eslint-plugin-import eslint
test: /\.js$/,
exclude: /node_modules/,
// 设置优先执行
enforce:'pre',
loader: 'eslint-loader',
options: {
// 自动修复错误
fix:true
}
},
// js兼容性处理 babel-loader @babel/preset-env @babel/core
// @babel/preset-env 问题是只能转换基本语法,promise等语法无法转换
// @babel/polyfill 可以兼容全部js 问题是体积太大 只需要在index.js中引入即可 import '@babel/polyfill'
// core-js按需加载
{
test: /\.js$/,
exclude:/node_modules/,
loader: 'babel-loader',
options: {
// 预设:还是babel做怎样的兼容性处理
// presets:['@babel/preset-env'],
presets:[
[
'@babel/preset-env',
//按需加载
{
useBuiltIns: 'usage',
// 指定corejs版本
corejs: {
version:3
},
// 兼容性做到那个版本浏览器
targets: {
chrome: '60',
firefix: '60',
ie: '9',
safari: '10'
}
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
},
/*
开启多进程打包 thread-loader
进程启动大概为600ms,进程通信也有开销
只有工作消耗时间比较长,才需要进行多进程打包
*/
{
test: /\.js$/,
exclude:/node_modules/,
use:[
// 'thread-loader', //默认按照cpn核数-1
{
loader: 'thread-loader',
options: {
workers: 2 //进行2个
}
},
{
loader: 'babel-loader',
options: {
// 预设:还是babel做怎样的兼容性处理
// presets:['@babel/preset-env'],
presets:[
[
'@babel/preset-env',
//按需加载
{
useBuiltIns: 'usage',
// 指定corejs版本
corejs: {
version:3
},
// 兼容性做到那个版本浏览器
targets: {
chrome: '60',
firefix: '60',
ie: '9',
safari: '10'
}
}
]
],
// 开启babel缓存
// 第二次构建时,会读取之前的缓存
cacheDirectory: true
}
}
]
},
{
test: /\.css$/,
use: [
//创建style标签,将样式引入
// 'style-loader',
//取代style-loader 作用提取js中的css成单独文件
MiniCssExtractPlugin.loader,
//将css文件整合到js文件
'css-loader',
// css兼容性处理 postcss --> postcss-loader postcss-preset-env
//帮postcss找到package.json 中browserslist里面的配置,通过配置加载指定的css兼容性样式
//"browserlist": {
//"development": [
// "last 1 chrome version",
// "last 1 firefox version",
// "last 1 safari version"
// ],
// "production": [
// ">0.2%",
// "not dead",
// "not op_mini all"
// ]
//}
//postcss-loader
// 修改loader的配置
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => {
require('postcss-preset-env')
}
}
}
]
},
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 问题,处理不了html中img图片
test: /\.(jpg|png|gif)$/,
//url-loader file-loader
loader: 'url-loader',
options: {
//图片大小小于8kb 就会被base64处理
//优点:减少请求数量(减轻服务器压力)
//缺点:图片体积会更大(文件请求速度更慢)
limit: 8 * 1024,
//问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs
//解析时会出现问题:[objext Module]
//解决:关闭url-loader的es6模块化,使用commonjs解析
esModule:false,
//给图片进行重命名
//[hash:10]取hash的前10位 [ext]取文件原来的扩展名
name: '[hash:10].[ext]'
}
},
{
test: /\.html$/,
//用于处理html文件中的img图片(负责引入img,从而能被url-loader进行处理)
loader: 'html-loader'
},
{
// 打包出html/js/css以外的其他资源
exclude: /\.(css|js|html|less|jpg|png|gif)$/,
loader:'file-loader',
options: {
name: '[hash:10].[ext]',
// 输出目录build/imgs
outputPath: 'imgs'
},
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
// 压缩html
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true
}
}),
new MiniCssExtractPlugin({
// 对生成的文件重命名
filename: 'css/built.css'
}),
// 压缩css
new OptimizeCssAssetsWebpackPlugin(),
// pwa 在入口文件中需配置
/*
注册serviceworker
处理兼容性问题
if('serviceWorker' in navigator) {
windwo.addEventListener('load', () => {
navigator.serviceWorker
.register('/service-worker.js')
.then(()=>{
console.log('注册成功')
})
.catch(()=>{
console.log('注册失败')
})
})
}
1.由于识别不了window navigator等,会报eslint错误
解决:需修改package.json中eslintConfig配置
"env": {
"broser": true
}
2.sw代码必须运行在服务器上
-->1种是nodejs
-->另一种是 npm i serve -g
serve -s build 启动服务器 将build 目录下所有资源作为静态资源暴露出去
*/
new WorkboxWebpackPlugin.GenerateSW({
/*
1.帮助serviceworker快读启动
2.删除旧的serviceworker
生成一个 serviceworker 配置文件
*/
clientsClaim: true,
skipWaiting: true
})
],
/*
code split 分割代码
可以将node_modules中代码单独打包成一个chunk最终输出
自动分析多入口chunk中,有没有公共的文件。如果有会打包成单独一个chunk
*/
optimization:{
splitChunks: {
chinks: 'all'
}
},
mode: 'development',
// 有些包需要用script标签通过cnd引入,需要忽略库
extermals: {
// 拒绝jQuery
jquery: 'jQuery'
},
//开发服务器 devServer: 用来自动化(自动编译,自动打开浏览器,自动刷新浏览器)
//特点:只会在内存中编译打包,不会有任何输出
//启动devServer指令为 npx webpack-dev-server
devServer: {
//项目构建后的路径
contentBase: resolve(__dirname, 'build'),
//启动gzip压缩
compress: true,
//端口号,
port: 3000,
//自动打开浏览器
open: true,
//开启HMR功能 只更新修改部分 便于更改某一个模块时,页面不全部刷新,只更新指定模块
// 样式文件 style-loader内部实现了HMR
// html文件默认不能使用HMR 一旦开启HMR功能,将无法热更新,此时在entry中添加html路径,即可热更新
// js文件默认不能使用hmr功能 --》需要在入口文件修改js代码,添加支持HMR功能的代码
// 入口文件添加代码块 改变print.js代码 只更新此模块
// if(module.hot){
// module.hot.accept('.print.js',function(){
// 操作
// })
// }
hot: true,
},
devtool: 'eval-source-map'
// source-map 提供源代码到构建后代码的映射技术
// [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
// source-map:外部
// 错误代码准确信息 和 源代码的错误位置
// inline-source-map:内联
// 只生成一个内联source-map
// 错误代码准确信息 和 源代码的错误位置
// hidden-source-map:外部
// 错误代码错误原因。但是没有错误位置
// 不能追踪源代码错误,只能提示到构建后代码的错误位置
// eval-source-map:内联
// 每一个文件都生成对应的source-map,都在eval
// 错误代码准确信息 和 源代码的错误位置
// nosources-source-map:外部
// 错误代码准确信息,但是没有任何源代码信息
// cheap-source-map:外部
// 错误代码准确信息 和 源代码的错误位置
// 只能精确的行
// cheap-module-source-map:外部
// 错误代码准确信息 和 源代码的错误位置
// module会将loader的source map加入
// 内联 和 外部的区别:1.外部生成了文件,内联没有 2.内联构建速度更快
// 开发环境:速度快,调试更友好
// 速度快(eval>inline>cheap>...)
// eval-cheap-source-map
// eval-source-map
// 调试更友好
// source-map
// cheap-module-source-mao
// cheap-source-map
// vue中使用的是 eval-source-map /eval-cheap-module-source-map
// 生产环境:需确认源代码要不要隐藏?调试要不要更友好
// 内联会让代码体积变大,所以生产环境不用内联
// nosources-source-map 全部隐藏
// hidden-source-map 只会隐藏源代码,会提示构建后代码错误信息
// --> source-map/cheap-module-source-map
}
// 懒加载和预加载
document.getElementById('btn').onclick = function() {
// 懒加载:当文件需要使用时才加载
// 预加载 prefetch: 会在使用之前,提前加载js文件
// 正常加载可以认为时并行加载(同一时间加载多个文件)
// 预加载 prefetch: 等其他资源加载完毕,浏览器空闲了,再偷偷加载资源
import (/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({mul})=>{
console.oog(mul(4.5))
})
}
/*
dll与external的区别
dll只打包一次,下一次速度就快了
external是完全不打包 只通过cdn引入
创建文件webpack.dll.js文件
使用dll技术,对某些库(第三方库:jquery,vue...)进行单独打包
当你运行 webpack 时,默认查找 webpack.config.js配置
需求:需要运行webpack.dll.js 文件
--> webpack --config webpack.dll.js
*/
const { resolve } = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
// 最终打包生成的[name] --> jquery
// ['jquery'] --> 要打包的库是jquery
jquery: ['jquery']
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'dll'),
library: '[name]_[hash]'//打包的库里面向外暴露出去的内容叫什么名字
},
plugins: [
// 打包生成一个 mainfest.json --> 提供和jquery映射
new webpack.DllPlugin({
name: '[name]_[hash]',//映射库的暴露的内容名称
path: resolve(__dirname, 'dll/mainfest.json')//输出文件路径
}),
],
mode: 'production'
}
/*
在webpack.config.js中
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin')
// 告诉webpack哪些库不参与打包,同时使用时的名称也得变
new webpack.DllReferencePlugin({
mainfest:resolve(__dirname, 'dll/mainfest.json')
}),
// 将某个文件打包输出去,并在html种自动引入该资源
new AddAssetHtmlWebpackPlugin({
filePath: resolve(__dirname,'dll/jquery.js')
})
*/
webpack5系统学习
最新推荐文章于 2024-09-06 11:26:45 发布