>[success] # 配置css模块解析
1. css 是在实际开发中最常见的模块,在解析时候需要配置其对应 loader 才能成功打包,一般常见的配置 css loader 如下
* `css-loader` 用于**加载.css 文件**,并且转化成**commonjs对象**,安装`npm install css-loader -D`
* `style-loader` 将样式通过`<style>` 标签插入到**head中**,安装`npm install style-loader -D`
* `less-loader` 将用于**less 转换成css**,安装`npm install less-loader -D`
* `postcss-loader`,一套将 CSS 源码解析为 AST 结构,并传入 PostCSS 插件做处理的流程框架,具体功能都由插件实现,因此可以安装`autoprefixer` 插件(用来告诉PostCSS 那些css用来加浏览器前缀,解析CSS并使用'**[Can I Use 网站](https://caniuse.com/)**'中的值向CSS规则添加供应商前缀,[CSS属性前缀的作用是什么](https://m.html.cn/qa/css3/16979.html)),安装`npm install postcss postcss-loader autoprefixer -D`,更多配合使用插件
* [`mini-css-extract-plugin`](https://link.juejin.cn/?target=https%3A%2F%2Fwebpack.js.org%2Fplugins%2Fmini-css-extract-plugin "https://webpack.js.org/plugins/mini-css-extract-plugin"):该插件会将 CSS 代码抽离到单独的`.css`文件,并将文件通过`<link>`标签方式插入到页面中,安装`npm install --save-dev mini-css-extract-plugin`
>[info] ## 使用
1. 如果单独使用`css-loader` 会发现执行完后对应css 样式并没有生效,因为 `css-loader` 的作用是将 **CSS 模块转换为一个 JS 模块**,具体的实现方法是将 **CSS 代码 push 到一个数组中,这个数组是由 css-loader 内部的一个模块提供的,但是整个过程并没有任何地方使用** 正是因为 **css-loader 只会把 CSS 模块加载到 JS 代码中,而并不会使用这个模块** 因此不生效
![](https://img.kancloud.cn/ba/50/ba500238f0e2506da041ee6a719b231f_1311x451.png)
![](https://img.kancloud.cn/6f/47/6f4783e47d831c430a6455032036d817_1159x375.png)
2. `style-loader`,style-loader的作用是在js执行时,动态的创建style标签,然后将 **css-loader 转换的样式插入到这个style标签里去的**
![](https://img.kancloud.cn/68/ce/68ce3b8e4f5e2ad54ae134b6f998be35_391x210.png)
3. 使用 `postcss-loader` 需要配置插件来达到css一些特殊配置
* [autoprefixer](https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fpostcss%2Fautoprefixer "https://github.com/postcss/autoprefixer"):基于[Can I Use](https://link.juejin.cn/?target=https%3A%2F%2Fcaniuse.com%2F "https://caniuse.com/")网站上的数据,自动添加浏览器前缀
* [postcss-preset-env](https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fjonathantneal%2Fpostcss-preset-env "https://github.com/jonathantneal/postcss-preset-env"):一款将最新 CSS 语言特性转译为兼容性更佳的低版本代码的插件
* [postcss-less](https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fshellscape%2Fpostcss-less "https://github.com/shellscape/postcss-less"):兼容 Less 语法的 PostCSS 插件,类似的还有:[postcss-sass](https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2FAleshaOleg%2Fpostcss-sass "https://github.com/AleshaOleg/postcss-sass")、[poststylus](https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fmadeleineostoja%2Fpoststylus "https://github.com/madeleineostoja/poststylus")
* [stylelint](https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fstylelint%2Fstylelint "https://github.com/stylelint/stylelint"):一个现代 CSS 代码风格检查器,能够帮助识别样式代码中的异常或风格问题
>[danger] ##### 使用配置
![](https://img.kancloud.cn/ed/fa/edfac40da471bf7d5c161178579ca642_539x431.png)
~~~
/** @type {import('webpack').Configuration} */
const config = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: ['autoprefixer'],
},
},
},
],
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader',
'postcss-loader',
],
},
],
},
}
module.exports = config
~~~
* 关于`postcss-loader` 的 `options` 可以通过配置`postcss.config.js`,来指定用`autoprefixer`
~~~
// postcss.config.js
module.exports = {
plugins: ['autoprefixer'],
}
~~~
~~~
/** @type {import('webpack').Configuration} */
const config = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader',
'postcss-loader',
],
},
],
},
}
module.exports = config
~~~
* 有时候并不是所有浏览器都需要配置 `.browserslistrc` 文件来执行需要通过`postcss`和其插件具体要适配的浏览器(Browserslist这个东西单独是没用的,browserslist字段会被 @babel/preset-env 和 Autoprefixer 用来确定需要转译的 JavaScript 特性和需要添加的 CSS 浏览器前缀)
~~~
last 2 version
>1%
~~~
* 直接使用 `postcss-preset-env`,它可以帮助我们将一些现代的CSS特性,转成大多数浏览器认识的CSS,并且会根据目标浏览器或者运行时环境添加所需的`polyfill`,也包括会自动帮助我们添加autoprefixer(所以相当于已经**内置了autoprefixer**)安装`npm install postcss-preset-env -D`,直接在`postcss.config.js` 文件使用
~~~
// postcss.config.js
module.exports = {
plugins: ['postcss-preset-env'],
}
~~~
>[info] ## 将css 文件抽离
1. 当 Webpack 版本低于 5.0 时,请使用[`extract-text-webpack-plugin`]
(https://link.juejin.cn/?target=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Fextract-text-webpack-plugin "https://www.npmjs.com/package/extract-text-webpack-plugin")代替`mini-css-extract-plugin`。
2. `mini-css-extract-plugin` 不能与 style-loader 混用,否则报错,所以需要判断 `process.env.NODE_ENV` 环境变量决定使用那个 Loader
~~~
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HTMLWebpackPlugin = require('html-webpack-plugin')
module.exports = {
module: {
rules: [{
test: /\.css$/,
use: [
// 根据运行环境判断使用那个 loader
(process.env.NODE_ENV === 'development' ?
'style-loader' :
MiniCssExtractPlugin.loader),
'css-loader'
]
}]
},
plugins: [
new MiniCssExtractPlugin(),
new HTMLWebpackPlugin()
]
}
~~~
>[danger] ##### 执行顺序
1. `postcss-loader` 执行顺序必须保证在 `css-loader` 之前,建议还是放在` less`或者 `sass `等预处理器之后更好。即 `loader `顺序:**less-loader -> postcss-loader -> css-loader -> style-loader 或者 MiniCssExtractPlugin.loader**
其实 postcss-loader 放在 less-loader 之前问题也不大,平时使用的 less 里面的语法基本不会和 autoprefixer 处理产生冲突的。
>[danger] ##### postcss-loader中的options怎么还会有个plugins
1. 这个是通过loader的options传递postcss所需要用到的插件,这个插件是postcss生态下的。和webpack插件没有关联
>[danger] ##### 为什么css 要向js 一样动态引入
1. **在JS中通过import方式引入CSS文件根据代码的,好处不像以前的代码,我们将所有的css 文件都沉积在业务里**,很多情况都是触发了某个js代码,然后从而需要某种资源,如果业务开发后续阶段删除了某个js业务逻辑,**而没有清空他的对应css代码就会产生资源浪费**,现在通过webpack 将他们关联到一起,也方便管理
* 举一个代码案例
~~~
// 注意这里是因为用了webpack 和css -- loader,才可以将css作为模块导入
// 这样导入后的效果就是只有当触发了下面的js 情况才会引入一个css文件
import './heading.css'
export default () => {
const element = document.createElement('h2')
element.textContent = 'Hello world'
element.classList.add('heading')
element.addEventListener('click', () => {
alert('Hello webpack')
})
return element
}
~~~
>[danger] ##### 补充
常见主流浏览器内核
* **Trident内核**: 主要代表为IE浏览器 -'ms'
* **Gecko内核**: 主要代表为Firefox -'moz'
* **Presto内核**': 主要代表为Opera -'o'
* **Webkit内核**: 产要代表为Chrome和Safari - 'webkit'
>[danger] ##### 总结
1. `css-loader`提供了很多处理 CSS 代码的基础能力,包括 CSS 到 JS 转译、依赖解析、Sourcemap、css-in-module 等,基于这些能力,Webpack 才能像处理 JS 模块一样处理 CSS 模块代码,经过`css-loader`处理后,样式代码最终会被转译成一段 JS 字符串,**只是被当作普通 JS 模块处理,并不会实际影响到页面样式**
* **开发环境**:使用`style-loader`将样式代码注入到页面`<style>`标签;
* **生产环境**:使用`mini-css-extract-plugin`将样式代码抽离到单独产物文件,并以`<link>`标签方式引入到页面中。
![](https://img.kancloud.cn/58/60/586039df00a792fe55e392395ec43851_696x496.png)
2. `style-loader`并不会对代码内容做任何修改,而是简单注入一系列运行时代码,用于将`css-loader`转译出的 JS 字符串插入到页面的`style`标签,由于通过`style`标签注入到页面。这种将 JS、CSS 代码合并进同一个产物文件的方式有几个问题:
* JS、CSS 资源无法并行加载,从而降低页面性能;
* 资源缓存粒度变大,JS、CSS 任意一种变更都会致使缓存失效。
![](https://img.kancloud.cn/c6/93/c693ead2466c28e6150ff5cbc77867eb_563x185.png)
3. 因此生产环境中通常会用[`mini-css-extract-plugin`](https://link.juejin.cn/?target=https%3A%2F%2Fwebpack.js.org%2Fplugins%2Fmini-css-extract-plugin "https://webpack.js.org/plugins/mini-css-extract-plugin")插件替代`style-loader`,抽离成单独的 CSS 文件
* `mini-css-extract-plugin`库同时提供 Loader、Plugin 组件,需要同时使用
* `mini-css-extract-plugin`不能与`style-loader`混用,否则报错,所以需要判断`process.env.NODE_ENV`环境变量决定使用那个 Loader
* `mini-css-extract-plugin`需要与`html-webpack-plugin`同时使用,才能将产物路径以`link`标签方式插入到 html 中
>[info] ## 参考
[Webpack5 核心原理与应用实践](https://juejin.cn/book/7115598540721618944)
[webpack4 css 提取插件 mini-css-extract-plugin,当想提取出css 样式文件时候](http://www.tensweets.com/article/5c8cad80362e5434baf6335d)
[style-loader](http://www.fly63.com/article/detial/5741)
[前端工程化精讲](https://kaiwu.lagou.com/course/courseInfo.htm?courseId=416&sid=20-h5Url-0#/detail/pc?id=4419)
[链接](https://github.com/fe-efficiency/lessons_fe_efficiency/blob/master/05_coding_efficiency/webpack.config.js)
- 工程化 -- Node
- vscode -- 插件
- vscode -- 代码片段
- 前端学会调试
- 谷歌浏览器调试技巧
- 权限验证
- 包管理工具 -- npm
- 常见的 npm ci 指令
- npm -- npm install安装包
- npm -- package.json
- npm -- 查看包版本信息
- npm - package-lock.json
- npm -- node_modules 层级
- npm -- 依赖包规则
- npm -- install 安装流程
- npx
- npm -- 发布自己的包
- 包管理工具 -- pnpm
- 模拟数据 -- Mock
- 页面渲染
- 渲染分析
- core.js && babel
- core.js -- 到底是什么
- 编译器那些术语
- 词法解析 -- tokenize
- 语法解析 -- ast
- 遍历节点 -- traverser
- 转换阶段、生成阶段略
- babel
- babel -- 初步上手之了解
- babel -- 初步上手之各种配置(preset-env)
- babel -- 初步上手之各种配置@babel/helpers
- babel -- 初步上手之各种配置@babel/runtime
- babel -- 初步上手之各种配置@babel/plugin-transform-runtime
- babel -- 初步上手之各种配置(babel-polyfills )(未来)
- babel -- 初步上手之各种配置 polyfill-service
- babel -- 初步上手之各种配置(@babel/polyfill )(过去式)
- babel -- 总结
- 各种工具
- 前端 -- 工程化
- 了解 -- Yeoman
- 使用 -- Yeoman
- 了解 -- Plop
- node cli -- 开发自己的脚手架工具
- 自动化构建工具
- Gulp
- 模块化打包工具为什么出现
- 模块化打包工具(新) -- webpack
- 简单使用 -- webpack
- 了解配置 -- webpack.config.js
- webpack -- loader 浅解
- loader -- 配置css模块解析
- loader -- 图片和字体(4.x)
- loader -- 图片和字体(5.x)
- loader -- 图片优化loader
- loader -- 配置解析js/ts
- webpack -- plugins 浅解
- eslit
- plugins -- CleanWebpackPlugin(4.x)
- plugins -- CleanWebpackPlugin(5.x)
- plugin -- HtmlWebpackPlugin
- plugin -- DefinePlugin 注入全局成员
- webapck -- 模块解析配置
- webpack -- 文件指纹了解
- webpack -- 开发环境运行构建
- webpack -- 项目环境划分
- 模块化打包工具 -- webpack
- webpack -- 打包文件是个啥
- webpack -- 基础配置项用法
- webpack4.x系列学习
- webpack -- 常见loader加载器
- webpack -- 移动端px转rem处理
- 开发一个自己loader
- webpack -- plugin插件
- webpack -- 文件指纹
- webpack -- 压缩css和html构建
- webpack -- 清里构建包
- webpack -- 复制静态文件
- webpack -- 自定义插件
- wepack -- 关于静态资源内联
- webpack -- source map 对照包
- webpack -- 环境划分构建
- webpack -- 项目构建控制台输出
- webpack -- 项目分析
- webpack -- 编译提速优护体积
- 提速 -- 编译阶段
- webpack -- 项目优化
- webpack -- DefinePlugin 注入全局成员
- webpack -- 代码分割
- webpack -- 页面资源提取
- webpack -- import按需引入
- webpack -- 摇树
- webpack -- 多页面打包
- webpack -- eslint
- webpack -- srr打包后续看
- webpack -- 构建一个自己的配置后续看
- webpack -- 打包组件和基础库
- webpack -- 源码
- webpack -- 启动都做了什么
- webpack -- cli做了什么
- webpack - 5
- 模块化打包工具 -- Rollup
- 工程化搭建代码规范
- 规范化标准--Eslint
- eslint -- 扩展配置
- eslint -- 指令
- eslint -- vscode
- eslint -- 原理
- Prettier -- 格式化代码工具
- EditorConfig -- 编辑器编码风格
- 检查提交代码是否符合检查配置
- 整体流程总结
- 微前端
- single-spa
- 简单上手 -- single-spa
- 快速理解systemjs
- single-sap 不使用systemjs
- monorepo -- 工程
- Vue -- 响应式了解
- Vue2.x -- 源码分析
- 发布订阅和观察者模式
- 简单 -- 了解响应式模型(一)
- 简单 -- 了解响应式模型(二)
- 简单 --了解虚拟DOM(一)
- 简单 --了解虚拟DOM(二)
- 简单 --了解diff算法
- 简单 --了解nextick
- Snabbdom -- 理解虚拟dom和diff算法
- Snabbdom -- h函数
- Snabbdom - Vnode 函数
- Snabbdom -- init 函数
- Snabbdom -- patch 函数
- 手写 -- 虚拟dom渲染
- Vue -- minVue
- vue3.x -- 源码分析
- 分析 -- reactivity
- 好文
- grpc -- 浏览器使用gRPC
- grcp-web -- 案例
- 待续