uniapp.ts 3.6 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1 2 3 4 5 6 7 8 9
import { extend } from '@vue/shared'
import { rule, Rule, Declaration, Plugin } from 'postcss'
import selectorParser from 'postcss-selector-parser'
import {
  createRpx2Unit,
  defaultRpx2Unit,
  isBuiltInComponent,
  COMPONENT_SELECTOR_PREFIX,
} from '@dcloudio/uni-shared'
10
import { parseRpx2UnitOnce } from '../../json/manifest'
fxy060608's avatar
fxy060608 已提交
11 12 13 14 15 16 17 18

interface UniAppCssProcessorOptions {
  page?: string
  unit?: string // 目标单位,默认rem
  unitRatio?: number // 单位转换比例,默认10/320
  unitPrecision?: number // 单位精度,默认5
}

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

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,
35 36
  state: { bg: boolean },
  { rewriteTag }: TransformOptions
fxy060608's avatar
fxy060608 已提交
37 38 39 40
) {
  if (selector.type !== 'tag') {
    return
  }
41

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

function createBodyBackgroundRule(origRule: Rule) {
  const bgDecls: Declaration[] = []
  origRule.walkDecls((decl) => {
    if (BG_PROPS.indexOf(decl.prop) !== -1) {
      bgDecls.push(decl.clone())
    }
  })
  if (bgDecls.length) {
    origRule.after(rule({ selector: 'body' }).append(bgDecls))
  }
}

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

interface TransformOptions {
  rewriteTag: RewriteTag
}

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

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