網(wǎng)站排名優(yōu)化在線培訓(xùn)百度云網(wǎng)盤網(wǎng)頁版登錄
Panda 編譯時(shí)原子化 CSS-in-JS 框架的跨平臺方案
- Panda 編譯時(shí)原子化 CSS-in-JS 框架的跨平臺方案
- 對編譯時(shí)原子化CSS框架的思考
- 編譯時(shí) CSS-in-JS 方案對比
- Linaria
- Pandacss
- 總結(jié)
- weapp-pandacss 介紹
- 快速開始
- pandacss 安裝和配置
- 0. 安裝和初始化 pandacss
- 1. 配置 postcss
- 2. 檢查你的 panda.config.ts
- 3. 修改 package.json 腳本
- 4. 全局 css 注冊 pandacss
- 5. 配置的優(yōu)化與別名
- weapp-pandacss 配置
- 0. 回到 postcss 進(jìn)行注冊
- 1. 回到 package.json 添加生成腳本
- pandacss 安裝和配置
- 跨平臺注意事項(xiàng)
- 小程序預(yù)覽事項(xiàng)
- 參考示例
- Show time
對編譯時(shí)原子化CSS框架的思考
筆者對目前市面上,一些流行的 編譯時(shí) 動態(tài)生成css
的解決方案還算有一點(diǎn)研究,比如 tailwindcss
,unocss
,( windicss
已死),又或者是 CSS-in-JS
思想下的 Linaria。
注意關(guān)鍵詞
編譯時(shí)(build time)
不是runtime
,所以不包括眾多運(yùn)行時(shí)CSS-in-JS
libs 或者是twind
這種方案
其中之前也寫了 weapp-tailwindcss
這樣一個(gè)開源項(xiàng)目,來和大家探討 tailwindcss
的跨平臺方案。
雖然大部分情況下 tailwindcss
已經(jīng)非常強(qiáng)了,我們可以通過 plugin
/ preset
/ @apply
等等功能,為自己的項(xiàng)目提煉出大量的樣式,縮短我們的類名,提升我們的效率,但是 tailwindcss
有個(gè)問題,就是 js
天然不親和。
是的,回想我們在使用 tailwindcss
的時(shí)候,要不就是直接在模板文件里寫原子類,要不就是在類 js
文件里操縱原子類的字面量,要不就是在 css
去 @apply/theme
來提取或組合多個(gè)原子類。
這看似靈活的同時(shí),卻給我們加了諸多限制。試想這樣一個(gè)場景,一個(gè)現(xiàn)成使用 tailwindcss
的項(xiàng)目, 有一天突然要去改所有原子類的前綴(prefix
),那這個(gè)改動將是一個(gè)浩劫!因?yàn)?prefix
這個(gè)配置項(xiàng),會影響到整個(gè) tailwindcss
上下文提取器的正則匹配方式,這意味著所有使用原子類的標(biāo)簽都要改!
而 CSS-in-JS
方案就不需要,因?yàn)轭惷怯?jì)算出來的,這顯然更加靈活。
編譯時(shí) CSS-in-JS 方案對比
這里重點(diǎn)介紹 2
種方案,一種是 Linaria
,另外一種是最近新出的 Pandacss
Pandacss
的作者Segun Adebayo
是一個(gè)尼日利亞(Nigeria
)黑人小哥,也是Chakra UI
的作者,真是太強(qiáng)了!
Linaria
一想到 linaria
我就想到一個(gè)字,牛逼!
,兩個(gè)字,太酷啦!
,它對 babel ast
的處理簡直是教科書級別的出神入化,令人著迷。
是的,它值得這么高的評價(jià),只要你看過它 babel
插件的實(shí)現(xiàn)。這里我們不深入探討,你只要知道它會去計(jì)算 css
模板字符串里的值和表達(dá)式(eval
流程),并把里面的計(jì)算結(jié)果提取成一個(gè)個(gè) css
節(jié)點(diǎn),然后在原先的 js
文件中 css
模板字符串處留下對應(yīng)的 css selector
的值。
不過這種方式生成的 class
選擇器名稱,雖然可以自定義,但是不能很好的代表生效樣式的內(nèi)容。因?yàn)橐粋€(gè) linaria css template string
只對應(yīng)一個(gè) css
節(jié)點(diǎn),所以說它不夠原子化。
這點(diǎn)不如 tailwindcss
直觀,例如,你一瞅見類名是 relative flex items-start
,你甚至都不需要打開 Chrome devtool
就知道里面的樣式是什么樣的。
Pandacss
而 pandacss
就是另外一種方案,它是原子化的,這意味著一個(gè)css()
方法會生成多個(gè) css
節(jié)點(diǎn),還有就是它和 [jt]sx?
文件相結(jié)合的寫法靈活而又令人印象深刻。
另外它的實(shí)現(xiàn)其實(shí)很像 tailwindcss
。
首先它們核心用法都是一個(gè) postcss plugin
,其次,它們都是通過分析我們源碼的內(nèi)容,去進(jìn)行提煉和生成css
原子類的。
不過不同的是,相比于 tailwindcss
這種基于文件內(nèi)容進(jìn)行 正則(regex) 匹配提取 token
的方式。pandacss
的提取器更為復(fù)雜。
它直接通過 ts-morph
,ts-pattern
,ts-evaluator
來評估和解析的所有 [jt]x?
文件內(nèi)容,同時(shí)也會把 vue
/ svelte
文件轉(zhuǎn)化成 tsx
進(jìn)行提取。真是太酷了!
另外一個(gè)部分,是它的js
運(yùn)行時(shí)和智能提示部分代碼,也是通過 panda codegen
生成到我們項(xiàng)目里的,這會導(dǎo)致在配置上稍稍復(fù)雜一點(diǎn),比如要額外配置 alias
和 tsconfig.json
等等。
總結(jié)
這 2
種 CSS-in-JS
方案各有它們出彩之處。目前我傾向于 pandacss
,只因 linaria
實(shí)在是太 hack
了! 它的 css
模板字符串,有自己的語法,有自己的詞法分析器,就像在創(chuàng)造一個(gè) Domain Specific Language
,真是太復(fù)雜了!但是它非常值得研究!
另外 pandacss
一個(gè)優(yōu)勢就是,它不會去修改我們的源代碼,這帶來了更少的出錯(cuò)的可能性,而本人在使用 linaria
的時(shí)候,配置稍復(fù)雜就有 fatal
的可能,這就需要我們花更多的時(shí)間去修復(fù)它。
它們各自有各自獨(dú)一無二的優(yōu)勢,相互無法完全替代,看它們各自的源代碼,就像在紫禁之巔欣賞葉孤城與西門吹雪的決戰(zhàn),令人賞心悅目的同時(shí),受益匪淺!
所以我推薦 pandacss
給大家,另外 panda
也是我國的國寶,這預(yù)示著中國又贏了!
weapp-pandacss 介紹
接下來進(jìn)入正題,我在使用了一段時(shí)間后的 pandacss
后,想在寫 taro react
項(xiàng)目的時(shí)候也去使用它,于是我就寫了這個(gè) weapp-pandacss。
讓我們快速來看看怎么使用它吧!
快速開始
pandacss 安裝和配置
0. 安裝和初始化 pandacss
首先我們需要把 @pandacss/dev
這些都安裝和配置好,這里我們以 tarojs
項(xiàng)目為例:
npm install -D @pandacss/dev weapp-pandacss postcss # 或者 yarn / pnpm
npx panda init
此時(shí)會在當(dāng)前目錄生成一個(gè) panda.config.ts
和一個(gè)包含大量文件的 styled-system
。
panda.config.ts
是pandacss
的配置文件,styled-system
文件夾里的是pandacss
的運(yùn)行時(shí)js
。
把 styled-system
加入我們的 .gitignore
中去。
# .gitignore
+ styled-system
1. 配置 postcss
接著在根目錄里,添加一個(gè) postcss.config.cjs
文件,寫入以下代碼注冊 pandacss
:
module.exports = {plugins: {'@pandacss/dev/postcss': {}}
}
2. 檢查你的 panda.config.ts
生成的配置文件大概長下面這樣,尤其注意 include
是用來告訴 pandacss
從哪些文件中提取原子類的,所以這個(gè)配置一定要準(zhǔn)確
import { defineConfig } from "@pandacss/dev"export default defineConfig({// 小程序不需要preflight: process.env.TARO_ENV === 'h5',// ??注意這里,假如你使用 vue,記得把 vue 文件格式包括進(jìn)來!!!include: ["./src/**/*.{js,jsx,ts,tsx}"],exclude: [],theme: {extend: {}},outdir: "styled-system",
})
3. 修改 package.json 腳本
然后,我們添加下方 prepare
腳本在我們的 package.json
的 scripts
塊中:
{"scripts": {
+ "prepare": "panda codegen",}
}
這樣我們每次重新 npm i / yarn /pnpm i
的時(shí)候,都會執(zhí)行這個(gè)方法,重新生成 styled-system
,當(dāng)然你也可以直接通過 npm run prepare
直接執(zhí)行這個(gè)腳本。
4. 全局 css 注冊 pandacss
然后在我們的全局樣式文件 src/app.scss
中注冊 pandacss
:
@layer reset, base, tokens, recipes, utilities;
配置好了之后,此時(shí) pandacss
在 h5
平臺已經(jīng)生效了,你可以 npm run dev:h5
在 h5
平臺初步使用了,但是為了開發(fā)體驗(yàn),我們還有一些優(yōu)化項(xiàng)要做。
5. 配置的優(yōu)化與別名
來到根目錄的 tsconfig.json
添加:
{"compilerOptions": {"paths": {"@/*": ["src/*"],
+ "styled-system/*": [
+ "styled-system/*"
+ ]}},"include": ["./src","./types","./config",
+ "styled-system"],
}
接著來到 config/index.ts
添加 alias
(參考鏈接):
import path from 'path'{alias: {'styled-system': path.resolve(__dirname, '..', 'styled-system')},
}
這樣我們就不需要使用相對路徑來使用 pandacss
了,同時(shí) ts
智能提示也有了,你可以這樣使用它:
import { View, Text } from "@tarojs/components";
import { css } from "styled-system/css";const styles = css({bg: "yellow.200",rounded: "9999px",fontSize: "90px",p: "10px 15px",color: "pink.500",
});export default function Index() {return (<View className={styles}><Text>Hello world!</Text></View>);
}
此部分參考的官方鏈接 https://panda-css.com/docs/installation/postcss
接下來進(jìn)入 weapp-pandacss
的插件配置,不用擔(dān)心,相比前面那些繁瑣的步驟,這個(gè)可簡單多了。
weapp-pandacss 配置
記得安裝好
weapp-pandacss
!
0. 回到 postcss 進(jìn)行注冊
回到項(xiàng)目根目錄的 postcss.config.cjs
注冊 weapp-pandacss
,添加以下配置:
module.exports = {plugins: {'@pandacss/dev/postcss': {},
+ 'weapp-pandacss/postcss': {}}
}
1. 回到 package.json 添加生成腳本
然后去 package.json
你添加 prepare
腳本的地方,加點(diǎn)代碼
{"scripts": {
- "prepare": "panda codegen",
+ "prepare": "panda codegen && weapp-panda codegen",}
}
注意這里必須用
&&
而不能用&
,&
任務(wù)執(zhí)行會并行不會等待,而&&
會等待前一個(gè)執(zhí)行完成再執(zhí)行后一條命令
然后,你再手動執(zhí)行一下
npm run prepare
來重新生成 styled-system
, 此時(shí)你會發(fā)現(xiàn) pandacss
的命令行輸出中多了 2
行:
?? `src/styled-system/css`: the css function to author styles
?? `src/styled-system/tokens`: the css variables and js function to query your tokens
?? `src/styled-system/patterns`: functions to implement apply common layout patterns
?? `src/styled-system/jsx`: styled jsx elements for react
+ ?? `src/styled-system/weapp-panda`: the core escape function for weapp
+ ?? `src/styled-system/helpers.mjs`: inject escape function into helpers
這代表著小程序相關(guān)的轉(zhuǎn)義邏輯已經(jīng)被注入進(jìn)去,此時(shí) panda css
生成的類就兼容小程序平臺啦,是不是很簡單?
當(dāng)然為了防止你配置失敗,我也給出了參考項(xiàng)目: taro-react-pandacss-template 方便進(jìn)行排查糾錯(cuò)。
跨平臺注意事項(xiàng)
你可能同時(shí)開發(fā) 小程序
和 h5
平臺,但是你發(fā)現(xiàn)使用 weapp-pandacss
之后,h5
平臺似乎就不行了?
這時(shí)候你可以這樣配置:
process.env.TARO_ENV === 'h5'
的時(shí)候,不去加載 weapp-pandacss/postcss
(根據(jù)環(huán)境變量動態(tài)加載 postcss
插件)
同時(shí)你也可以執(zhí)行 weapp-panda rollback
把 css
方法進(jìn)行回滾到最原始適配 h5
平臺的狀態(tài)。
當(dāng)然你恢復(fù)到小程序版本也只需要執(zhí)行 weapp-panda codegen
就會重新注入了。
小程序預(yù)覽事項(xiàng)
當(dāng)小程序預(yù)覽時(shí)會出現(xiàn) Error: 非法的文件,錯(cuò)誤信息:invalid file: pages/index/index.js, 565:24, SyntaxError: Unexpected token . if (variants[key]?.[value])
錯(cuò)誤。
這是因?yàn)?panda
生成的文件 cva.mjs
使用了 Optional chaining (?.)
語法,這個(gè)語法小程序原生不支持,這時(shí)候可以開啟勾選 將JS編譯成ES5
功能再進(jìn)行預(yù)覽,或者使用 babel
預(yù)先進(jìn)行處理再上傳預(yù)覽。
參考示例
taro-react-pandacss-template
Show time
最后給自己的個(gè)人小程序打個(gè)小小的推廣:
想要你的Github項(xiàng)目在微信內(nèi)分享嗎?快來試試 程序員名片
吧。
進(jìn)入方式:微信內(nèi),搜索 程序員名片
,快速注冊后添加名片,導(dǎo)入 Github
項(xiàng)目即可。
在使用過程中,如果遇到問題,或者你有好的意見和建議,歡迎與我討論。
Demo short link
: 微信內(nèi)訪問 #小程序://程序員名片/c9lmHLg29GtN2PH
查看我的名片。