什么是UnoCSS
UnoCSS 是一个原子化 CSS 引擎 ,旨在提供一种高效、灵活且轻量级的方式来生成和管理 CSS 样式。它由 Anthony Fu(Vue.js 核心团队成员之一)开发,并作为现代前端开发中的一种创新工具。UnoCSS 的核心目标是通过高度可配置性和按需生成样式,减少冗余代码,同时保持高性能。
核心特点
- 原子化 CSS:UnoCSS 使用类似于 Tailwind CSS 的原子化类名模式,每个类名对应一个具体的样式规则
- 按需生成:UnoCSS 不会像传统框架那样预生成所有可能的样式规则,而是根据项目实际使用的类名动态生成所需的 CSS。
- 高度可配置:UnoCSS 提供了强大的配置能力,允许开发者自定义规则、主题和插件。
- 无预设(No Preset):UnoCSS 默认没有内置的样式规则或预设,完全依赖于开发者定义的规则。
- 支持多种框架:UnoCSS 可以与多种前端框架(如 Vue、React、Svelte 等)无缝集成,同时也支持纯 HTML 项目。
- 极快的构建速度:由于其按需生成的特性,UnoCSS 在开发和生产环境中都具有极高的性能表现。
对于我来说,使用 UnoCSS 终于不用再纠结类名了,对于需要经常切换主题的项目也非常友好。可以说,用过就回不去了!
所以,当我最近接手到一个uniapp项目后,马上决定引入 UnoCSS 进行开发。然而,按照网上的步骤操作后,发现配置无法生效。经过观察,发现大多数教程都是针对使用 CLI 创建的 uniapp 项目,而我这个项目是直接在 HBuilderX 中创建的,很多配置都被 HBuilderX 高度封装。你问我为什么要使用HBuilderX创建?不知道,因为项目不是我创建的。但我实在无法忍受想类名的烦恼,于是决定想办法引入 UnoCSS。终于,受到这篇文章的启发,使用unocss/cli + child_process.exec实现了 UnoCSS 的引入。
开始配置
1. 安装依赖包
pnpm i unocss unocss-preset-weapp -D
2. 创建uno.config.js
在项目根目录下创建 uno.config.js 文件,并添加以下配置:
import presetWeapp from 'unocss-preset-weapp'
import { defineConfig } from 'unocss'
import { extractorAttributify, transformerClass } from 'unocss-preset-weapp/transformer'
const { transformerAttributify, presetWeappAttributify } = extractorAttributify()
export default defineConfig({
presets: [
// https://github.com/MellowCo/unocss-preset-weapp
presetWeapp({
// h5兼容
// 只开发小程序可删除
platform: 'uniapp',
isH5: process.env.UNI_PLATFORM === 'h5',
}),
// attributify autocomplete
presetWeappAttributify(),
],
transformers: [
// https://github.com/MellowCo/unocss-preset-weapp/tree/main/src/transformer/transformerAttributify
transformerAttributify(),
// https://github.com/MellowCo/unocss-preset-weapp/tree/main/src/transformer/transformerClass
transformerClass(),
],
})
3. 新增unocss/cli脚本
在 package.json 中新增 unocss/cli 脚本:
"scripts": {
"unocss": "unocss ./**/*.vue -c unocss.config.js --watch -o unocss.css",
"unocss:build": "unocss ./**/*.vue -c unocss.config.js -o unocss.css"
},
4. 引入unocss.css
在根组件 App.vue 中引入 unocss.css:
<style>
/* 每个页面公共 css */
@import 'unocss.css'
</style>
至此,通过手动执行 pnpm unocss 命令,然后再启动项目,已经可以成功实现引入 UnoCSS 了。但每次启动项目前都需要手动执行脚本,这显然不够方便。
5. 实现自动化
为了实现自动化,我们可以通过 child_process.exec 在项目启动时自动执行 unocss 脚本。新建 vue.config.js 文件,并添加以下代码:
const { exec } = require('child_process');
console.log("process.env.NODE_ENV:", process.env.NODE_ENV);
console.log("当前nodejs版本", process.version);
const isDev = process.env.NODE_ENV === 'development';
exec(
// 这里指令对应 package.json 中的 npm scripts
isDev ?
'npm run unocss' :
'npm run unocss:build', {
cwd: __dirname, // 切换目录到当前项目,必须
stdio: 'inherit',
},
(error, stdout, stderr) => {
// unocss --watch 是一个持久进程,不会立即执行回调
if (error) {
console.error('[unocss] 异常,请检查');
console.error(error);
console.error(stdout);
console.error(stderr);
}
})
module.exports = {};
通过以上配置,启动项目时会自动执行 unocss 脚本,从而实现 UnoCSS 的自动化引入。
正当我以为能够完结撒花时,意外来了!
意料之外
当时,经过以上步骤,我已经在常用电脑上成功配置并运行了项目。然而,当我在另一台电脑上尝试运行同一个项目时,却遇到了一个令人困惑的错误:'npm'不是内部或外部命令,也不是可运行的程序或批处理文件。。这让我感到非常奇怪,因为我确认已经安装了 node 和 npm,并且在本地终端中也能正常执行这些命令。
经过一番排查,我发现了一个关键问题:在 powershell 终端中,npm 命令可以正常执行,但在 cmd 中却失败了。而 child_process.exec 默认使用的是 cmd 来运行命令。于是,我开始深入探究为什么在 cmd 中无法运行 npm。
最终,我找到了问题的根源:我的备用电脑在安装 fnm(Fast Node Manager)时,配置没有完全生效,导致 cmd 无法识别 npm 命令。为什么我的常用电脑没有这个问题呢?因为常用电脑上安装的是 nvm for windows,而 nvm 和 fnm 的实现原理不同,nvm 的环境变量配置在 cmd 中能够正常生效,因此常用电脑没有问题。
于是,我按照 fnm 的官方文档重新配置了环境变量,并在 cmd 中验证了 npm 命令可以正常执行。本以为问题已经解决,但当我满怀希望地启动项目时,却再次遇到了同样的错误:'npm'不是内部或外部命令,也不是可运行的程序或批处理文件。。
经过进一步的分析,我得出结论:fnm 的官方文档中提到的配置方式,是通过为 cmd 添加一段启动脚本,使得每次打开新的命令提示符窗口或切换目录时,自动更新 fnm 的环境变量,从而让 fnm 正常工作。然而,这种启动脚本仅对用户手动启动的 cmd 生效,而对于通过 child_process.exec 启动的 cmd,这些脚本并不会被执行。因此,尽管在手动打开的 cmd 中 npm 可以正常运行,但在子进程中依然无法识别 npm 命令。
至此我已尝试过多种方法都无济于事。
失败案例:
- 按照官方文档配置脚本
- 在
child_process.exec执行npm前显式运行启动脚本 - 通过在注册表写入启动脚本
- ......不一一列举,如有成功案例,希望大佬能分享一下
最终,我决定放弃在 cmd 中解决这个问题,转而让子进程直接使用 powershell 来执行 npm 命令。
当我加上shell: 'powershell.exe'后,启动项目,成功运行!
其他
在排查问题过程中,我发现子进程打印中文会出现乱码现象,以下方法能够解决
- 安装依赖包
pnpm i iconv-lite
- 配置
const { exec } = require('child_process');
const iconv = require('iconv-lite');
const encoding = 'cp936';
const binaryEncoding = 'binary';
exec(
'xxx', {
cwd: __dirname, // 切换目录到当前项目,必须
encoding: 'binaryEncoding',
env: process.env,
shell: 'powershell.exe'
},
(error, stdout, stderr) => {
console.log(iconv.decode(new Buffer(stderr, binaryEncoding), encoding));
})
以上就是我在 HBuilderX 创建的 uniapp 项目中配置 UnoCSS 的经历。
如果在配置过程中发现任何问题,或者文章中有不准确的地方,欢迎在评论区指正和讨论。我会尽力解答大家的疑问,并不断完善这篇文章。
感谢阅读!如果你觉得这篇文章对你有帮助,欢迎点赞、收藏或分享给更多有需要的开发者。