打包环境的区分
打包工具的配置在生产环境中,不同于开发模式,所以我们需要对配置文件进行区分。
既然要开始区分,我们就单独将分开的配置文件单独命名放在一个文件夹中,方便管理
webpack.prod.js(到本章为止,最新的配置)
生产环境
const Version = new Date().getTime();
// nodejs中的包,用来解析当前路径
const path = require('path')
// 引入动态插入JS
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 引入动态插入CSS
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// 引入eslint
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
// 压缩Css代码
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
// 合并同类配置
function getStyleLoader(exLoader) {
return [
// 将Css提取成单独文件,插入html的link
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
exLoader
].filter(Boolean)
}
// commonJS语法
module.exports = {
// 环境模式:开发模式development,生产模式production
mode: 'production',
// 入口
// 拼接要打包的文件路径,参数1起名约定俗成,参数二定位文件夹位置, 参数三打包的入口
// __dirname,是一个成员,用来动态获取当前文件模块所属的绝对路径
// __filename,可以动态获取当前文件夹的绝对路径(包含文件名)
entry: path.join(__dirname, '../src', 'index.js'),
// 输出
// 入口文件打包输出的文件名
output: {
path: path.join(__dirname, '../dist'),
filename: 'static/js/bundle'+Version+'.js',
// 原理:在打包前,将path路径下的文件清空
clean: true
},
// 插件
plugins: [
new HtmlWebpackPlugin({
// 同entry注释
template: path.join(__dirname, '../src', 'index.html'),
// 打包后的文件名
filename: 'bundle.html'
}),
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.join(__dirname, "../src"),
}),
new MiniCssExtractPlugin({
filename: 'static/css/bundle.css'
}),
// css压缩
new CssMinimizerPlugin(),
],
// 模块
module: {
rules: [
{
test: /\.css$/i,
use: getStyleLoader()
},
// 配置样式文件
{
// 正则匹配文件
test: /\.s[ac]ss$/i,
use: getStyleLoader('sass-loader') // 将sass/scss编译成css
},
{
test: /\.less$/i,
use: getStyleLoader('less-loader') // 将less编译成css
},
{
test: /\.(png|jpe?g|gif|webp|svg)$/i,
// 设置资源类型用于匹配模块。它防止了 defaultRules 和它们的默认导入行为发生。
type: 'asset',
// 解析选项对象,匹配条件
parser: {
dataUrlCondition: {
// 小于10kb的图片转base64
maxSize: 10 * 1024 // 10kb
}
},
generator: {
// 定义图片资源输出路径
// hash生成文件唯一名,10代表取名字前十位。ext是文件扩展名。query代表图片?携带的参数。
filename: "static/images/[hash:10][ext][query]"
}
},
{
test: /\.(ttf|woff2?|mp3|mp4|avi|rmvb)$/i,
// 这样可以避免文件转化为base64的格式
type: 'asset/resource',
generator: {
// 定义字体图标资源输出路径
filename: "static/asset/[hash:10][ext][query]"
}
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules中的js文件(这些不处理)
loader: "babel-loader",
options: {
// @babel/preset-env: 一个智能预设,允许您使用最新的 JavaScript。
// @babel/preset-react:一个用来编译 React jsx 语法的预设
// @babel/preset-typescript:一个用来编译 TypeScript 语法的预设
presets: ["@babel/preset-env"],
}
},
]
},
devServer: {
static: [
{
directory: path.join(__dirname, '../dist'),
}
],
// 是否自动打开浏览器
// open: true,
// 启动服务器域名
// host: 'localhost',
// 指定运行的端口
// vue项目默认运行在8080
port: 3000,
// 存放静态资源的文件夹
// static: path.join(__dirname, 'dist')
}
}
webpack.dev.js(到本章为止,最新的配置)
开发环境中,无需输出打包文件
const Version = new Date().getTime();
// nodejs中的包,用来解析当前路径
const path = require('path')
// 引入动态插入JS
const HtmlWebpackPlugin = require('html-webpack-plugin')
// 引入动态插入CSS
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// 引入eslint
const ESLintWebpackPlugin = require("eslint-webpack-plugin");
// 合并同类配置
function getStyleLoader(exLoader) {
return [
// 将Css提取成单独文件,插入html的link
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
exLoader
].filter(Boolean)
}
// commonJS语法
module.exports = {
// 环境模式:开发模式development,生产模式production
mode: 'development',
// 入口
// 拼接要打包的文件路径,参数1起名约定俗成,参数二定位文件夹位置, 参数三打包的入口
// __dirname,是一个成员,用来动态获取当前文件模块所属的绝对路径
// __filename,可以动态获取当前文件夹的绝对路径(包含文件名)
entry: path.join(__dirname, '../src', 'index.js'),
// 输出
// 入口文件打包输出的文件名
// 开发模式不用输出
output: {
path: undefined,
filename: 'static/js/bundle'+Version+'.js',
},
// 插件
plugins: [
new HtmlWebpackPlugin({
// 同entry注释
template: path.join(__dirname, '../src', 'index.html'),
// 打包后的文件名
filename: 'bundle.html'
}),
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.join(__dirname, "../src"),
}),
new MiniCssExtractPlugin(),
],
// 模块
module: {
rules: [
{
test: /\.css$/i,
use: getStyleLoader()
},
// 配置样式文件
{
// 正则匹配文件
test: /\.s[ac]ss$/i,
use: getStyleLoader('sass-loader') // 将sass/scss编译成css
},
{
test: /\.less$/i,
use: getStyleLoader('less-loader') // 将less编译成css
},
{
test: /\.(png|jpe?g|gif|webp|svg)$/i,
// 设置资源类型用于匹配模块。它防止了 defaultRules 和它们的默认导入行为发生。
type: 'asset',
// 解析选项对象,匹配条件
parser: {
dataUrlCondition: {
// 小于10kb的图片转base64
maxSize: 10 * 1024 // 10kb
}
},
generator: {
// 定义图片资源输出路径
// hash生成文件唯一名,10代表取名字前十位。ext是文件扩展名。query代表图片?携带的参数。
filename: "static/images/[hash:10][ext][query]"
}
},
{
test: /\.(ttf|woff2?|mp3|mp4|avi|rmvb)$/i,
// 这样可以避免文件转化为base64的格式
type: 'asset/resource',
generator: {
// 定义字体图标资源输出路径
filename: "static/asset/[hash:10][ext][query]"
}
},
{
test: /\.js$/,
exclude: /node_modules/, // 排除node_modules中的js文件(这些不处理)
loader: "babel-loader",
options: {
// @babel/preset-env: 一个智能预设,允许您使用最新的 JavaScript。
// @babel/preset-react:一个用来编译 React jsx 语法的预设
// @babel/preset-typescript:一个用来编译 TypeScript 语法的预设
presets: ["@babel/preset-env"],
}
},
]
},
devServer: {
static: [
{
directory: path.join(__dirname, '../dist'),
}
],
// 是否自动打开浏览器
// open: true,
// 启动服务器域名
// host: 'localhost',
// 指定运行的端口
// vue项目默认运行在8080
port: 3000,
// 存放静态资源的文件夹
// static: path.join(__dirname, 'dist')
}
}
优化CSS加载速度(基于webpack5新特性)
如果Css文件是引入JS中被打包,这样在页面被加载时,执行顺序为html-->js-->css,用户看到的就会是,先是无样式的文本信息,然后会突然变换文本样式,弹出各种图片媒体信息。这样的闪屏,非常影响体验。
解决思路为:将Css单独提取为文件,通过html中的link标签加载
由此我们引入插件mini-css-extract-plugin
引入插件
// 引入动态插入CSS
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
加载插件
plugins: [
new MiniCssExtractPlugin(),
]
使用插件(将所有style-loader替换)
CSS兼容处理
前文中提到了JS的浏览器兼容问题,CSS同样也是需要解决的。
我们所需要的依赖有:
postcss-loader(用来处理css的load)
postcss(postcss-loader依赖于它)
postcss-preset-env(兼容,智能预设)
要将配置项插入css-loader之后
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
我们需要在 package.json 文件中添加 browserslist 来控制样式的兼容性做到什么程度。
// 兼容IE8以上
"browserslist": ["ie >= 8"]
想要知道更多的 browserslist 配置,查看browserslist 文档
合并同类项
在loader中已经有太多的重复配置项了,为方便统一管理,使用方法集中配置
// 合并同类配置
function getStyleLoader(exLoader) {
return [
// 将Css提取成单独文件,插入html的link
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
exLoader
]
}
CSS压缩优化处理
通过格式化等方式减少Css文件的体积,达到压缩的目的
引入webpack5新插件css-minimizer-webpack-plugin 较前一代optimize-css-assets-webpack-plugin,在 source maps 和 assets 中使用查询字符串会更加准确,支持缓存和并发模式下运行。
// 压缩Css代码
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
plugins: [
// css压缩
new CssMinimizerPlugin(),
]