将使用 TypeScript / Less 的 uni SFC(.vue / .nvue)降级为 JavaScript / CSS 的 SFC。
插件在打包阶段把 lang="ts" 的 script 块与模板表达式中的 TS 语法降级为 JS,把 lang="less" 的 style 块编译为 CSS,产物中的 .vue 以降级后的源码直接输出;依赖解析、编译和产物组织仍然交给打包工具(vite / rolldown / tsdown),插件不重复造轮子。
环境要求:Node.js ≥ 18.12。
pnpm add -D @uni-helper/unplugin-uni-sfcvite.config.ts
import UnpluginUniSfc from '@uni-helper/unplugin-uni-sfc/vite'
export default defineConfig({
plugins: [UnpluginUniSfc()],
})插件只接管构建产物;dev server 下的 .vue 仍交给其它插件(如 @vitejs/plugin-vue)处理。
tsdown.config.ts / rolldown 配置
import UnpluginUniSfc from '@uni-helper/unplugin-uni-sfc/rolldown'
export default defineConfig({
plugins: [UnpluginUniSfc()],
})<style lang="less"> 会在构建时用 less 编译为 CSS:变量替换、嵌套展开、@import 内联(相对 .vue 解析),并移除 lang="less" 标记,产物中的 .vue 不再依赖 less。
- sass / scss 不需要处理:uni-app 的编译器自带 sass,
lang="scss"/lang="sass"原样保留; - 其它预处理器(stylus 等)不在降级范围内,同样原样保留;
- less 按可选依赖加载:只有 SFC 里出现
lang="less"时才会用到,未安装时构建会报错并提示安装(pnpm add -D less); - 带
src的外部样式块不处理(与 script 块的规则一致):它们不会被降级,也不会进入产物,请改为内联样式或自行编译为 CSS。
SFC 脚本里的样式引用(import './styles/global.less')由打包工具的 CSS 管线编译(tsdown 需要 @tsdown/css,vite 自带),插件负责处理产物 .vue 里对应的引用:
- CSS 管线在渲染阶段已产出对应的 CSS 资产时(vite
cssCodeSplit: true),引用回填成 CSS 资产的路径,下游构建会正常加载它; - 资产要到构建收尾才产出时(如 tsdown 的
@tsdown/css),整句import从产物中移除(与打包工具对 JS 导入方的处理一致),并给出告警——编译出的 CSS 仍会作为资产输出,需要时自行引入。
产物中的 .vue 不会引用不存在的文件,也不会把 .less 引用留给不支持 less 的下游。
本插件本质是语言降级(TS → JS),不改模块语法:产出的 .vue 资产本身就是 ESM 源码(import / export),产物中的 JS 也需要以 ESM 引用这些 .vue 文件,因此只支持 ESM 产物格式。
- 支持:
esm(rolldown / tsdown)、es(rollup / vite);未设置format时打包工具的默认值也是 ESM - 不支持:
cjs、iife、umd、amd等
使用非 ESM 格式时,插件会在构建时警告并保持原样:
.vue模块不会换回.vue文件,引用也不会回填,JS 按打包工具的默认行为输出;- 降级后的
.vue源码仍会作为资产输出,但产物中的 JS 不会引用它们。
本插件不做 uni-app 条件编译(#ifdef / #ifndef / #endif)的预处理:SFC(script、模板、style)中出现条件编译指令时,构建会直接报错中断,而不是把指令原样保留进产物。
请用 if 分支判断替代条件编译,推荐 @uni-helper/uni-env:
import { isH5 } from '@uni-helper/uni-env'
if (isH5) {
// 仅 H5 执行
}uni-env 提供各平台的判断值(isH5、isMpWeixin、isApp 等),读取的是 uni-app 构建期注入的环境值,经 Vite define 静态替换成字面量;不想引入依赖时,也可以直接写 if (process.env.UNI_PLATFORM === 'h5') { ... }。
.vue 必须一个模块一个产物才能在生成阶段换回 .vue 文件。插件会在 ESM 产物下自动打开 preserveModules(对应 tsdown unbundle: true),无需手动配置。
.vue 在产物中的位置与它的 JS 模块同位(只把扩展名换回 .vue / .nvue),镜像基准完全由打包工具决定:rolldown / rollup 按 preserveModules 的规则推导,tsdown unbundle 下对应 root 配置。插件不拥有任何产物形态的配置,也没有可配置项——它本质上是做降级处理,产物组织全部交给打包工具。