【原子样式实践】第5篇 为微信小程序生成原子样式

时间:2022-10-17 18:03:15

原子样式的web实现有很多,tailwind, windy, unocss 等。原子样式使用最麻烦的地方是在动态生成上,而这与工程类型、IDE皆有关系。如果原子样式项目是集成到某个项目的,事情就会变得更加复杂,实现进度和完成度都会滞后。而这,与原子样式本身的简洁特点是不符合的。


1 类似工具支持情况

1.1 快速使用

到目前为止,还没有特别适合微信原生小程序的原子样式生成工具。我们可以从现有工具的特点吸收优点进行改进。

(1) windicss ,在 CLI 模式下,一行命令安装,一行命令生成代码。

npm i -g windicss
windicss './**/*.wxml' -to windi.css

CLI 模式下使用已经是极简。其他模式下配置也不复杂。

但生成的结果不理想,没有针对微信小程序优化,编译器报告 wxss 编译错误。

(2)unocss 通过 CLI 方式在 windows powershell 下运行失败,适配还没有完全做好。


1.2 问题分析

当然,主要原因是微信内置的浏览器不是标准的WEB浏览器,各工具没有完全适配。这一点会随着标准的公开和时间的推进而越来越好。

就小程序而言,要快而小,样式无需太复杂,在手机上是全屏运行,场景更加简单。微信小程序的原子样式工具应该更加简单。


2 工具研发

2.1 特定需求

(1)​​app.wxss​​ 为全局样式,默认启用。

(2)页面根元素使用 ​​page​​​,而不是 ​​body​​。

(3)页面样式属性对应 ​​class ​​​和​​ hover-class​​​ 和  ​​placeholder-class​​。


2.2 建设思路

基于上一篇通过样式生成css代码的函数,生成微信小程序所需的样式代码,只需要从样式文件中提取样式名称即可。

提取样式只需解析 wxml 文件,从匹配的样式属性中提取样式名称,去重即可。


2.3 技术实现

本地文件 wxmp-atomic-css-generate.ts

import {htmltok, TokenType} from 'https://deno.land/x/htmltok@v0.0.3/mod.ts';

const RootDir = "./miniprogram"
const ConfigFileName = `${RootDir}/app.json`

interface CountMap {
[index: string]: number
}

const fullPagePath = (page: string): string => `${RootDir}/${page}.wxml`

const isClassAttr = (attrName: string): boolean => attrName == "class" || attrName == "hover-class" || attrName == "placeholder-class"

const readWxmpPages = (app: any): string[] => [...app.pages, ...app.subpackages.map((pkg: any) => pkg.pages.map((page: string) => `${pkg.root}/${page}`)).flat()]

const extraClassItem = (className: string): string[] => {
if (className == "" || className.length <= 2) {
return []
}
if (className.match(/^[\s\da-z-\\.]+$/)) {
return className.trim().split(/\s+/)
}
const result = className.trim().match(/[\w-]+/g)
if(!result) {
return []
}
return result.filter(m=> m.length > 1 && !/[A-Z]/.test(m))
}

const parseClassItem = (page: string, countMap: CountMap) => {
const xml = Deno.readTextFileSync(fullPagePath(page))
let attrName = ""
for (const token of htmltok(xml)) {
if (token.type == TokenType.ATTR_NAME) {
attrName = token.getValue()
} else if (isClassAttr(attrName) && token.type == TokenType.ATTR_VALUE) {
const items = extraClassItem(token.getValue())
items.forEach((s:string)=> {
countMap[s] = (countMap[s] || 0) + 1
})
}
}
}

const readAllClassItems = async () => {

const classNameMap: CountMap = {}
const pages = await Deno.readTextFile(ConfigFileName)
.then((data: string) => readWxmpPages(JSON.parse(data)))
.then((pages: any) => pages.map((page: string) => parseClassItem(page, classNameMap)))
return [...Object.keys(classNameMap)]
}

const classItems = await readAllClassItems()
console.log(classItems)

 执行命令

deno run --allow-read ./wxmp-atomic-css-generate.ts

也可以将 wxmp-atomic-css-generate.ts 文件放到代码仓库,在小程序代码下直接执行。


3 小结

本文介绍了基于 deno 实现 CLI 模式的微信小程序原子样式代码生成方式,一个文件即可。微信小程序适配的主要工作任务是从页面文件中提取样式名称,通过正则表达式和函数组合可以提取。复杂点在于识别微信表达式,提取样式名称不遗漏。