为什么要打包样式
component.js
import "../css/index.css";
function component() {
const element = document.createElement("div");
element.innerHTML = "Hello World";
element.className = "content";
return element;
}
document.body.appendChild(component());
/css/index.css
.content{
color: red;
}
执行 npm run build 之后
webpack 可以处理 js 文件,但是当代码中 import 引入了 css 文件,webpack 不知道如何对其进行加载。
css-loader
css-loader 用于 css 文件的加载,将CSS资源编译成commonJS模块放到JS中。
安装:
npm install css-loader -D
css-loader 的使用
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
// 必须是一个绝对路径
path: path.resolve(__dirname, "./build")
},
module: {
rules: [
{
test: /\.css$/, // 匹配资源
use: [
{ loader: "css-loader" }
]
}
]
}
}
打包之后可以看到 css 代码已经加载到 js 中了
css-loader 只是负责将 .css 文件进行加载,并不会将加载之后的 css 插入到页面中,需要用 style-loader 完成插入样式的操作。
style-loader
将JS中的CSS通过创建style标签添加到HTML文件中生效。
安装:
npm install style-loader -D
配置:
{
test: /\.css$/, // 匹配资源
use: [
{ loader: "style-loader" },
{ loader: "css-loader" }
]
}
打包之后
less
1. less 处理
.less 文件可以使用 less 工具来完成它的编译,
- 安装:
npm install less -D - 执行:
npx less ./src/css/title.less > title.cssless-loader 可以识别 less 文件,加载 less 文件
index.less
@fontSize: 50px;
@fontWeight: 700;
.content {
font-size: @fontSize;
font-weight: @fontWeight;
}
执行:npx less ./src/css/title.less > title.css
.content {
font-size: 50px;
font-weight: 700;
}
2. less-loader 处理
- 作用:将less处理成css
- 安装:
npm install less less-loader -D(less-loader下载会自动把less也下载了) - 配置 webpack.config.js
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
"less-loader"
]
}
Sass 和 Scss 资源
下载包
npm i sass-loader sass -D
sass-loader:负责将 Sass 文件编译成 css 文件sass:sass-loader依赖sass进行编译 配置方式:
{
test: /.s[ac]ss$/,
use: ["style-loader", "css-loader", "sass-loader"],
}
浏览器兼容性
兼容性是针对不同的浏览器支持的特性:比如css特性、js语法,之间的兼容性。在很多的脚手架配置中,都能看到类似于这样的配置信息
> 1%
last 2 versions
not dead
查询到浏览器的市场占有率:"Can I use" usage table
.browserslist
不同的浏览器对于样式文件的支持度是不一样的,有的样式在部分浏览器中使用可能要加前缀,需要支持哪些浏览器的兼容性,这个是可以自己指定的。指定好支持的规则之后,用 browserslist 工具去查询
browserslist 工具
Browserslist是一个 在不同的前端工具之间 ,共享 目标浏览器和Node.js版本的配置
- Autoprefixer
- Babel
- postcss-preset-env
- eslint-plugin-compat
- stylelint-no-unsupported-browser-features
- postcss-normalize
- obsolete-webpack-plugin
浏览器查询过程
- 可以编写类似于这样的配置:
> 1%
last 2 versions
not dead
2. caniuse-lite 的工具进行查询。(来自于 caniuse 的网站)
如果没写 npx browserslist 后面的执行条件,会默认获取 .browserslistrc 中的查询条件
项目中的编写
工程化项目中创建 .browserslistrc 文件,打包的时候就会看这个文件中的条件。
PostCSS
PostCSS 是一个通过 JavaScript 来转换样式的工具,如:自动添加浏览器前缀、css样式的重置。需要借助 postcss 对应的插件。
PostCSS 实际的作用:
- 解析css代码,解析成抽象语法树。
- 将抽象语法树交给插件处理。
- 将插件处理之后的抽象语法树重新文本化。
1. 命令行使用postcss
安装:npm install postcss postcss-cli -D
案例:写一个添加前缀的 css
安装 autoprefixer npm install autoprefixer -D
使用postcss工具,并且指定使用autoprefixer:npx postcss --use autoprefixer -o end.css ./src/css/style.css
转换之前:
.content{
user-select: none;
}
转换之后:
.content{
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
2. 工程化项目中使用 postcss
安装: npm install postcss-loader -D
在使用 css-loader 之前使用 postcss-loader,使用 postcss-loader 的目的是在项目中能使用 postcss
const path = require('path');
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
// 必须是一个绝对路径
path: path.resolve(__dirname, "./build")
},
module: {
rules: [
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
{
loader:"postcss-loader",
options:{
postcssOptions:{
plugins:[
require('autoprefixer')
]
}
}
},
"less-loader"
]
}
]
}
}
importLoaders
为什么要有 importLoaders ?
- index.css(index.css 中引入了 test.css)
@import './test.css'
- test.css
.content{
user-select: none;
}
- webpack
const path = require('path');
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
// 必须是一个绝对路径
path: path.resolve(__dirname, "./build")
},
module: {
rules: [
{
test: /\.css$/, // 匹配资源
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
require('autoprefixer')
]
}
}
}
]
}
]
}
}
打包之后,发现没有将 css 代码加前缀。
.content{
user-select: none;
}
原因是:webpack.config.js 中的配置,匹配到 css 文件的时候用 postcss-loader 处理 index.css ,然后用 css-loader 处理 index.css,css-loader 是可以处理 @import 语法,引入了 test.css,处理 test.css。但是 postcss-loader 没有处理 test.css 中的内容。 ["style-loader","css-loader","postcss-loader"] 是不会逆序再执行的。
解决方式:需要让 postcss-loader 处理 test.css
const path = require('path');
module.exports = {
entry: "./src/index.js",
output: {
filename: "bundle.js",
// 必须是一个绝对路径
path: path.resolve(__dirname, "./build")
},
module: {
rules: [
{
test: /\.css$/, // 匹配资源
use: [
{ loader: "style-loader" },
{
loader: "css-loader",
options: {
importLoaders: 1
}
},
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
require('autoprefixer')
]
}
}
}
]
}
]
}
}
打包之后
.content{
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
提取 Css 成单独文件
Css 文件目前被打包到 js 文件中,当 js 文件加载时,会创建一个 style 标签来生成样式,这样对于网站来说,会出现闪屏现象,用户体验不好。
npm i mini-css-extract-plugin -D
- 配置
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "../dist"), // 生产模式需要输出
filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中
clean: true,
},
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"],
},
{
test: /\.s[ac]ss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
{
test: /\.styl$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "stylus-loader"],
}
],
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
}),
// 提取css成单独文件
new MiniCssExtractPlugin({
// 定义输出文件名和目录
filename: "static/css/main.css",
}),
],
mode: "production",
};
postcss 预设
上面的案例只处理了 箭头函数 ,怎么能处理更多的css语法呢?
npm i postcss-loader postcss postcss-preset-env -D
- 配置
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "../dist"), // 生产模式需要输出
filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中
clean: true,
},
module: {
rules: [
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
],
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
"less-loader",
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
}),
// 提取css成单独文件
new MiniCssExtractPlugin({
// 定义输出文件名和目录
filename: "static/css/main.css",
}),
],
mode: "production",
};
- 控制兼容性:
可以在
package.json文件中添加browserslist来控制样式的兼容性做到什么程度。
{
// 其他省略
"browserslist": ["ie >= 8"]
}
Css 压缩
npm i css-minimizer-webpack-plugin -D
- 配置
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = {
entry: "./src/main.js",
output: {
path: path.resolve(__dirname, "../dist"), // 生产模式需要输出
filename: "static/js/main.js", // 将 js 文件输出到 static/js 目录中
clean: true,
},
module: {
rules: [
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
],
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
"postcss-preset-env", // 能解决大多数样式兼容性问题
],
},
},
},
"less-loader",
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../public/index.html"),
}),
// 提取css成单独文件
new MiniCssExtractPlugin({
// 定义输出文件名和目录
filename: "static/css/main.css",
}),
// css压缩
new CssMinimizerPlugin(),
],
mode: "production",
};
附加
指定 webpack 打包入口
默认会从 src/index.js 开始打包。但是也可以修改入口文件npx webpack --entry ./src/main.js
指定 webpack 配置文件路径
"script":{
"build": "webpack --config ./wk.config.js"
}