携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
直接根据上篇的案例继续编写,不要每次都新建一个demo了,上篇-> 掘金课程《Webpack5 核心原理与应用实践》学习笔记
如何借助预处理器、PostCSS 等构建现代 CSS 工程环境?
1. webpack 如何处理 css 资源?
原生
webpack并不认识css,如果直接在.js文件中直接引入.css文件,会导致编译失败。
src下面新建一个index.css文件,里面随便写点代码。
// index.css
body {
background: pink;
}
index.js文件里面引入index.css
// index.js
import './index.css'
const list = [1, 2, 3, 4, 5, 6, 7, 8, 9];
list.map(item => item)
虽然上节配置好了
ts的环境,但是以后的课程如果没有一定指定ts就还是使用.js,这里只是学习webpack,ts准备这节完成再继续专精
- 命令行:
npx webpack,可以看到会编译失败
2. webpack处理css的loader
webpack处理css的loader通常会用到如下:css-loader:该 Loader 会将 CSS 等价翻译为形如module.exports = "${css}"的JavaScript 代码,使得 Webpack 能够如同处理 JS 代码一样解析 CSS 内容与资源依赖;style-loader:该 Loader 将在产物中注入一系列 runtime 代码,这些代码会将 CSS 内容注入到页面的<style>标签,使得样式生效;mini-css-extract-plugin:该插件会将 CSS 代码抽离到单独的.css文件,并将文件通过<link>标签方式插入到页面中。
当 Webpack 版本低于 5.0 时,请使用
extract-text-webpack-plugin代替mini-css-extract-plugin。
3. 配置webpack
-
安装依赖
- 命令行:
npm i -D css-loader style-loader webpack.config.js添加配置
const path = require('path'); const EslintPlugin = require('eslint-webpack-plugin'); module.exports = { mode: 'development', entry: { index: './src/index.js', test: './src/test.ts' }, output: { filename: '[name].js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /.js$/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env', '@babel/preset-typescript'] } } }, { test: /.ts$/, use: { loader: 'ts-loader' } }, // 处理css的loader { test: /.css$/, use: ['style-loader', 'css-loader'] // 这里css-loader需要写到后面 } ] }, resolve: { extensions: ['.ts', '.js'], }, plugins: [ new EslintPlugin({ extensions: ['.ts', '.js'] }) ] }这里先用只有
css-loader和style-loader,loader的加载顺序是从后往前,后面一个处理完成之后,会把结果抛给前面的loader再进行下一步的处理。
css-loader只会把css放到.js文件中,不会对样式产生作用,所以需要style-loader进行下一步处理。
style-loader会把css拿出来,然后创建<style>标签,并插入到<head>中。- 命令行:
npx webpack - 这里编译成功后,可以看到没有
.css结尾的文件,因为css生成在.js文件中了,感兴趣可以找找看。
- 命令行:
生产环境
上面将
css放到.js文件中,无疑是会增加包的体积,这样会产生很多问题。
css、js并存,无法并行加载,只是在js线程中加载。包体积变大,影响加载时间(可以分包解决)。
css、js随便一者发生修改,就会丢失浏览器缓存能力。说白了就是影响首屏加载时间。
所以在生产环境中使用mini-css-extract-plugin代替style-loader。
- 安装
mini-css-extract-plugin- 命令行:
npm i -D mini-css-extract-plugin html-webpack-plugin
mini-css-extract-plugin需要搭配html-webpack-plugin来使用,所以这里需要安装两个。- 配置
webpack.config.js
const path = require('path'); const EslintPlugin = require('eslint-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 引入mini-css-extract-plugin const HTMLWebpackPlugin = require('html-webpack-plugin'); // 引入html-webpack-plugin module.exports = { mode: 'development', entry: { index: './src/index.js', test: './src/test.ts' }, output: { filename: '[name].js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /.js$/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env', '@babel/preset-typescript'] } } }, { test: /.ts$/, use: { loader: 'ts-loader' } }, { test: /.css$/, use: [ (process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader) // 根据运行环境判断使用哪个loader , 'css-loader' ] } ] }, resolve: { extensions: ['.ts', '.js'], }, plugins: [ new EslintPlugin({ extensions: ['.ts', '.js'] }), new MiniCssExtractPlugin(), // 使用MiniCssExtractPlugin new HTMLWebpackPlugin() // 使用HTMLWebpackPlugin ] }mini-css-extract-plugin库同时提供 Loader、Plugin 组件,需要同时使用mini-css-extract-plugin不能与style-loader混用,否则报错,所以上述示例中需要判断process.env.NODE_ENV环境变量决定使用那个 Loadermini-css-extract-plugin需要与html-webpack-plugin同时使用,才能将产物路径以link标签方式插入到 html 中
- 命令行:
npx webpack - 会生成对应的
.html、.css、.js文件 - 可以打开
.html文件看看内容,同时也可以运行一下.html看看样式是否生效,js文件是否正常加载。
- 命令行:
css预处理器
css发展这么多年,性能,功能什么的已经突飞猛进,但是对于循环、分支判断、扩展复用、函数、嵌套之类的特性还是缺失的,以至于原生 CSS 已经难以应对当代复杂 Web 应用的开发需求。
于是社区就产出了功能更强大的 CSS 预处理器,,比较知名的有Less、Sass、Stylus。
这些工具各有侧重,但都在 CSS 之上补充了扩展了一些逻辑判断、数学运算、嵌套封装等特性,基于这些特性,我们能写出复用性、可读性、可维护性更强,条理与结构更清晰的样式代码。
本节主要讲Less
- 安装依赖
- 命令行:
npm i -D less less-loader - 配置
webpack.config.js
const path = require('path'); const EslintPlugin = require('eslint-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const HTMLWebpackPlugin = require('html-webpack-plugin'); module.exports = { mode: 'development', entry: { index: './src/index.js', test: './src/test.ts' }, output: { filename: '[name].js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ // 省掉了之前的配置,less只需要下面的配置就可以了 { test: /.less$/, use: [ 'style-loader', 'css-loader', 'less-loader' ] } ] }, resolve: { extensions: ['.ts', '.js'], }, plugins: [ new EslintPlugin({ extensions: ['.ts', '.js'] }), new MiniCssExtractPlugin(), new HTMLWebpackPlugin() ] }- 创建
.less文件
// 变量 @size: 12px; @color: #006633; // 混合 .mx-bordered() { border: 1px solid #000; } // 嵌套 body { // 函数计算 background: spin(lighten(@color, 25%), 8); font-weight: bold; padding: @size; .main { // 数学运算 font-size: @size * 2; .mx-bordered; color: darken(@color, 10%); padding: @size * 0.6; } }index.js引入.less文件
import './index.css' import './index.less' const list = [1, 2, 3, 4, 5, 6, 7, 8, 9]; list.map(item => item)- 编译,命令行输入:
npx webpack - 运行生成后的
index.html文件查看效果
- 命令行:
除了less,其他的两种接入的方式也很简单
Sass:npm i -D sass-loader
Stylus:npm i -D stylus-loader
webpack.config.js配置也很一样,就是把less换成对应的名字就好了。
使用 post-css
post-css是什么?
post-css就会说css版的babel,不同的是babel会改造或者创建js语法为兼容低版本的js语法,post-css就是增加兼容性前缀。
-
使用
post-css- 安装依赖
- 命令行:
npm i -D postcss postcss-loader autoprefixer - 配置
webpack.config.js
const path = require('path'); const EslintPlugin = require('eslint-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const HTMLWebpackPlugin = require('html-webpack-plugin'); module.exports = { mode: 'development', entry: { index: './src/index.js', test: './src/test.ts' }, output: { filename: '[name].js', path: path.resolve(__dirname, 'dist') }, module: { rules: [ { test: /.css$/, use: [ (process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader), { loader: "css-loader", options: { importLoaders: 1 // 主要是用来处理@import引入的css,如果不加这个,@import引入的css不会被postcss-loader处理 } }, { loader: "postcss-loader", options: { postcssOptions: { // 添加 autoprefixer 插件 plugins: [require("autoprefixer")], }, }, } ] }, ] }, resolve: { extensions: ['.ts', '.js'], }, plugins: [ new EslintPlugin({ extensions: ['.ts', '.js'] }), new MiniCssExtractPlugin(), new HTMLWebpackPlugin() ] }- 完了之后在
.css文件中写点新颖的css,例如伪类::placeholder - 然后
npx webpack - 然后就可以查看生成的
.css文件的内容了
-
post-css的配置可以单独抽离出来处理- 创建
postcss.config.js,内容如下:
module.exports = { plugins: [ require("autoprefixer") ], };- 然后
webpack.config.js就可以下面这样了
// 省略其他的配置 module.exports = { module: { rules: [ { test: /.css$/, use: [ (process.env.NODE_ENV === 'development' ? 'style-loader' : MiniCssExtractPlugin.loader), { loader: "css-loader", options: { importLoaders: 1 } }, 'postcss-loader', // 可以不加配置属性,简写了 ] }, { test: /.less$/, use: [ 'style-loader', { loader: "css-loader", options: { importLoaders: 1 } }, 'postcss-loader', // 和预处理器是兼容的,但是需要预处理器处理完了之后再给它处理哟,不要弄错顺序了 'less-loader', ] } ] }, } - 创建
总结
总结都是课程里面的,自己的总结就是配置好了,可以使用了,后面默认都知道我的总结了
本文介绍 css-loader、style-loader、mini-css-extract-plugin、less-loader、postcss-loader 等组件的功能特点与接入方法,内容有点多,重点在于:
- Webpack 不能理解 CSS 代码,所以需要使用
css-loader、style-loader、mini-css-extract-plugin三种组件处理样式资源; - Less/Sass/Stylus/PostCSS 等工具可弥补原生 CSS 语言层面的诸多功能缺失,例如数值运算、嵌套、代码复用等。
这些工具几乎已经成为现代 Web 应用开发的标配,能够帮助我们写出更清晰简洁、可复用的样式代码,帮助我们解决诸多与样式有关的工程化问题。