<p class="image-package"><img class="uploaded-img" src="https://upload-images.jianshu.io/upload_images/3895637-4ae8370826017e94.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="auto" height="auto"/></p><p><strong>前言</strong></p><p><strong>tailwindcss</strong>?是一個(gè)原子類優(yōu)先的css框架形庭,現(xiàn)如今非常的流行。它語義化的?<strong>類名</strong>?能夠讓前端開發(fā)人員<strong>直觀</strong>地對(duì)元素的樣式進(jìn)行編寫和維護(hù)厌漂。</p><p>然而這種直觀性萨醒,有時(shí)候也會(huì)帶來一定的困擾。有時(shí)候我們不想讓用戶或者外界的開發(fā)人員也能直觀的觀測(cè)到所有元素的樣式苇倡,</p><p>比如我們?cè)L問?<a>https://tailwindcss.com</a>?, 然后打開開發(fā)者工具富纸,檢查元素。瞬間雏节,頁面上那些元素的排版和樣式都能猜測(cè)出來胜嗓,甚至都不需要看右邊的?<strong>style</strong>?面板。</p><p>所以钩乍,出于讓其他人在生產(chǎn)環(huán)境中無法直觀的看出一個(gè)元素的樣式,我們就需要對(duì)?<strong>tailwindcss</strong>?生成的原子類進(jìn)行混淆怔锌。</p><p><strong>方案的尋找</strong></p><p>起初我在網(wǎng)絡(luò)上尋找解決方案時(shí)寥粹,我找到了?<strong>mangle-css-class-webpack-plugin</strong>变过,這是一個(gè)?<strong>webpack</strong>?插件,專門用來壓縮和混淆在?<strong>html</strong>,<strong>js</strong>,<strong>css</strong>?里的類名涝涤。</p><p>然而我在嘗試使用它去混淆?<strong>tailwindcss</strong>?的類名的時(shí)候遇到了困難媚狰,一開始我無法準(zhǔn)確的傳入?<strong>classNameRegExp</strong>?和其他的參數(shù),這導(dǎo)致我?<strong>webpack build</strong>?之后的結(jié)果阔拳,要不就完全是錯(cuò)的崭孤,要不就完全達(dá)不到預(yù)期,后來找了一些?<strong>issue</strong>?看似解決了這個(gè)問題糊肠,但是可維護(hù)性極差辨宠。</p><p>另外直接通過正則去修改?<strong>js</strong>?里的字面量的方式,很容易造成小范圍誤傷货裹,導(dǎo)致整個(gè)項(xiàng)目運(yùn)行不起來報(bào)錯(cuò)嗤形。</p><p>于是我開始思考,有沒有什么方式能夠精準(zhǔn)的實(shí)現(xiàn)混淆?<strong>tailwindcss</strong>?的類名弧圆,以下是我的解決方案赋兵。</p><p><strong>如何實(shí)現(xiàn)混淆</strong></p><p>首先為了更加精確的進(jìn)行匹配,我決定從以下角度去實(shí)現(xiàn)</p><ol><li><p>為了精確找到?<strong>tailwindcss</strong>?生成了多少的類搔预,我需要在運(yùn)行時(shí)霹期,得到?<strong>tailwindcss</strong>?的上下文。</p></li><li><p>放棄正則匹配拯田,全面使用AST,即使用?<strong>prase5</strong>?來解析轉(zhuǎn)化?<strong>html</strong>?,使用?<strong>babel</strong>?來解析轉(zhuǎn)化?<strong>js</strong>,使用?<strong>postcss</strong>?來解析轉(zhuǎn)化?<strong>css</strong></p></li></ol><p>為了達(dá)到第一點(diǎn)历造,我設(shè)計(jì)編寫了一個(gè)npm包:?<a>tailwindcss-patch</a>?使用它來獲取到所有生成的?<strong>class</strong>?集合。</p><p>為了達(dá)到第二點(diǎn)勿锅,我編寫了一個(gè)<strong>unplugin</strong>插件:?<a>unplugin-tailwindcss-mangle</a>, 這是一個(gè)?<strong>webpack/vite</strong>?插件帕膜,用來在打包的時(shí)候,修改<strong>html</strong>,<strong>js</strong>,<strong>css</strong>混淆所有的類名溢十。</p><p><strong>如何使用</strong></p><p>那么如何使用它們呢垮刹?很簡(jiǎn)單只要以下幾步:</p><p><strong>1. 安裝這2個(gè)包</strong></p><pre><npm|yarn|pnpm>?i?-D?unplugin-tailwindcss-mangle?tailwindcss-patch</pre><p><strong>2. 執(zhí)行一下腳本</strong></p><pre>npx?tw-patch</pre><p><strong>3. 添加?</strong></p><pre>??"scripts":?{
????"prepare":?"tw-patch"
??},</pre><p><strong>4. 注冊(cè)這個(gè)插件</strong></p><p>這里以?<strong>webpack</strong>?和?<strong>vite</strong>?為例</p><p><strong>webpack</strong></p><pre>//?esmimport?{?webpackPlugin?as?utwm?}?from?'unplugin-tailwindcss-mangle'//?or?cjsconst?{?webpackPlugin:?utwm?}?=?require('unplugin-tailwindcss-mangle')//?use?this?webpack?plugin//?for?example?next.config.js/*?@type?{import('next').NextConfig}?/const?nextConfig?=?{
??reactStrictMode:?true,
??webpack:?(config)?=>?{
????config.plugins.push(utwm())
????return?config
??}}module.exports?=?nextConfig</pre><p>這里我以?<strong>nextjs</strong>?為例,當(dāng)然?<strong>vue.config.js</strong>?那些也都是類似的张弛,把?<strong>utwm()</strong>?注冊(cè)進(jìn)?<strong>webpack</strong>?然后打包構(gòu)建荒典,預(yù)覽即可看到效果。</p><p><strong>vite</strong></p><pre>//?for?example:?vue?vite?projectimport?{?defineConfig?}?from?'vite'import?vue?from?'@vitejs/plugin-vue'import?{?vitePlugin?as?utwm?}?from?'unplugin-tailwindcss-mangle'//?https://vitejs.dev/config/export?default?defineConfig({
??plugins:?[vue(),?utwm()]})</pre><p>然后執(zhí)行腳本:</p><pre>#?generate?bundle<npm|yarn|pnpm>?run?build#?preview<npm|yarn|pnpm>?run?preview</pre><p><strong>效果預(yù)覽</strong></p><pre><div?class="z-10?w-full?max-w-5xl?items-center?justify-between?font-mono?text-sm?lg:flex"></div><div?class="tw-g?tw-h?tw-i?tw-d?tw-e?tw-j?tw-k?tw-l"></div></pre><p>當(dāng)然吞鸭,你也可以自定義生成的類名寺董,查看<a>文檔</a>獲取更多的配置項(xiàng)。</p><p><strong>核心原理</strong></p><p>上面簡(jiǎn)單的介紹了一下使用方式刻剥,下面才是正文遮咖,當(dāng)然只是用就沒必要看這一段了。</p><p>思路上造虏,首先我們仿照?<strong>tailwindcss</strong>?的文件提取方式御吞,先從源文件(<strong>content</strong>?配置的?<strong>glob</strong>?表達(dá)式 覆蓋到的文件)麦箍,比如?<strong>html</strong>,<strong>js</strong>,<strong>ts</strong>,<strong>jsx</strong>,<strong>tsx</strong>,<strong>vue</strong>,<strong>svelte</strong>...這類的文件中,讀取內(nèi)容生成?<strong>class</strong>,然后陶珠,利用?<strong>html ast</strong>?和?<strong>babel ast</strong>?轉(zhuǎn)義挟裂,把轉(zhuǎn)義結(jié)果保存起來,最后交給?<strong>postcss</strong>?對(duì)所有的?<strong>css</strong>?選擇器進(jìn)行轉(zhuǎn)義揍诽。</p><p>一圖以蔽之:</p><p class="image-package"><img class="uploaded-img" src="https://upload-images.jianshu.io/upload_images/3895637-373f93cf745f6cdf.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" width="auto" height="auto"/></p><p>當(dāng)然有些聰明的小伙伴诀蓉,可能會(huì)產(chǎn)生疑問,為什么圖上的?<strong>css</strong>?被處理了?<strong>2</strong>?次呢暑脆?</p><p>因?yàn)?<strong>css</strong>?有可能是變成一段?<strong>inline</strong>?的?<strong>js</strong>簸淀,這種情況下框产,沒有?<strong>css</strong>?文件產(chǎn)生,只有一個(gè)?<strong>js</strong>?塊,里面包含著樣式內(nèi)容匕争,這時(shí)候使用插入?<strong>loader</strong>?的方案可以解決狮荔。而最后獲取生成器內(nèi)的<strong>map</strong>進(jìn)行轉(zhuǎn)化和比較盼樟,算是一道雙保險(xiǎn)倒槐。</p><p><strong>SSR 場(chǎng)景思考和解決方案</strong></p><p>然而上述方案還有一些缺陷,尤其是在?<strong>ssr</strong>?場(chǎng)景下</p><p>我們都知道?<strong>react</strong>/<strong>vue</strong>?<strong>ssr</strong>?模式下面會(huì)打?<strong>2</strong>類包玄帕,一類是服務(wù)端部脚,一類是客戶端的。</p><p>這意味著我們?cè)谶\(yùn)行構(gòu)建任務(wù)時(shí)裤纹,我們的插件會(huì)被跑?<strong>2</strong>?次委刘。</p><p>然而這里面存在一個(gè)嚴(yán)重的問題,我們能得到?<strong>tailwindcss</strong>?上下文的時(shí)機(jī)鹰椒,是在客戶端的?<strong>postcss</strong>?被觸發(fā)后锡移,然而服務(wù)端打包時(shí),并不會(huì)觸發(fā)?<strong>postcss</strong>?的處理漆际。假如?<strong>server</strong>?的包淆珊,在?<strong>client</strong>?的包之前打好了,這時(shí)候運(yùn)行項(xiàng)目奸汇。由于?<strong>clinet</strong>?包被混淆了施符,<strong>server</strong>包沒有被混淆,這時(shí)候就會(huì)出現(xiàn)?<strong>2</strong>邊的<strong>dom</strong>?屬性不對(duì)等的問題擂找,從而造成客戶端水合激活報(bào)錯(cuò)戳吝。遇到這種情況,我們應(yīng)該怎么辦呢贯涎?</p><p>實(shí)際上很簡(jiǎn)單听哭,既然插件在同一個(gè)?<strong>nodejs</strong>?進(jìn)程里,被運(yùn)行了?<strong>2</strong>?次,那么我們大可創(chuàng)建一塊緩存區(qū)域欢唾,當(dāng)發(fā)現(xiàn)?<strong>server</strong>?端的打包先被激活的時(shí)候且警,我們就緩存住它的運(yùn)行結(jié)果粉捻,就是那些?<strong>Webpack Source</strong>?或者?<strong>Vite Chunk/Asset</strong>?對(duì)象礁遣。等到客戶端獲取上下文,處理好了之后肩刃,再把它們?nèi)ト〕鰜硭罨簦褂蒙舷挛膶?duì)?<strong>server bundle</strong>?進(jìn)行處理混淆,然后再對(duì)之前?<strong>server</strong>?已經(jīng)輸出的結(jié)果進(jìn)行覆寫盈包,這樣不就可以了嗎沸呐?</p><p>所以這個(gè)方案,我用在了?<strong>nextjs</strong>/<strong>nuxtjs</strong>?里呢燥。</p><p><strong>錯(cuò)誤與反饋</strong></p><p>如果你在使用過程中崭添,遇到了問題或者疑問,或者想進(jìn)行交流叛氨,歡迎提?<a>issue</a>?給我.</p><p>
</p>
一個(gè)混淆Tailwindcss類的工具
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
- 文/潘曉璐 我一進(jìn)店門使鹅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人昌抠,你說我怎么就攤上這事患朱。” “怎么了扰魂?”我有些...
- 文/不壞的土叔 我叫張陵麦乞,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我劝评,道長(zhǎng)姐直,這世上最難降的妖魔是什么? 我笑而不...
- 正文 為了忘掉前任蒋畜,我火速辦了婚禮声畏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己插龄,他們只是感情好愿棋,可當(dāng)我...
- 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著均牢,像睡著了一般糠雨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上徘跪,一...
- 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼寒亥!你這毒婦竟也來了邮府?” 一聲冷哼從身側(cè)響起,我...
- 序言:老撾萬榮一對(duì)情侶失蹤护盈,失蹤者是張志新(化名)和其女友劉穎挟纱,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腐宋,經(jīng)...
- 正文 獨(dú)居荒郊野嶺守林人離奇死亡紊服,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
- 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了胸竞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片欺嗤。...
- 正文 年R本政府宣布吆玖,位于F島的核電站,受9級(jí)特大地震影響马篮,放射性物質(zhì)發(fā)生泄漏沾乘。R本人自食惡果不足惜,卻給世界環(huán)境...
- 文/蒙蒙 一浑测、第九天 我趴在偏房一處隱蔽的房頂上張望翅阵。 院中可真熱鬧歪玲,春花似錦、人聲如沸掷匠。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽讹语。三九已至钙皮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間募强,已是汗流浹背株灸。 一陣腳步聲響...
- 正文 我出身青樓逐抑,卻偏偏與公主長(zhǎng)得像鸠儿,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子厕氨,可洞房花燭夜當(dāng)晚...
推薦閱讀更多精彩內(nèi)容
- 來自 「楊勁松」 同學(xué)的內(nèi)部分享进每。 說起前端構(gòu)建,大家一定首先想到 Webpack命斧,確實(shí)它是前端構(gòu)建的老大哥了田晚,大...
- 作為奇舞團(tuán)的一個(gè)小小程序媛贤徒,每天都在不斷地接受新知識(shí),PostCSS剛學(xué)完汇四,PostHTML又出來了接奈。剛研究明白R(shí)...
- theme: nico 初始化 vue-ts 項(xiàng)目 pnpm create vite tutulist-web-a...
- 在小程序中愉快的使用 Tailwind CSS 吧! 把 tailwindcss JIT 思想帶入小程序開發(fā)吧! ...