index.js 7.8 KB
Newer Older
fxy060608's avatar
fxy060608 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
if (process.env.UNI_USING_V3) {
  module.exports = require('./index.v3.js')
} else {
  const postcss = require('postcss')
  const selectorParser = require('postcss-selector-parser')
  const valueParser = require('postcss-value-parser')

  const {
    getPlatformCssVars
  } = require('@dcloudio/uni-cli-shared')

  const CSS_TAGS = require('./tags')
  const {
    unit,
    walk
  } = valueParser

  const defaultOpts = {
    px: false
  }

  const cssVars = getPlatformCssVars()

  const transformSelector = (complexSelector, transformer) => {
    return selectorParser(transformer).processSync(complexSelector)
  }

fxy060608's avatar
fxy060608 已提交
28
  const parseWord = function (node, opts) {
fxy060608's avatar
fxy060608 已提交
29 30 31 32 33 34
    const pair = unit(node.value)
    if (pair) {
      const num = Number(pair.number)
      let u = pair.unit.toLowerCase()
      if (u === 'px' && process.UNI_TRANSFORM_PX) { // TODO px 转换为 upx
        u = 'upx'
fxy060608's avatar
fxy060608 已提交
35
      }
fxy060608's avatar
fxy060608 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48
      if (process.env.UNI_PLATFORM === 'h5') {
        if (u === 'upx' || u === 'rpx') {
          node.value = `%?${num}?%`
        }
      } else {
        if (u === 'upx') {
          node.value = num + 'rpx'
        }
        // fixed 百度目前1rpx会转换成小数点 vw,导致边框之类的显示有问题
        if (process.env.UNI_PLATFORM === 'mp-baidu') {
          if (num === 1 && (u === 'upx' || u === 'rpx')) {
            node.value = '1px'
          }
fxy060608's avatar
fxy060608 已提交
49 50 51 52
        }
      }
    }
  }
fxy060608's avatar
fxy060608 已提交
53

fxy060608's avatar
fxy060608 已提交
54
  const isInsideKeyframes = function (rule) {
fxy060608's avatar
fxy060608 已提交
55 56 57 58 59
    return (
      rule.parent && rule.parent.type === 'atrule' && /^(-\w+-)?keyframes$/.test(rule.parent.name)
    )
  }

60 61
  const tranformValue = function (value, opts) {
    return valueParser(value)
fxy060608's avatar
fxy060608 已提交
62 63 64 65 66 67 68 69 70 71 72
      .walk(node => {
        if (node.type === 'word') {
          parseWord(node, opts)
        } else if (node.type === 'function') {
          if (node.value === 'url') {
            return false
          }
          if (node.value === 'var') {
            let cssVarValue = false
            walk(node.nodes, n => {
              if (n.type === 'word') {
fxy060608's avatar
fxy060608 已提交
73
                if (Object.prototype.hasOwnProperty.call(cssVars, n.value)) { // 目前仅考虑 nodes 长度为0
fxy060608's avatar
fxy060608 已提交
74 75
                  cssVarValue = cssVars[n.value]
                }
fxy060608's avatar
fxy060608 已提交
76
              }
fxy060608's avatar
fxy060608 已提交
77 78 79 80 81 82 83
            })
            if (cssVarValue !== false) {
              node.type = 'word'
              node.value = cssVarValue
              delete node.before
              delete node.after
              delete node.nodes
fxy060608's avatar
fxy060608 已提交
84
            }
fxy060608's avatar
fxy060608 已提交
85 86 87 88 89 90 91
            return false
          } else {
            walk(node.nodes, n => {
              if (n.type === 'word') {
                parseWord(n, opts)
              }
            })
fxy060608's avatar
fxy060608 已提交
92 93
          }
        }
fxy060608's avatar
fxy060608 已提交
94 95
      })
      .toString()
fxy060608's avatar
fxy060608 已提交
96
  }
fxy060608's avatar
fxy060608 已提交
97 98 99 100 101 102 103 104 105 106 107

  const TAGS = [
    'ad',
    'audio',
    'button',
    'camera',
    'canvas',
    'checkbox',
    'checkbox-group',
    'cover-image',
    'cover-view',
Q
qiang 已提交
108
    'editor',
fxy060608's avatar
fxy060608 已提交
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
    'form',
    'functional-page-navigator',
    'icon',
    'image',
    'input',
    'label',
    'live-player',
    'live-pusher',
    'map',
    'movable-area',
    'movable-view',
    'navigator',
    'official-account',
    'open-data',
    'picker',
    'picker-view',
    'picker-view-column',
    'progress',
    'radio',
    'radio-group',
    'rich-text',
    'scroll-view',
    'slider',
    'swiper',
    'swiper-item',
    'switch',
    'text',
    'textarea',
    'video',
    'view',
    'web-view'
  ]

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

154
  let rewriteUrl
fxy060608's avatar
fxy060608 已提交
155 156 157 158
  /**
   * 转换 upx
   * 转换 px
   */
159
  const fn = function (opts) {
fxy060608's avatar
fxy060608 已提交
160 161 162 163
    opts = {
      ...defaultOpts,
      ...opts
    }
fxy060608's avatar
fxy060608 已提交
164
    return function (root, result) {
165 166 167 168 169
      if (!rewriteUrl) {
        rewriteUrl = require('@dcloudio/uni-cli-shared/lib/url-loader').rewriteUrl
      }
      rewriteUrl(root)

fxy060608's avatar
fxy060608 已提交
170 171 172 173 174 175 176 177 178 179 180
      if (process.env.UNI_PLATFORM === 'h5') {
        // Transform CSS AST here

        const bgDecls = []

        root.walkRules(rule => {
          let hasPage = false
          // Transform each rule here
          if (!isInsideKeyframes(rule)) {
            // rule.selectors == comma seperated selectors
            // a, b.c {} => ["a", "b.c"]
181
            rule.selectors = rule.selectors.map(complexSelector => {
fxy060608's avatar
fxy060608 已提交
182 183
              // complexSelector => simpleSelectors
              // "a.b#c" => ["a", ".b", "#c"]
184 185 186 187
              if (complexSelector === 'page') {
                hasPage = true
              }
              return transformSelector(complexSelector, simpleSelectors =>
fxy060608's avatar
fxy060608 已提交
188 189 190 191 192
                // only process type selector, leave alone class & id selectors
                simpleSelectors.walkTags(tag => {
                  if (tag.value === 'page') {
                    tag.value = 'uni-page-body'
                  } else if (~TAGS.indexOf(tag.value) && tag.value.substring(
fxy060608's avatar
fxy060608 已提交
193
                    0, 4) !== 'uni-') {
fxy060608's avatar
fxy060608 已提交
194 195 196 197
                    tag.value = 'uni-' + tag.value
                  }
                })
              )
198
            })
fxy060608's avatar
fxy060608 已提交
199
          }
fxy060608's avatar
fxy060608 已提交
200 201 202 203 204 205 206 207
          // handle upx unit
          rule.walkDecls(decl => {
            if (hasPage) {
              if (BG_PROPS.indexOf(decl.prop) !== -1) {
                bgDecls.push(decl.clone())
              }
            }
            // Transform each property declaration here
208
            decl.value = tranformValue(decl.value, opts)
fxy060608's avatar
fxy060608 已提交
209
          })
fxy060608's avatar
fxy060608 已提交
210 211
        })

212 213 214 215 216 217
        root.walkAtRules(rule => {
          if (rule.name === 'media') {
            rule.params = tranformValue(rule.params, opts)
          }
        })

fxy060608's avatar
fxy060608 已提交
218 219 220
        if (bgDecls.length) {
          const rule = postcss.rule({
            selector: 'body.?%PAGE?%'
fxy060608's avatar
fxy060608 已提交
221
          })
fxy060608's avatar
fxy060608 已提交
222 223
          bgDecls.forEach(decl => rule.append(decl))
          root.append(rule)
fxy060608's avatar
fxy060608 已提交
224
        }
fxy060608's avatar
fxy060608 已提交
225 226
      } else {
        root.walkRules(rule => {
fxy060608's avatar
fxy060608 已提交
227
          const selectors = transformSelector(rule.selectors.join(','), function (selectors) {
fxy060608's avatar
fxy060608 已提交
228 229 230 231 232 233
            selectors.walkUniversals(node => {
              node.parent.remove()
            })
          })
          if (!selectors) {
            return rule.remove()
fxy060608's avatar
fxy060608 已提交
234
          }
fxy060608's avatar
fxy060608 已提交
235 236 237 238 239 240 241 242
          rule.selectors = selectors.split(',')

          // handle upx unit
          rule.walkDecls(decl => {
            const raws = decl.raws
            if (raws) {
              if (raws.before && raws.before.indexOf(';') !== -1) {
                raws.before = raws.before.replace(/;/g, '')
fxy060608's avatar
fxy060608 已提交
243
              }
fxy060608's avatar
fxy060608 已提交
244 245 246 247 248
              if (raws.after && raws.after.indexOf(';') !== -1) {
                raws.after = raws.after.replace(/;/g, '')
              }
            }
            // Transform each property declaration here
249
            decl.value = tranformValue(decl.value, opts)
fxy060608's avatar
fxy060608 已提交
250
          })
fxy060608's avatar
fxy060608 已提交
251
          if (process.env.UNI_PLATFORM !== 'quickapp-native') {
252 253 254 255 256 257 258 259 260 261 262 263
            rule.selectors = rule.selectors.map(complexSelector => {
              return transformSelector(complexSelector, simpleSelectors => {
                return simpleSelectors.walkTags(tag => {
                  const k = tag.value
                  const v = CSS_TAGS[k]
                  if (v) {
                    tag.value = v === 'r'
                      ? `._${k}` : v
                  }
                })
              })
            })
fxy060608's avatar
fxy060608 已提交
264
          }
fxy060608's avatar
fxy060608 已提交
265
        })
fxy060608's avatar
fxy060608 已提交
266
      }
fxy060608's avatar
fxy060608 已提交
267
    }
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
  }

  const version = Number(require('postcss/package.json').version.split('.')[0])

  if (version < 8) {
    module.exports = postcss.plugin('postcss-uniapp-plugin', fn)
  } else {
    module.exports = function (opts) {
      return {
        postcssPlugin: 'postcss-uniapp-plugin',
        Once: fn(opts)
      }
    }

    module.exports.postcss = true
  }
Q
qiang 已提交
284
}