postcss插件开发

  • 邢毅彪
  • 9 Minutes
  • 2020年12月7日

前言

postcss是一个非常强大的css处理器(说它是预处理或者后处理器都是不准确的, 就是一个类似babel之与js的存在),可以让我们前端开发者使用js语言,让css完成非常多很酷炫的操作, 甚至赋予css一定的编程能力。 而本篇博客只是一个抛砖引玉的作用, 后续有机会或者时间会再更加深入研究一下postcss。

由于公司项目组件库开发使用的rollup开发, 而遇到字体,图片等静态资源, rollup没有一个能配合scss/postcss的一个好用的插件。故自己研究了一下postcss,先埋个坑, 后续这篇博客可能会变成一个postcss专题。这里先介绍一下postcss插件开发

实现

Note: 该插件是基于postcss7开发的, postcss8改动还是蛮大的, 由于没有时间去升级整个工具链的postcss插件, 所以这个插件也是基于postcss7开发的。后续可能会考虑升级到postcss8

我的插件其实只需要实现一个功能, 就是copy scss文件里引用的静态资源到dist文件夹下, 这样不需要使用蹩脚的rollup copy插件,可以让开发和打包完成后的静态资源目录都是对的,将真正的处理交给使用组件库的项目。 由调用者选择如何处理静态资源, 组件库只需要保证组件库里的静态资源正确即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// copyUrl.js
const postcss = require('postcss');
const path = require('path');
const fs = require('fs');

const defaultOption = {
baseDir: '.',
};

module.exports = postcss.plugin('postcss-plugin-copy-url', (opts) => {
const options = Object.assign(defaultOption, opts);
const urlReg = /url\([\S\s]+\)/;
if (!fs.existsSync(options.baseDir)) {
fs.mkdirSync(options.baseDir);
}
return function copyUrl(root) {
// 遍历所有选择器
root.walkRules((rule) => {
// 遍历所有属性
rule.walkDecls((decl) => {
const { value } = decl;
if (urlReg.exec(value)) {
const file = decl.source.input.file || options.file;
const matchValue = urlReg.exec(value)[0];
const assetsUrl = matchValue.replace(/\s*/g, '').substring(5, matchValue.length - 2);
const basePath = path.dirname(file);
const realAssetUrl = path.resolve(basePath, assetsUrl);
const fileName = path.basename(assetsUrl);
const targetFile = path.resolve(options.baseDir, fileName);
const readStream = fs.createReadStream(realAssetUrl);
const writeStream = fs.createWriteStream(targetFile);
readStream.pipe(writeStream);

decl.value = `url("${fileName}")`;
}
});
});
};
});

使用

为什么postcss生态没有一个符合我要求的插件, 究其原因是因为我找到的几款插件都不能很好的和rollup scss/sass这两个插件配合。这两个插件共同特点都是不会给postcss插件传入文件, 即无法通过postcss的内部api获取到scss文件路径, 故而无法搜索到我们使用相对路径的静态资源。 我这里是结合rollup-plugin-sass 这个插件, 因为这个插件不需要我去修改源码或者很复杂的循环操作,我就能把文件路径传给postcss

1
2
3
4
5
6
7
8
9
10
11
// rollup.config.js

const copyUrl = require('./plugins/copyUrl');
// 省略一万个插件
sass({
processor: (css, id) =>
postcss([autoprefixer(), px2rem({ remUnit: 75, remPrecision: 5 }), copyUrl({ baseDir: './dist', file: id })])
.process(css)
.then((result) => result.css),
output: 'dist/bundle.css',
}),

结语

其实这个插件的开发过程, 我也对整个postcss生态做了一个大概的了解。 甚至我还买了本电子书,专门研究postcss生态及插件开发, 因为国内对这块的资料很少,埋个坑先, 后续可能会出一个升级postcss8或者一个postcss整个生态及插件开发的介绍

访问量