一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
简介
- 基于
webpack@5.82.0
本文包含的 loader
如下
- sass-loader(scss 转 css) git 仓库
- postcss-loader (css 加各种兼容前缀)git 仓库
- css-loader(将 css 文件转化成 webpack module ,支持 import 等) git 仓库
- style-loader (将 css 文件以 style 标签方式放到 html head 中) git 仓库
包含的 plugin
如下
- mini-css-extract-plugin(提取 css 成单独文件) git 仓库
- html-webpack-plugin(将输出的 bundle.js、style.css 等自动放入模板 html 中) git 仓库
npm install
sh
# 基础三件套,sass 需要 额外安装 node-sass
npm i style-loader css-loader sass-loader node-sass -D
# postcss ,额外增加 autoprefixer 插件自动补全
npm i postcss postcss-loader postcss-preset-env autoprefixer -D
# plugin
npm i mini-css-extract-plugin -D
npm i html-webpack-plugin -D
loader 流程图
原始 .scss 样式
我们来看一个 scss 文件通过各种哪个 loader 转换后各个输出是什么样子的。
下面是开发人员写的 scss 样式。
css
.box {
background-color: blue;
padding: 20px;
display: flex;
.title {
color: #00000066;
flex: 1;
transform: rotate(90deg);
}
}
sass-loader 编译后
嵌套的样式等等 sass 高阶样式都转换成平铺的 css 样式
css
.box {
background-color: blue;
padding: 20px;
display: flex;
}
.box .title {
color: rgba(0, 0, 0, 0.4);
flex: 1;
transform: rotate(90deg);
}
postcss-loader 编译后
需要额外配置 postcss.config.js
文件 ,包含需要使用的插件
ini
const config = {
plugins: [require("autoprefixer")], // 自动根据 caniuse 里面的兼容性自动补全各种浏览器前后缀
};
module.exports = config;
同时,额外配置 package.json
中的 browserslist
指定索要支持的浏览器类型。
经过 postcss-loader
编译后文件如下
css
.box {
background-color: blue;
padding: 20px;
display: -webkit-box;
display: -webkit-flex;
display: -moz-box;
display: flex;
}
.box .title {
color: rgba(0, 0, 0, 0.4);
-webkit-box-flex: 1;
-webkit-flex: 1;
-moz-box-flex: 1;
flex: 1;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
}
css-loader 编译后
- 将上述代码转换成 js 代码,
- 支持
import
语法导入到 js 文件中, - 开启
module
支持模式 - 变量重命名,避免重复等问题,比如下面的
U0owno48RksV_sCqH1K_
,也可以额外配置命名规则 localidentname, 让 classname 更语义化,方便阅读
js
import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from "../node_modules/css-loader/dist/runtime/noSourceMaps.js";
import ___CSS_LOADER_API_IMPORT___ from "../node_modules/css-loader/dist/runtime/api.js";
var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___);
// Module
___CSS_LOADER_EXPORT___.push([module.id, ".U0owno48RksV_sCqH1K_ {\n background-color: blue;\n padding: 20px;\n display: -webkit-box;\n display: -webkit-flex;\n display: -moz-box;\n display: flex;\n}\n.U0owno48RksV_sCqH1K_ ._10LGwUfHrljqaYJfVKI {\n color: rgba(0, 0, 0, 0.4);\n -webkit-box-flex: 1;\n -webkit-flex: 1;\n -moz-box-flex: 1;\n flex: 1;\n -webkit-transform: rotate(90deg);\n -moz-transform: rotate(90deg);\n -ms-transform: rotate(90deg);\n transform: rotate(90deg);\n}", ""]);
// Exports
export var box = "U0owno48RksV_sCqH1K_";
export var title = "_10LGwUfHrljqaYJfVKI";
export default ___CSS_LOADER_EXPORT___;
页面可以使用 import * as styles from "./index.module.scss";
方式引入使用。
这里相当于默认用了 CSS Modules 的方式
ts
import React, { useEffect, useRef } from "react";
import * as styles from "./index.module.scss";
interface Props {
text?: string; // 要绘制的文本
}
const ShowHello = ({ text = "" }: Props) => {
return (
<div className={styles.box}>
<div style={{ background: "pink" }}>Hello word,{text}</div>
</div>
);
};
export default ShowHello;
style-loader 编译后
style-loader
编译后,将 css 文件以 <style>.xxx</style>
方式放到 html 中。
html
<html>
...
<head>
<style>
.U0owno48RksV_sCqH1K_ {
background-color: blue;
padding: 20px;
display: -webkit-box;
display: -webkit-flex;
display: -moz-box;
display: flex;
}
.U0owno48RksV_sCqH1K_ ._10LGwUfHrljqaYJfVKI {
color: rgba(0, 0, 0, 0.4);
-webkit-box-flex: 1;
-webkit-flex: 1;
-moz-box-flex: 1;
flex: 1;
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
}</style>
</head>
<body>
<div id="root">
<div class="U0owno48RksV_sCqH1K_">
<div style="background: pink;">Hello word,Nice day!</div>
</div>
</div>
<script src="bundle.js"></script>
</body></html>
一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第54天,点击查看活动详情。
一般会在 dev 环境下使用。
生产环境一般后面的插件 mini-css-extract-plugin
,单独提取 css 文件。
mini-css-extract-plugin 提取 css
引入插件,提取生成 style.css
文件,存在内存中,和 bundle.js
一样,
js
// webpack plugin
plugins: [
new MiniCssExtractPlugin({
filename: "style.css", // 定义的 CSS 文件名
}),
],
配置 loader
js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// webpack module 配置
module:{
{
test: /\.scss$/,
use:[..., MiniCssExtractPlugin.loader,"css-loader",...] // 引入 loader
}
}
因为 style.css
文件在内存中,需要手动引入到 html 文件中,以 <link href ... />
方式。
html
// head 中手动下面一行内容
<link href="style.css" rel="stylesheet" />
或者自动引入,增加 html-webpack-plugin
插件,自动会引入打包后的 js 和 css 文件到 head 中
js
const HtmlWebpackPlugin = require("html-webpack-plugin");
// webpack plugin 内容
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, "../example/public/index.html"), // 使用 xxx 模板
inject: "body", // 将 js 注入到 body 中(不写这个会默认放到 head 中)
}),
]
webpack 最终配置
js
const path = require("path");
const { merge } = require("webpack-merge");
const baseConfig = require("./webpack.base.js"); // 公共配置
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const devConfig = {
mode: "development", // 开发模式
entry: path.join(__dirname, "../example/src/index.tsx"), // 入口,处理资源文件的依赖关系
output: {
path: path.join(__dirname, "../example/public/"),
filename: "bundle.js",
},
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader",
],
},
],
},
devServer: {
static: path.join(__dirname, "../example/public/"),
compress: true,
host: "127.0.0.1",
port: 4000, // 启动端口
open: false, // 打开浏览器
},
plugins: [
new MiniCssExtractPlugin({
filename: "style.css", // 提取的 CSS 文件名
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, "../example/public/index.html"),
inject: "body",
}),
],
};
module.exports = merge(devConfig, baseConfig); // 合并配置