uniapp.ts 3.4 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1
import { extend } from '@vue/shared'
fxy060608's avatar
fxy060608 已提交
2
import type { Rule, Declaration, Plugin } from 'postcss'
fxy060608's avatar
fxy060608 已提交
3 4 5 6 7 8 9 10
import selectorParser from 'postcss-selector-parser'
import {
  createRpx2Unit,
  defaultRpx2Unit,
  isBuiltInComponent,
  COMPONENT_SELECTOR_PREFIX,
} from '@dcloudio/uni-shared'

fxy060608's avatar
fxy060608 已提交
11
export interface UniAppCssProcessorOptions {
fxy060608's avatar
fxy060608 已提交
12 13 14 15 16
  unit?: string // 目标单位,默认rem
  unitRatio?: number // 单位转换比例,默认10/320
  unitPrecision?: number // 单位精度,默认5
}

17
const defaultUniAppCssProcessorOptions = extend({}, defaultRpx2Unit)
fxy060608's avatar
fxy060608 已提交
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

const BG_PROPS = [
  'background',
  'background-clip',
  'background-color',
  'background-image',
  'background-origin',
  'background-position',
  'background-repeat',
  'background-size',
  'background-attachment',
]

function transform(
  selector: selectorParser.Node,
33 34
  state: { bg: boolean },
  { rewriteTag }: TransformOptions
fxy060608's avatar
fxy060608 已提交
35 36 37 38
) {
  if (selector.type !== 'tag') {
    return
  }
39

fxy060608's avatar
fxy060608 已提交
40
  const { value } = selector
41 42 43
  selector.value = rewriteTag(value)
  if (value === 'page' && selector.value === 'uni-page-body') {
    state.bg = true
fxy060608's avatar
fxy060608 已提交
44 45 46 47 48 49 50 51 52 53 54
  }
}

function createBodyBackgroundRule(origRule: Rule) {
  const bgDecls: Declaration[] = []
  origRule.walkDecls((decl) => {
    if (BG_PROPS.indexOf(decl.prop) !== -1) {
      bgDecls.push(decl.clone())
    }
  })
  if (bgDecls.length) {
fxy060608's avatar
fxy060608 已提交
55
    const { rule } = require('postcss')
fxy060608's avatar
fxy060608 已提交
56 57 58 59
    origRule.after(rule({ selector: 'body' }).append(bgDecls))
  }
}

60 61 62 63 64 65 66
type RewriteTag = (tag: string) => string

interface TransformOptions {
  rewriteTag: RewriteTag
}

function walkRules(options: TransformOptions) {
fxy060608's avatar
fxy060608 已提交
67 68 69
  return (rule: Rule) => {
    const state = { bg: false }
    rule.selector = selectorParser((selectors) =>
70
      selectors.walk((selector) => transform(selector, state, options))
fxy060608's avatar
fxy060608 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
    ).processSync(rule.selector)
    state.bg && createBodyBackgroundRule(rule)
  }
}

function walkDecls(rpx2unit: ReturnType<typeof createRpx2Unit>) {
  return (decl: Declaration) => {
    const { value } = decl
    if (value.indexOf('rpx') === -1 && value.indexOf('upx') === -1) {
      return
    }
    decl.value = rpx2unit(decl.value)
  }
}

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
const baiduTags: Record<string, string> = {
  navigator: 'nav',
}

function rewriteBaiduTags(tag: string) {
  return baiduTags[tag] || tag
}

function rewriteUniH5Tags(tag: string) {
  if (tag === 'page') {
    return 'uni-page-body'
  }
  if (isBuiltInComponent(tag)) {
    return COMPONENT_SELECTOR_PREFIX + tag
  }
  return tag
}

function rewriteUniAppTags(tag: string) {
  if (tag === 'page') {
    return 'body'
  }
  if (isBuiltInComponent(tag)) {
    return COMPONENT_SELECTOR_PREFIX + tag
  }
  return tag
}

const transforms: Record<string, RewriteTag | undefined> = {
  h5: rewriteUniH5Tags,
  app: rewriteUniAppTags,
  'mp-baidu': rewriteBaiduTags,
}

fxy060608's avatar
fxy060608 已提交
120
const uniapp = (opts?: UniAppCssProcessorOptions) => {
121 122
  const platform = process.env.UNI_PLATFORM
  const { unit, unitRatio, unitPrecision } = extend(
fxy060608's avatar
fxy060608 已提交
123 124
    {},
    defaultUniAppCssProcessorOptions,
fxy060608's avatar
fxy060608 已提交
125
    opts
fxy060608's avatar
fxy060608 已提交
126 127 128 129 130 131 132 133
  )
  const rpx2unit = createRpx2Unit(unit, unitRatio, unitPrecision)
  return {
    postcssPlugin: 'uni-app',
    prepare() {
      return {
        OnceExit(root) {
          root.walkDecls(walkDecls(rpx2unit))
134 135 136 137 138 139 140 141
          const rewriteTag = transforms[platform]
          if (rewriteTag) {
            root.walkRules(
              walkRules({
                rewriteTag,
              })
            )
          }
fxy060608's avatar
fxy060608 已提交
142 143 144 145 146 147 148
        },
      }
    },
  } as Plugin
}
uniapp.postcss = true
export default uniapp