taro小程序支持scoped CSS

返回
Author Avatar
钢翼
2023-09-29
编程
119

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.在vuesetScopeId时,改成添加class。
    源码位置:@vue/runtime-dom/dist/runtime-dom.esm-bundler.js