利用 webpack 拆分 css
要拆分 css,就必须把 css 当成像 js 那样的模块;要把 css 当成模块,就必须有一个构建工具(webpack),它具备合并代码的能力
而 webpack 本身只能读取 css 文件的内容、将其当作 JS 代码进行分析,因此,会导致错误(原因是 AST 抽象语法树无法解析 css)
于是,就必须有一个 loader,能够将 css 代码转换为 js 代码,通过 AST 抽象语法树。
该问题解决了上个章节中提出的最后一问---如何将 css 进行细分。
css-loader
css-loader 的作用,就是将 css 代码转换为 js 代码
pnpm i css-loader -D
它的处理原理极其简单:将 css 代码作为字符串导出
例如:
.red {
color: "#f40";
}
经过 css-loader 转换后变成 js 代码:
module.exports = `.red{
color:"#f40";
}`;
上面的 js 代码是经过我简化后的,不代表真实的 css-loader 的转换后代码,css-loader 转换后的代码会有些复杂,同时会导出更多的信息,但核心思想不变
再例如:
.red {
color: "#f40";
background: url("./bg.png")
//无法解析,因为图片通不过AST,需要file-loader或者url-loader
;
}
经过 css-loader 转换后变成 js 代码:
var import1 = require("./bg.png"); //file-loader会返回解析后的路径
module.exports = `.red{
color:"#f40";
background:url("${import1}")
}`;
这样一来,经过 webpack 的后续处理,会把依赖./bg.png
添加到模块列表,然后再将代码转换为
var import1 = __webpack_require__("./src/bg.png");
module.exports = `.red{
color:"#f40";
background:url("${import1}")
}`;
再例如:
@import "./reset.css"; //css-loader会将该模块解析为字符串,并拼接到最终结果去
.red {
color: "#f40";
background: url("./bg.png");
}
会转换为:
var import1 = require("./reset.css");
var import2 = require("./bg.png");
module.exports = `${import1}
.red{
color:"#f40";
background:url("${import2}")
}`;
总结,css-loader 干了什么:
- 将 css 文件的内容作为字符串导出
- 将 css 中的其他依赖作为 require 导入,以便 webpack 分析依赖
- 就算多次导入引用,也只会执行一次,因为 webpack 分析依赖的时候会对照资源记录表
style-loader
由于 css-loader 仅提供了将 css 转换为字符串导出的能力,剩余的事情要交给其他 loader 或 plugin 来处理
style-loader 可以将 css-loader 转换后的代码进一步处理,将 css-loader 导出的字符串加入到页面的 style 元素中
pnpm i style-loader -D
例如:
.red {
color: "#f40";
}
经过 css-loader 转换后变成 js 代码:
module.exports = `.red{
color:"#f40";
}`;
经过 style-loader 转换后变成:
module.exports = `.red{
color:"#f40";
}`;
var style = module.exports;
var styleElem = document.createElement("style");
styleElem.innerHTML = style;
document.head.appendChild(styleElem);
module.exports = {};
以上代码均为简化后的代码,并不代表真实的代码 style-loader 有能力避免同一个样式的重复导入
实践
src/index.js
const bannerCss = require("./assets/banner.css"); //解析不了,我们要使用css-loader来解析css
console.log(bannerCss.toString());
const pagerCss = require("./assets/pager.css"); //解析不了,我们需要file-loader或者url-loader来解析里面引用的文件
// //css-loader只是将css文件解析为js字符串,并没有自动的创建style插入到页面,这个工作需要style-loader来完成
const style = document.createElement("style");
style.innerHTML = pagerCss.toString();
document.head.appendChild(style);
src/assets/banner.css
.banner {
color: "#f40";
}
src/assets/pager.css
@import "./banner.css";
.pager {
width: 1000px;
height: 1000px;
color: "#f40";
/* 需要file-loader或者url-loader */
background: url("./bg.png");
}
webpack.config.js
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
mode: "development",
devtool: "source-map",
watch: true,
module: {
rules: [
//loader执行顺序是从后向前的,这里是要先css-loader然后才style-loader
{ test: /\.css$/, use: ["style-loader", "css-loader"] },
{ test: /\.png$/, use: "file-loader" },
],
},
//
plugins: [new CleanWebpackPlugin()],
};
总结
我们只需要记住一点,webpack 想要解析 css 的话,就需要 loader 来进行。
我们可以使用css-loader
和style-loader
来解析,有了这两个 loader,我们就解决了 css 模块化的问题。。
以后还会介绍将 css 以文件的形式生成的插件 plugins。