前言:最近有空看了看webpack5,干脆把webpack4仔细整理下。
webpack是用common.js,加上用到了node的基本知识点。先整理一部分基础,后续补充webpack性能优化,以及基础配置之上的详细配置。
webpack五个核心概念
先了解下webpack的基本核心配置,了解下这主要的五个核心概念,对webpack有个整体的概念,慢慢我们再来根据一个个需求,问题,逐级进阶。
1. entry 入口文件
2. output 打包的文件绝对路径
3. loader 资源转换器
4. plugins 插件
5. mode 环境模式,分生产环境,开发环境
//webpack.config.js
const {resolve} = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const commonCssLoader = [
//'style-loader',
MiniCssExtractPlugin.loader,//取代style-loader,提取js中css成单独文件
//可以用mini-css-extract-plugin把css提取出来,那就不需要style-loader,
'css-loader',
{
loader:'postcss-loader',//处理css的兼容性
options:{
ident:'postcss',
plugins:()=>[
//postcss的插件
require('postcss-preset-env')()
]}
];
module.exports={
entry:'./src/index.js',//就是写你的项目入口文件
output:{
filename:"built.js",//生成目录如何可以根据自己需要配置:js/built.js
path:resolve(__dirname,"build") //__dirname是获取node的绝对地址
},
module:{
rules:[
//loader的配置
{
test:/\.js$/,
exclude:/node_modules/,//把模块包排除
enforce:'pre',//优先执行,避免和下面的兼容性loader冲突
use: ['babel-loader?cacheDirectory=true'],
options:{
fix:true //自动修复
}
},
{
test: /\.js$/,
use: ['babel-loader?cacheDirectory=true'],
include: path.join(__dirname, '../src'),
exclude:/node_modules/,
options:{
//预设:指示babel做怎么样的兼容性处理
presets:[ [
'@babel/preset-env',
{
//按需加载就不需要第3步的加 "@babel/polyfill"
"useBuiltIns": "usage",
/**
* false : 不启用polyfill, 如果 import '@babel/polyfill', 会无视 browserlist 将所有的 polyfill 加载进来
entry : 启用,需要手动 import '@babel/polyfill', 这样会根据 browserlist 过滤出 需要的 polyfill
usage : 不需要手动import '@babel/polyfill'(加上也无妨,构造时会去掉), 且会根据 browserlist +,无法支持IE
*/
"corejs": {
version:3,//指定core-js版本
//指定兼容性做到那个版本的浏览器
targets:{
chrome:'60',
firfox:'60',
ie:'9',
safari:"10",
edge:"17"
}
}
}
],]
}
},
{
//处理css资源
test:/\.css$/,
use:[...commonCssLoader],
},
{
//处理less资源
test:/\.less$/,//正则匹配资源
use:[
//'style-loader',//把css字符串创建style标签插入到head中
//'css-loader',//把css转换成字符串,整合到js文件中。
...commonCssLoader,//代码复用,
{
loader: 'less-loader',
options: {
modules: true,
javascriptEnabled: true,
localIdentName: '[local]--[hash:base64:5]',//样式文件复用,避免class名重复出现问题
}
},
]//把less转换成css
},
{
//处理图片资源
test:/\.(jpg|png|gif|jpeg)/,
loader:'url-loader',
//url-loader是在file-loader的基础上的一个补充,可以将图片转成base64是专门针对图片的,所以安装npm包的时候,要下载url-loader file-loader。
//url-loader这个loader是指处理样式和js里面的图片处理,对于html里面引入的图片不起作用,所以还需要html-loader。
options:{
limit:8 * 1024,//8kby以下转成base64码
name:'[hash:10].[ext]',//hash值和ext值是打包运行就会生成的,在命令终端可以看到,各项资源打包的详细数据,有类型,size等等。
outputPath:'images',//输出路劲配置
//关闭es6模块化
esModule:false
}},
{
//处理html中img资源
test:/\.html$/,
loader:'html-loader'
//因为这个html-loader处理图片资源是用commonJs去解析,而上面url-loader是根据es6去解析,所以要关闭url-loader的es6模块化
},{
//处理其他资源
exclude:/\.(html|css|less|jpg|png|jpeg|gif)/,
loader:'file-loader',//直接将资源处理输出
}
]
},
plugins:[
//plugins的配置
new HtmlWebpackPlugin({
template:'./src/index.html',//生成html的时候可以用自己配置的html模板,如果在html页面有设置全局变量就可以不用每次部署都要替换。
}),
new MiniCssExtractPlugin(),//提取css文件
new OptimizeCssAssetsPlugin() //压缩css文件
],
mode:"development",//production 会自动压缩js代码
}
热更新
// webpack-dev-server
// contentBase: path.join(__dirname, '../dist'),
// 注:contentBase一般不配,主要是允许访问指定目录下面的文件,这里使用到了dist下面的index.html
devServer: {
// contentBase: path.join(__dirname, '../dist'),
compress: true, // gzip压缩
host: 'localhost', // 允许ip访问
hot: true, // 热更新
historyApiFallback: true, // 解决启动后刷新404
port: 9000,// 端口
proxy: { // 配置服务代理
'/api': {
target: 'http://localhost:8002',
pathRewrite: {'^/api': ''}, //可转换
changeOrigin: true, //解决跨域的问题
}
}
},
html代码压缩
new HtmlWebpackPlugin({
template:'./src/index.html',
//压缩代码处理
minify:{
//移除空格
collapseWhitespace:true,
//移除注释
removeComments:true}
}),
css兼容性处理、单独打包、压缩样式css
css兼容性处理 :
1. postcss ==> 安装postcss-loader postcss-preset-env
2. package.json中设置browserslist : GitHub上有browserslist的详细配置。
"browserslist": {
//这里的环境变量指的是node中的环境变量,所以process.env.NODE_ENV = 'development'
'development':[
"> 1%",
"last 2 versions"
],
//默认是生产环境
'production':[
"> 1%",
"not dead",//死掉的浏览器,太低版本的ie
"not op_mini_all",//欧朋浏览器。。。。
]}
3. webpack.config.js中loader配置
{
//处理css资源
test:/\.css$/,
use:[
//'style-loader',
MiniCssExtractPlugin.loader,//取代style-loader,提取js中css成单独文件
//可以用mini-css-extract-plugin把css提取出来,那就不需要style-loader,
'css-loader',
{
loader:'postcss-loader',
options:{
ident:'postcss',
plugins:()=>{
//postcss的插件
require('postcss-preset-env')()
}}}
],
},
压缩css
webpack.config.js中plugins配置
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
plugins:[
new OptimizeCssAssetsPlugin()
]
提取css文件,单独打包
/**
* hash是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的hash值都会更改,并且全部文件都共用相同的hash值
chunkhash和hash不一样,它根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值。
contenthash是针对文件内容级别的,只有你自己模块的内容变了,那么hash值才改变,所以我们可以通过contenthash解决上诉问题
*/
plugins:[
new MiniCssExtractPlugin({
filename: "static/[name].[contenthash].css",
chunkFilename: "static/[id].[contenthash].css"
})
]
语法eslint检查
1. eslint ===> 安装eslint eslint-loader
2. package.json中eslintConfig设置规则
"eslintConfig":{
"extends":"airbnb-base"
}
3. 推荐使用airbnb ===> 安装 eslint-config-airbnb-base eslint-plugin-import
4. loader配置
{
test:/\.js$/,
exclude:/node_modules/,//把模块包排除
loader:"eslint-loader",//eslint 语法检查
options:{
fix:true //自动修复eslint的错误
}
},
js兼容性处理
/*src目录下面的以.js结尾的文件,要使用babel解析*/
/*cacheDirectory是用来缓存编译结果,下次编译加速*/
1. 基本兼容处理:安装babel-loader @babel/core @babel/preset-env ,问题:只能转换基本语法,如高级语法promise就转换不了
2. loader配置
{
test: /\.js$/,
use: ['babel-loader?cacheDirectory=true'],
include: path.join(__dirname, '../src'),
exclude:/node_modules/,
options:{
//预设:指示babel做怎么样的兼容性处理
presets:['@babel/preset-env']
}
},
3. 全部兼容性处理 ,问题:所有兼容性代码都会引入,导致体积太大
entry: {
app: [
"@babel/polyfill", //全面的js兼容性处理,按需加载时去掉
path.join(__dirname, '../src/index.js')
],
vendor: ['react', 'react-router-dom', 'redux', 'react-dom', 'react-redux']
//vendor的意思是依赖的第三方库,不会经常变更的
},
4.按需加载 coreJs 安装core-js 推荐!!!
{
test: /\.js$/,
use: ['babel-loader?cacheDirectory=true'],
include: path.join(__dirname, '../src'),
exclude:/node_modules/,
options:{
//预设:指示babel做怎么样的兼容性处理
presets:[ [
'@babel/preset-env',
{
//按需加载就不需要第3步的加 "@babel/polyfill"
"useBuiltIns": "usage",
/**
* false : 不启用polyfill, 如果 import '@babel/polyfill', 会无视 browserlist 将所有的 polyfill 加载进来
entry : 启用,需要手动 import '@babel/polyfill', 这样会根据 browserlist 过滤出 需要的 polyfill
usage : 不需要手动import '@babel/polyfill'(加上也无妨,构造时会去掉), 且会根据 browserlist +,无法支持IE
*/
"corejs": {
version:3,//指定core-js版本
//指定兼容性做到那个版本的浏览器
targets:{
chrome:'60',
firfox:'60',
ie:'9',
safari:"10",
edge:"17"
}
}
}
],]
}
},
ps:babel的配置内容可以单独拉出来一个文件维护 在src同级创建一个 .babelrc的文件 ,内容是一样的
{
"presets":[],
"plugins":[]
}