书接上回 tailwindcss 小程序定制化之旅
我们知道 uni-app
和 tarojs
在最终打包成小程序运行的时候,都是使用的 webpack
,所以在这 2 个框架中,我们可以使用 *-loader
轻而易举的赋予它们这方面的能力。
但是,假如我们使用的是原生开发呢?
使用微信开发工具的小伙伴们,肯定注意到,在 项目详情
-> 本地设置
中,
有上传代码时 样式自动补全
,自动压缩样式
, 自动压缩混淆
等等选项。
它们的本质,不过是几个插件罢了:
样式自动补全
-> autoprefixer
自动压缩样式
-> cssnano
自动压缩混淆
-> uglify-js
/terser
所以我们完全可以自定义,以获得更强更自由的能力。
我们知道 在 webpack
里 sass-loader
, postcss-loader
,babel-loader
这类,只是编译核心们和 webpack
做粘合的胶水代码。
在不使用 webpack
gulp
rollup
... 这类的打包工具的情况下,我们当然可以去自定义一个最小化的样式编译工具。
首先,直接安装 dart-sass
, 和 postcss
yarn add -D sass postcss
安装后,可以看到,sass
渲染函数签名
// sass函数签名
export function render(options: Options, callback: (exception: SassException, result: Result) => void): void;
export function renderSync(options: Options): Result;
然后我们又知道 webpack
的 loader
选择了 compose
方式的执行方式。
函数式编程中,
compose
从右到左执行,pipe
从左到右执行
于是我们知道了执行顺序,那么就可以确定 *.scss
文件,先交给 sass
处理,再交由 postcss
处理,然后就直接打成 xxpage.wxss
这类 局部页面样式 , 又或者打成 app.wxss
作为全局样式。
那么写代码实现就是探囊取物了:
// 不考虑 preset merge的情况下
const sass = require('sass')
const postcss = require('postcss')
const { plugins } = require('./postcss.config.js')
function handleScss (path) {
sass.render({
file: path,
// fiber: Fiber
}, (err, result) => {
if (err) {
console.error(err)
}
const destPath = path.replace(/\.scss$/, '.wxss')
postcss(plugins).process(result.css, {
from: path,
to: destPath
}).then(result => {
fs.writeFile(destPath, result.css, () => true)
if (result.map) {
fs.writeFile(destPath + '.map', result.map.toString(), () => true)
}
})
})
}
上面这段代码就是 scss
-> postcss
-> wxss
的转化链路
而且还可以在里面,随意的装 postcss plugin
, 比如 autoprefixer
, cssnano
, tailwindcss
之前笔者写的 tailwindcss-miniprogram-preset
也可以无缝的嵌入这套机制中去,给原生小程序使用。
我们开发的时候,会经常去创建,修改,删除文件,这么获取到这些 timing
对文件进行重新编译呢?
fs.watch
,fs.watchFile
固然可以,不过更推荐的还是 chokidar
yarn add -D chokidar
在 chokidar
的 README.md
中详细介绍了它的优势,这里不再叙述。
const watcher = chokidar.watch(`${someGlob}`, {
ignored: /(^|[\/\\])\../,
persistent: true
})
// EventEmitter 的写法,把监控安排的明明白白
watcher
.on('add', (path,stats) => {
// 添加文件
})
.on('change', (path,stats) => {
// 修改文件
})
.on('unlink', (path,stats) => {
// 删除文件
})
.on('error', error => {
// 发生错误
})
.on('ready', () => {
// watch ready after add files
})
通过 watcher
的持续性监控,我们可以很容易得出结论,我们需要在 *.scss
文件变动的时候,重新编译,
即 add
,change
的时间点,在 unlink
的时间点,也要同时 unlink
对应的 *.wxss
文件。
假如
purgecss
开启,则需要在wxml
文件发生变更时,通知重新编译app.scss
和文件对应的page.scss
, 一般开发时不开启此工具。
前面这一套机制,搭建完成后
在 app.scss
里加一行 @tailwind utilities;
就可以顺利使用 tailwindcss
了
但是我们需要我们的编辑器根据 tailwindcss
配置,自动生成 class 的智能提示怎么做呢?
这里我们以 vscode
为例:
安装 WXML - Language Services 插件
(一搜 wxml 下载量最多的就是了)
接着找到 Tailwind CSS IntelliSense
的 扩展设置
在 include languages
, 手动标记 wxml
的类型为 html
智能提示就出来了:
是不是非常方便,同时也能大大提升开发效率。
其实这篇文章,拆开了 webpack
的部分黑盒, 探讨了场景定制化的代码加工生产线,以期来帮助开发者提升效率。
typescript
+ @babel/core
+ rollup
这种处理js
的组合也见过。
只要能提升开发者生产效率,提升开发体验,提升可维护性的工具还是值得一做的。