解析webpack下的postcss-loader

420 阅读1分钟

postcss 是 css 的 transpiler(转换编译器,简称转译器),它对于 css 就像 babel 对于 js 一样,能够做 css 代码的分析和转换。同时,它也提供了插件机制来做自定义的转换;

原理分析

postcss 是 css 到 css 的转译器,它也和 babel 一样,分为 parse、transform、generate 3个阶段。各种转换插件都是工作在 transform 阶段,基于 AST 做分析和转换。

image.png

css的AST

atrule:以 @ 开头的规则,比如:

@media ``screen and (``min-width``: ``480px``) {``    ``body {``        ``background-color``: lightgreen;``    ``}``}

rule:选择器开头的规则,比如:

ul li {``    ``padding``: ``5px``;``}

decl:具体的样式,比如:

padding``: ``5px``;

可以通过 astexplorer.net 的网站进行查找解析

image.png

postcss插件的写法(webpack工程实践)

postcss-loader可以结合css-loader使用,也可以单独使用,也就是说不配置css-loader也可以达到相同的效果。唯一不同的是,单独使用postcss-loader时,不建议使用css中的@import语句,否则会产生荣誉代码,因此官方还是推荐将postcss-loader放在css-loader之后使用

自动前缀功能(在线网站)

依赖包:postcss-loader、Autoprefixer或者PostCSS Preset Env 

简单介绍:

Autoprefixer:自动获取浏览器的流行度和能够支持的属性,并根据这些数据帮你自动为 CSS 规则添加前缀

PostCSS Preset Env:帮你将最新的 CSS 语法转换成大多数浏览器都能理解的语法

注:PostCSS Preset Env 实际预设了很多好用的css插件,完全可以替代autoprefixer使用,但是两者不同时使用,可能引发冲突

关键配置

webpack.config.js里关于css处理的配置

`loader配置`

`{`

`        ``test: /.css$/,`

`        ``use: [`

`          ``// 'style-loader',`

`          ``{`

`            ``loader: MiniCssExtractPlugin.loader,`

`            ``options: {`

`              ``publicPath: ``'./'``,`

`            ``}`

`          ``},`

`          ``'css-loader'``,`

`          ``'postcss-loader'`

`         ``]`

`}`

 

`插件配置`

`plugins: [`

`    ``new` `HtmlWebpackPlugin({`

`      ``template: ``'index.html'``,`

`    ``}),`

`    ``new` `MiniCssExtractPlugin({`

`      ``// 这里的配置和webpackOptions.output中的配置相似`

`      ``// 即可以通过在名字前加路径,来决定打包后的文件存在的路径`

`      ``filename: ``'css/[name].css'``,`

`    ``})`

`  ``],`

postcss.config.js(当webpack配置里加入postcss-loader)

`const` `autoprefixer = require(``'autoprefixer'``);`

`const` `preset = require(``"postcss-preset-env"``);`

 

`module.exports = {`

`    ``plugins: [`

`        ``autoprefixer,`

`        ``// preset`

`    ``]`

`  ``};`

.browserlistrc浏览器兼容范围配置(浏览器兼容谁还写last 2 version)  浏览器兼容详细介绍

`last ``100` `version`

启动webpack工程看下效果

未开启postcss

`div {`

`    ``background: linear-gradient(to bottom, white, skyblue)`

`}`

`div{`

`    ``background: #eff0f0;`

`    ``padding: 1rem;`

`    ``border-radius: 8px;`

`    ``user-select: none;`

`    ``transform: rotate(0deg);`

`  ``}`

开启postcss

`div{`

`    ``background: #eff0f0;`

`    ``padding: 1rem;`

`    ``-webkit-border-radius: 8px;`

`            ``border-radius: 8px;`

`    ``-webkit-user-select: none;`

`       ``-moz-user-select: none;`

`        ``-ms-user-select: none;`

`            ``user-select: none;`

`    ``-webkit-transform: rotate(0deg);`

`        ``-ms-transform: rotate(0deg);`

`         ``-o-transform: rotate(0deg);`

`            ``transform: rotate(0deg);`

`  ``}`

`  ` 

 

`div {`

`    ``background: -webkit-gradient(linear, left top, left bottom, from(white), to(skyblue));`

`    ``background: -webkit-linear-gradient(top, white, skyblue);`

`    ``background: -o-linear-gradient(top, white, skyblue);`

`    ``background: linear-gradient(to bottom, white, skyblue)`

`}`

自定义变量postcss-simple-vars

可以在css里写变量名,会通过postcss-aimple-var,将里面的变量替换成对应变量,包括

配置项如下

`const` `vars = require(``'postcss-simple-vars'``);`

 

 

`module.exports = {`

`    ``plugins: [`

`        ``vars({`

`            ``silent: ``true``,``//postcss-simple会自带检测是否有未知变量,有的话,会报错,这里设置成true,就是不管有没有未知变量了`

`            ``variables: {`

`                ``$kevin: ``'18px'`

`            ``}`

`        ``})`

`    ``]`

`  ``};`

写一个css

`/* $kevin测试 */`

`div {`

`    ``font-size: 13px;`

`    ``font-size: $kevin;`

`    ``--$(kevin): $kevin;`

`}`

 

`$kevin { }`

`$(kevin)_button { }`

在postcss.config.js里,我们将$kevin设置成'18px'

展示到页面上就是

image.png

postcss-cssnext

介绍:

可以将自定义的css变量自动转化成常量,自带前缀功能,会和autoprefixer冲突

postcss.config配置项

`const nextcss = require(``"postcss-cssnext"``);`

 

 

`module.exports = {`

`    ``plugins: [`

`        ``nextcss`

`    ``]`

`  ``};`

开启前

`:root {`

`    ``--``color``: ``red``;`

`}`

 

`div {`

`    ``color``: var(--color);`

`}`

开启后

image.png

对于比较大的工程来说感觉有点鸡肋

如果在非:root下使用自定义变量,比如body,会出现报错

image.png

原因是默认不让你在其他dom元素里使用自定义变量的,但是控制台没报错,而且去掉这个警告图层,渲染还是正常的

说明我们的工程其实是跑起来了,去掉警告就好了

`const nextcss = require(``"postcss-cssnext"``);`

`module.exports = {`

`    ``plugins: [`

`        ``nextcss({`

`            ``features: {`

`                ``customProperties: {`

`                    ``warnings: false`

`                ``}`

`            ``}`

`        ``})`

`    ``]`

`  ``};`

这样就解决问题了,但是还是觉得仍然鸡肋

个人看法:

缺点:

1.css变量最大的特点,就是灵活性,这样写,相当于直接把css值写死了,那不如直接写死

2.只对:root下的变量生效,如果像移动端组件里,每个组件会修改自定义变量,会导致失效,因为底层的自定义变量值已经被替换成固定值了

优点

1.这样写,可以把需要经常修改的变量,集中到一起,在修改的时候,不需要去翻箱倒柜的找每一个变量

对比框架适用(比较偏的框架,可跳过):

antdfinedesignfineui
antdfd(公司内部框架)fineui(公司内部框架)
image.pngimage.pngimage.png
自定义变量基本上不在:root上定义,都定义在父类或者自身,不适配自定义变量基本上都定义在:root上,但是fd就是想通过修改自定义变量,来修改主题色,因此不适配fineui用的是less变量,写的是类样式,元素只需要添加对应的样式类名即可,用postcss是可以的

课外延伸:

问:为什么antd的类名看起来像是随机类名

答:可以通过css-loader配置项来实现

css modules是近年来比较流行的一种开发模式,其理念就是把css模块化,让css也拥有模块的特点,具体如下:

每个css文件中的样式都拥有单独的作用域,不会和外界发生命名冲突

对css进行依赖管理,可以通过相对路径引入css文件

使用css modules不需要额外安装模块,只要开启css-loader的modules配置项即可

`{`

`      ``loader: ``'css-loader'``,`

`      ``options: {`

`           ``// modules: true,`

`           ``modules: {`

`             ``localIdentName: ``'[name]_[local]_[hash:base64:5]_[path]'``,``//name指的是模块名,local指的选择器标识符,hash:base64:5指的是5位数的hash值`

`           ``}`

`         ``}`

`},`

test.css

`.kevin {`

`    ``font-family: Verdana, Geneva, Tahoma, sans-serif;`

`}`

index.js

`import styles from ``'./css_module/test.css'`

 

`!(``function``($) {`

`  ``$(``'.test'``).addClass(styles.kevin);`

`}(jQuery))`

实际效果

image.png