主题
样式处理
webpack默认不认识样式文件css
、scss
、less
等,需要通过loader来处理
1. css处理--开发
- 下载loader
bash
pnpm add -D style-loader css-loader
style-loader
:作用是将样式文件以style标签的形式插入页面
css-loader
:作用是解析css
- 配置loader
js
// webpack.dev.js`
{
test: /\.css$/i,
exclude: /node_modules/,
use: ["style-loader", "css-loader"],
},
2. scss处理--开发
- 下载loader
bash
pnpm add -D sass sass-loader
- 配置
js
// webpack.dev.js
{
test: /\.sc|ass$/i,
exclude: /node_modules/,
use: ["style-loader", "css-loader", "sass-loader"],
},
3. css、scss处理--生产环境
开发环境下的样式文件是与js混在一起的,有利于加快构建速度,但是生产环境下(打包构建)这样可不行,我们需要将样式文件单独提出来作为独立文件,这个操作,style-loader无法处理,需要额外的loader处理
css提取与压缩
- 安装
bash
pnpm add -D mini-css-extract-plugin
- 配置
js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [new MiniCssExtractPlugin(
{}
)],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"], // MiniCssExtractPlugin.loader用于提取css文件
},
{
test: /\.sc|ass$/i,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"], // MiniCssExtractPlugin.loader用于提取css文件
},
],
},
};
4. CSS Module处理
配置css-loader兼容cssModule
js
{
test: /\.css$/i,
exclude: /node_modules/,
use: [
"style-loader",
{
loader: "css-loader", // 解析 CSS 文件
options: {
modules: { namedExport: false },
},
},
],
},
就可以通过import的方式引入css文件,然后像js对象一样使用这个样式文件
存在的问题
css-loader的配置导致所有css文件都开启module,会浪费编译性能
使用css-module后,css类名是一串乱码hash,不太友好
不会为module.css当都生成一个文本
解决
将css.module文件的处理的loader独立开来,不与css混在一起,并且在css-loader中排除 .module.css
文件
js
rules: [
{
test: /\.css$/i, // 仅处理正常的css
exclude: [/node_modules/, /\.module\.css$/i],
use: ["style-loader", "css-loader"],
},
{
test: /\.module\.css$/i, // 专门处理 cssModule
exclude: [/node_modules/],
use: [
"style-loader",
{
loader: "css-loader", // 解析 CSS 文件
options: {
modules: {
namedExport: false, // 是否启用命名导出
localIdentName: "[name]__[local]--[hash:base64:5]", // 生成的类名格式
},
},
},
],
}
],
5. CSS后处理器
作用:兼容性处理、添加浏览器前缀
bash
pnpm add -D postcss poscss-loader postcss-preset-env
postcss-preset-env:一堆预设,包含了autofix等很多功能
PostCSS 插件传送门
- 配置
在css-loader
后面加上postcss-loader
js
{
test: /\.sc|ass$/i,
exclude: /node_modules/,
use: [
"style-loader",
{
loader: "css-loader", // 解析 CSS 文件
options: {
modules: { namedExport: false },
},
},
"postcss-loader", // 处理 CSS 前缀
"sass-loader", // 解析 Sass 文件
],
},
创建postcss.config.js
文件
js
// postcss.config.js
module.exports = {
plugins: [["postcss-preset-env"]],
};
6. 自动注入全局样式文件
场景:项目中有一个全局的scss变量文件variables.scss
,每个每个scss或者vue sfc文件都需要通过@import '@/assets/styles/variables.scss';
来使用
就比较麻烦, 此时style-resources-loader
就派上用场了[style-resources-loader](样式资源加载器 - npm)传送门
- 安装
bash
pnpm add -D style-resources-loader
- 配置
js
const path = require('path');
module.exports = {
// ...
module: {
rules: [{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader', {
loader: 'style-resources-loader',
options: {
patterns: [
path.resolve( __dirname, "../src/assets/styles/variables.scss" ),
]
}
}]
}]
},
// ...
}
7. 样式处理优化
优化点1:将样式处理提取到webpack.base.js
中,通过打包环境区分是否要提取css
优化点2:使用oneof优化css处理
优化点3:将处理css的loader封装成函数
最终结果
- 获取loader辅助函数
js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const getStyleLoader = () => {
// 需要先设置好环境变量
if (process.env.NODE_ENV === "production") {
return MiniCssExtractPlugin.loader;
}
return "style-loader";
};
const getCssLoaders = (isModule) => {
return !isModule
? "css-loader"
: {
loader: "css-loader", // 解析 CSS 文件
options: {
modules: {
namedExport: false, // 是否启用命名导出
localIdentName: "[name]__[local]--[hash:base64:5]", // 生成的类名格式
},
},
};
};
module.exports = {
getStyleLoader,
getCssLoaders,
};
webpack.base.js
js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const VueLoaderPlugin = require("vue-loader").VueLoaderPlugin;
const webpack = require("webpack");
const { getStyleLoader, getCssLoaders } = require("./util");
/**
* @type {import('webpack').Configuration}
* @description webpack基础配置
*/
module.exports = {
entry: path.resolve(__dirname, "../src/main.ts"), // 入口文件
output: {
path: path.resolve(__dirname, "../dist"), // 打包后输出目录
filename: "js/[name].[contenthash:6].js",
clean: true, // 清空上一次打包的输出目录, webpack5内置
publicPath: "/", // 打包后的资源路径前缀
},
resolve: {
alias: {
"@": path.resolve(__dirname, "../src"), // @指向src目录
vue$: "vue/dist/vue.runtime.esm-bundler.js", // vue的运行时模块别名
},
extensions: [".ts", ".js", ".vue", ".json"], // 解析文件后缀名
modules: [path.resolve(__dirname, "../src"), "node_modules"], // 告诉 webpack 解析模块时应该搜索的目录。
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"), // 模板文件
filename: "index.html", // 打包后的文件名
title: "webpack5-vue3-ts", // 页面标题
inject: true, // 是否自动注入js和css文件
}),
new VueLoaderPlugin(),
new webpack.DefinePlugin({
__VUE_OPTIONS_API__: true, // 开启options api 解除控制台警告
__VUE_PROD_DEVTOOLS__: false, // 生产环境不启用devtools 解除控制台警告
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false, // 禁用生产中水合不匹配的详细警告
}),
],
module: {
rules: [
{
test: /\.m?jsx?$/,
exclude: /node_modules/,
loader: "babel-loader",
},
{
test: /\.vue$/,
loader: "vue-loader",
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [
{
loader: "ts-loader",
options: {
transpileOnly: true, // 只进行类型检查,不进行编译
appendTsSuffixTo: [/\.vue$/], // 给.vue文件添加ts后缀
},
},
"babel-loader",
],
},
{
oneOf: [
{
test: /\.css$/i,
exclude: [/node_modules/, /\.module\.css$/i],
use: [getStyleLoader(), getCssLoaders(), "postcss-loader"],
},
{
test: /\.module\.css$/i,
exclude: [/node_modules/],
use: [
getStyleLoader(),
getCssLoaders(true),
"postcss-loader", // 处理 CSS 前缀
],
},
{
test: /\.sc|ass$/i,
exclude: /node_modules/,
use: [
getStyleLoader(),
getCssLoaders(),
"postcss-loader", // 处理 CSS 前缀
"sass-loader", // 解析 Sass 文件
{
loader: "style-resources-loader",
options: {
patterns: [
path.resolve( __dirname, "../src/assets/styles/variables.scss" ),
], // 引入全局变量和混入
},
},
],
},
],
},
],
},
};
然后,删除webpack.dev.js
与webpack.prod.js
里面的样式处理loader
即可