taro小程序支持scoped CSS
taro在使用<style scoped>时在h5正常,但是由于小程序不支持[data-v-*]选择器,所以样式会失效。
官方推荐是使用cssModules。我都用vue了,还让我用cssModules那套,非得让我不优雅?
虽然官方支持style scoped也有提上开发日程,但是感觉短期内是没法实现了。只能自己搞一个阉割版了。
解决思路
首先h5我们是不需要修改的。主要修改的是小程序。
由于小程序端的page是样式隔离的。所以我们只要在小程序端不要生成[data-v-*],基本就能满足我们基本需求。
但是如果page内包含了组件,组件里面也有<style scoped>且和page的样式冲突,则需要特殊处理。
所以这个方案并不是一个完善的解决方案,但是基本满足需求,不会因为写了<style scoped>在小程序端连样式都没有。
具体实现
首先taro依赖的是vue-loader对vue文件进行编译。在vue-loader的源码找到style是根据scoped判断是否加[data-v-*]的。
https://github.com/vuejs/vue-loader/blob/8357e071c45e77de0889a9feedf2079a327f69d4/src/stylePostLoader.ts#L17
import * as qs from 'querystring'
import type { LoaderDefinitionFunction } from 'webpack'
import { compiler } from './compiler'
const { compileStyle } = compiler
// This is a post loader that handles scoped CSS transforms.
// Injected right before css-loader by the global pitcher (../pitch.js)
// for any <style scoped> selection requests initiated from within vue files.
const StylePostLoader: LoaderDefinitionFunction = function (source, inMap) {
const query = qs.parse(this.resourceQuery.slice(1))
const { code, map, errors } = compileStyle({
source: source as string,
filename: this.resourcePath,
id: `data-v-${query.id}`,
map: inMap as any,
scoped: !!query.scoped,
trim: true,
isProd: this.mode === 'production' || process.env.NODE_ENV === 'production',
})
if (errors.length) {
this.callback(errors[0])
} else {
this.callback(null, code, map as any)
}
}
export default StylePostLoader
接着在本地的note_modules找到这个文件编译后的文件,并修改scoped的值,根据taro的环境变量,如果不是h5则不启用scoped
node_modules/vue-loader/dist/stylePostLoader.js
- scoped: !!query.scoped,
+ scoped: (process.env.TARO_ENV && process.env.TARO_ENV !== 'h5')?false:!!query.scoped,
改完后参考 https://www.iceolive.com/#/detail/g0dpiG 的操作使用patch-package导出补丁。
为了避免后续升级时补丁不生效,最好在package.json中锁定vue-loader的版本号。 等后续taro支持scoped CSS时,再将此代码进行回滚。
2023-11-04更新
今天找到了更好的思路
判断是否小程序端,若是则
- 1.将
style scoped生成的style从.example[data-v-f3f3eg9]改成.example.data-v-f3f3eg9
源码位置:@vue/compiler-sfc/dist/compiler-sfc.cjs.js - 2.在vue
setScopeId时,改成添加class。
源码位置:@vue/runtime-dom/dist/runtime-dom.esm-bundler.js