让你的小程序用上原汁原味的 Tailwind/Windi CSS

  • By Digital Creative
  • Last update: Dec 30, 2022
  • Comments: 3

wechat-mp-plugin

Mini Program Tailwind Webpack Plugin

让你的小程序用上原汁原味的 Tailwind/Windi CSS

来自 Digital Creative, 一家位于上海的数字产品调研、设计与开发公司。

了解我们

推荐阅读 独立文档 以获得更好的阅读体验 ♥️


介绍

由于小程序本身不支持由 Tailwind/Windi CSS 产生的选择器名称中包含的一些特殊转义字符(如 \[ \! \. 等),这使得你在开发小程序时无法使用一些本该在开发 Web 应用时使用的得心应手的灵活语法与 JIT/Value auto-infer 功能,如 w-[30px] translate-x-1/2 !bg-[#ff0000] 等。这无疑对我们的开发效率与心智负担带来了不小的影响。

为了突破这一限制,我们开发了这一款插件来帮助你在使用 Tailwind/Windi CSS 开发小程序时仍然保持着与开发 Web 应用高度一致的开发体验,你不再需要关注因为哪些字符串不被支持而不得不换一种写法的问题,而是继续按照 Tailwind/Windi CSS 的官方语法继续编写你的小程序样式,背后的兼容工作则由这款插件静默处理。

此外,本插件还集成了 rpx 值自动转换的功能。该功能可以将 Tailwind/Windi CSS 配置文件中以及源码中我们书写的 rempx 单位的值在最终生成的样式文件中自动转换为 rpx 单位的值。这既可以让开发者复用在 Web 项目中使用的同一份主题配置又可以让小程序继续使用 responsive pixel 带来的特性。

进一步了解本插件的工作原理

让你的小程序用上原汁原味的 Tailwind/Windi CSS


快速开始

选择其中一个适合你的小程序类型进行插件安装

⚙️ 针对常规 Webpack 类小程序(以 MPX 为例)

常规 Webpack 类小程序(以 MPX 为例)

MPX, 一款具有优秀开发体验和深度性能优化的增强型跨端小程序框架。

由于 MPX 框架为典型的以 Webpack 为构建工具的增强型小程序开发框架,所以本次安装示范将 MPX 项目作为典型案例来演示如何为大部分 Webpack 类小程序项目进行插件安装。以下安装步骤在 Webpack 项目中具有广泛的通用性,对于大部分 Webpack 类小程序项目只需参考相同步骤进行安装即可。

安装 windicss-webpack-plugin

npm i windicss-webpack-plugin -D
参考 Windi CSS 官方文档了解更多细节

Windi CSS Webpack 集成

安装 @dcasia/mini-program-tailwind-webpack-plugin

npm i @dcasia/mini-program-tailwind-webpack-plugin -D

更新 webpack 配置文件

使用 Webpack 插件

//webpack.base.conf.js
const WindiCSSWebpackPlugin = require("windicss-webpack-plugin");
const MiniProgramTailwindWebpackPlugin = require("@dcasia/mini-program-tailwind-webpack-plugin")

module.exports = {
  plugins: [
    new WindiCSSWebpackPlugin(),
    new MiniProgramTailwindWebpackPlugin({
      // options
    })
  ]
}

新建 Windi CSS 配置文件

在项目根目录新建 windi.config.js 配置文件

//windi.config.js
export default {
  preflight: false,
  prefixer: false,
  extract: {
    // 将 .mpx 文件纳入范围(其余 Webpack 类小程序根据项目本身的文件后缀酌情设置)
    include: ['src/**/*.{css,html,mpx}'],
    // 忽略部分文件夹
    exclude: ['node_modules', '.git', 'dist']
  },
  corePlugins: {
    // 禁用掉在小程序环境中不可能用到的 plugins
    container: false
  }
}

此处 Tailwind CSS 配置文件同样适用

参考 Windi CSS 官方文档了解更多细节

Windi CSS 配置文件兼容规则

在入口文件中引入 Windi CSS 的产物

// app.mpx
<style src="windi.css"></style>

对于其余非 MPX 项目的 Webpack 类小程序,可参考类似的方式在入口文件中引入 windi.css 即可,如:

// main.js
import 'windi.css'
参考 Windi CSS 官方文档了解更多细节

引入 Windi CSS 样式文件

完成

开始享受在小程序项目中由 Windi CSS 带来的高效开发体验 🎉

可配置参数

名称 类型 默认 描述
enableRpx Boolean true 是否开启自动转换至 rpx 单位值的功能
designWidth Number 350 设计稿的像素宽度值,该尺寸会影响 rpx 转换过程中的计算比率

案例

集成案例:MPX 项目

👽 针对 Taro 小程序

Taro 小程序

Taro, 多端统一开发解决方案

本插件包含 Taro 插件,通过“一键安装”的方式来便捷的适配 Taro 小程序。

Taro 插件已兼容以下前端框架

  • React
  • Vue 2
  • Vue 3

同时也兼容在混合原生组件开发中使用 Tailwind/Windi CSS

安装 @dcasia/mini-program-tailwind-webpack-plugin

npm i @dcasia/mini-program-tailwind-webpack-plugin -D

使用 Taro 插件

// config/index.js
const config = {
  plugins: [
    ['@dcasia/mini-program-tailwind-webpack-plugin/dist/taro', {
      // ...options
    }]
  ]
}

新建 Windi CSS 配置文件

在项目根目录新建 windi.config.js 配置文件

// windi.config.js
export default {
  prefixer: false,
  extract: {
    // 忽略部分文件夹
    exclude: ['node_modules', '.git', 'dist']
  },
  corePlugins: {
    // 禁用掉在小程序环境中不可能用到的 plugins
    container: false
  }
}

此处 Tailwind CSS 配置文件同样适用

参考 Windi CSS 官方文档了解更多细节

Windi CSS 配置文件兼容规则

在入口文件中引入 Windi CSS 的产物

// app.js
import 'windi.css';

完成

开始享受在 Taro 中由 Windi CSS 带来的高效开发体验 🎉

可配置参数

名称 类型 默认 描述
enableWindiCSS Boolean true 是否开启插件自带的 Windi CSS
windiCSSConfigFile String 读取项目根目录的配置文件 必要时手动设置 Windi CSS 配置文件的路径
enableRpx Boolean false 是否开启自动转换至 rpx 单位值的功能(由于 Taro 自带该功能,默认关闭)
designWidth Number 375 设计稿的像素宽度值,该尺寸会影响 rpx 转换过程中的计算比率
enableDebugLog Boolean false 是否开启打印本插件的内部运行日志

案例

🔗 针对 uni-app 小程序

uni-app 小程序

uni-app, 开发一次,多端覆盖。

本篇内容包含 uni-app 的 Vue 3 与 Vue 2 两种安装示范。

Vue 3 安装示范

请参考下一个小程序类型:常规 Vite 类小程序(以 uni-app 为例)

Vue 2 安装示范

安装 windicss-webpack-plugin

npm i windicss-webpack-plugin -D
参考 Windi CSS 官方文档了解更多细节

Windi CSS Webpack 集成

安装 @dcasia/mini-program-tailwind-webpack-plugin

npm i @dcasia/mini-program-tailwind-webpack-plugin -D

新建 Vue 配置文件

在项目根目录新建 vue.config.js 配置文件并使用 Webpack 插件

// vue.config.js
const WindiCSSWebpackPlugin = require("windicss-webpack-plugin");
const MiniProgramTailwindWebpackPlugin = require("@dcasia/mini-program-tailwind-webpack-plugin")

module.exports = {  
  configureWebpack: {  
    plugins: [  
      new WindiCSSWebpackPlugin(),
      new MiniProgramTailwindWebpackPlugin({
        // options
      })
    ]  
  }  
}

新建 Windi CSS 配置文件

在项目根目录新建 windi.config.js 配置文件

//windi.config.js
export default {
  preflight: false,
  prefixer: false,
  extract: {
    // 忽略部分文件夹
    exclude: ['node_modules', '.git', 'dist']
  },
  corePlugins: {
    // 禁用掉在小程序环境中不可能用到的 plugins
    container: false
  }
}

此处 Tailwind CSS 配置文件同样适用

参考 Windi CSS 官方文档了解更多细节

Windi CSS 配置文件兼容规则

在入口文件中引入 Windi CSS 的产物

// main.js
import 'windi.css'

完成

开始享受在小程序项目中由 Windi CSS 带来的高效开发体验 🎉

可配置参数

名称 类型 默认 描述
enableRpx Boolean true 是否开启自动转换至 rpx 单位值的功能
designWidth Number 350 设计稿的像素宽度值,该尺寸会影响 rpx 转换过程中的计算比率

案例

集成案例:uni-app Vue 2 项目

🔩 针对常规 Vite 类小程序(以 uni-app 为例)

常规 Vite 类小程序(以 uni-app 为例)

uni-app, 开发一次,多端覆盖。

由于在 uni-app 中使用 Vue 3 进行小程序开发时项目是基于 Vite 进行构建的,所以本次安装示范将 uni-app Vue 3 项目作为典型案例来演示如何为大部分 Vite 类小程序项目进行插件安装。以下安装步骤在 Vite 项目中具有广泛的通用性,对于大部分 Vite 类小程序项目只需参考相同步骤进行安装即可。

安装 vite-plugin-windicss 与 windicss

npm i vite-plugin-windicss windicss -D
参考 Windi CSS 官方文档了解更多细节

Windi CSS Vite 集成

安装 @dcasia/mini-program-tailwind-webpack-plugin

npm i @dcasia/mini-program-tailwind-webpack-plugin -D

更新 Vite 配置文件

vite.config.js 配置文件中使用插件

// vite.config.js
import WindiCSS from 'vite-plugin-windicss';
import MiniProgramTailwind from '@dcasia/mini-program-tailwind-webpack-plugin/rollup';

export default {
  plugins: [
    WindiCSS(),
    MiniProgramTailwind()
  ]
}

新建 Windi CSS 配置文件

在项目根目录新建 windi.config.js 配置文件

//windi.config.js
export default {
  preflight: false,
  prefixer: false,
  extract: {
    // 忽略部分文件夹
    exclude: ['node_modules', '.git', 'dist']
  },
  corePlugins: {
    // 禁用掉在小程序环境中不可能用到的 plugins
    container: false
  }
}

此处 Tailwind CSS 配置文件同样适用

参考 Windi CSS 官方文档了解更多细节

Windi CSS 配置文件兼容规则

在入口文件中引入 Windi CSS 的产物

// main.js
import 'virtual:windi.css'

完成

开始享受在小程序项目中由 Windi CSS 带来的高效开发体验 🎉

可配置参数

名称 类型 默认 描述
enableRpx Boolean true 是否开启自动转换至 rpx 单位值的功能
designWidth Number 350 设计稿的像素宽度值,该尺寸会影响 rpx 转换过程中的计算比率

案例

集成案例:uni-app Vue 3 项目

🛠 针对原生开发或自定义构建的小程序

原生开发或自定义构建工具的小程序

无论你的项目基于什么 bundler 或 workflow 工具进行开发,只要有一个可编程的文件监听与处理服务便可以进行自定义实现。但这里需要明确的一点是,若想在以原生开发模式的基础之上去集成本插件的功能,则一定需要我们去启动一套可编程的文件监听处理服务作为插件的运行基础,这个服务通常由配置好的 Webpack, Gulp 等第三方工具完成。

使用 Tailwind/Windi CSS CLI 的开发者请看

如果你是通过 Tailwind/Windi CSS 官方的 CLI 进行小程序 UI 开发,遗憾的是由于该 CLI 不支持插件机制而且不可能支持对于模板文件的修改,所以我们无法在此基础之上以自定义的方式集成本插件。

我们将本插件的核心功能解耦并打包进了 universal-handler.js 文件中,若你想在自定义的构建工具中集成本插件的核心功能,可以在工作流逻辑中引入 universal-handler

const { handleSource } = require('@dcasia/mini-program-tailwind-webpack-plugin/universal-handler')

处理 template:

const rawContent = '<view class="w-10 h-[0.5px] text-[#ffffff]"></view>'
const handledTemplate = handleSource('template', rawContent, options) // 'template' 为常量,设置文件类型为模板文件

处理 style:

const rawContent = '.h-\\[0\\.5px\\] {height: 0.5px;}'
const handledStyle = handleSource('style', rawContent, options) // 'style' 为常量,设置文件类型为样式文件

此后你便可以将处理过的字符串返回至工作流原本的流程中来生成最终的文件。

进一步了解自定义实现过程中的实践细节

小程序集成 Windi CSS 的自定义实现

可配置参数

名称 类型 默认 描述
enableRpx Boolean false 是否开启自动转换至 rpx 单位值的功能
designWidth Number 350 设计稿的像素宽度值,该尺寸会影响 rpx 转换过程中的计算比率

案例

集成案例:基于 Gulp 进行自定义实现

示范操作步骤均以集成 Windi CSS 为例(Windi CSS 的体验更佳且兼容 Tailwind CSS)

进一步了解 Windi CSS

Windi CSS


陷阱

  • 在小程序中为了使组件样式可以被 Tailwind/Windi 的 CSS 产物作用到,我们需要在每一个组件的 JSON 配置文件中设置其样式的作用域 styleIsolation,否则即使 Tailwind/Windi CSS 工作正常也无法用来开发组件 UI。

    {
      "component": true,
      "styleIsolation": "apply-shared"
    }
    相关 issue

    Issue #1

  • 由于目前微信开发者工具的热重载功能无法监听到样式文件内由 @import 导入的 wxss 文件内容的变动,所以当启用热重载功能开发时,模拟器不会随着你对 Tailwind/Windi CSS 的更改而更新 UI。目前微信官方已知晓该 bug 的存在,在该 bug 修复之前,我们建议你在开发时关闭热重载,用传统的页面自动刷新来预览每一次的 UI 更新。

    相关 issue

    Issue #3


功能对比

语法 不使用本插件 使用本插件
Regular: h-10 text-white
JIT/Value infer: t-[25px] bg-[#ffffff]
Fraction: translate-x-1/2 w-8.5
Important: !p-1
RGB value infer: text-[rgb(25,25,25)]
Variants: dark:bg-gray-800
Variants groups: hover:(bg-gray-400 font-medium)
Responsive: md:p-2
rpx value transformed from rem and px value

兼容范围

  • Webpack >= 4.0.0
  • Taro >= 3.0.0
  • uni-app
  • MPX

trackgit-views

Github

https://github.com/dcasia/mini-program-tailwind

Comments(3)

  • 1

    动态属性有时候会没有正确编译

    "react": "^18.0.0" "@dcasia/mini-program-tailwind-webpack-plugin": "^1.5.6" "@tarojs/cli": "3.5.10"

    支付宝小程序,打包似乎没有问题,但是开发的时候会出现有原本正常编译的class没有被编译 image

  • 2

    无法编译支付宝小程序

    存在动态绑定class类的情况下,编译到支付宝小程序里直接报错。

    Module build failed (from C:/snapshot/code-repo/out/target/bundle/node_modules/@ali/antcube-thread-loader/lib/cjs.js):
    Thread Loader (Worker 0)
    Expected "
    at (c:\Workspace\gitlab\efficient-wx\dist\dev\mp-alipay\pages\search\modules\Hots.axml:1:1322)
    
    at (c:\Workspace\gitlab\efficient-wx\dist\dev\mp-alipay\pages\search\modules\Hots.axml:1:1322)
    Module build failed (from C:/snapshot/code-repo/out/target/bundle/node_modules/@ali/antcube-thread-loader/lib/cjs.js):
    Thread Loader (Worker 1)
    Expected "
    at (c:\Workspace\gitlab\efficient-wx\dist\dev\mp-alipay\pages\search\modules\Hots.axml:1:1322)
    
    at (c:\Workspace\gitlab\efficient-wx\dist\dev\mp-alipay\pages\search\modules\Hots.axml:1:1322)
    
    

    报错情况:

     <view
            v-for="(item,index) in table.list"
            :key="index"
            class="mt-[41rpx] text-center tracking-[2.8rpx]"
            :class="[table.index === index ? 'text-theme' : 'text-main']"
            @tap="fetchHotDetail(item, index)"
          >
            {{ item.name }}
     </view>
    

    不报错:

     <view class="hot-item">
          <view
            v-for="(item,index) in table.list"
            :key="index"
            class="base-item"
            :class="[table.index === index ? 'text-theme' : 'text-main']"
            @tap="fetchHotDetail(item, index)"
          >
            {{ item.name }}
          </view>
     </view>
    
    css: 
    .base-item{
    @apply @apply mt-[41rpx] text-center tracking-[2.8rpx];
    }
    
    
  • 3

    mpx @apply指令问题

    https://github.com/dcasia/mini-program-tailwind/blob/11afaf0a77d56032b6b2cf65c4da555ff2f9c9d5/examples/mpx/src/pages/index.mpx#L10-L13

    在mpx v2.8.0中似乎能够支持@apply指令了