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)
|
}
|
|
const parseWord = function (node, opts) {
|
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'
|
}
|
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'
|
}
|
}
|
}
|
}
|
}
|
|
const isInsideKeyframes = function (rule) {
|
return (
|
rule.parent && rule.parent.type === 'atrule' && /^(-\w+-)?keyframes$/.test(rule.parent.name)
|
)
|
}
|
|
const tranformValue = function (value, opts) {
|
return valueParser(value)
|
.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') {
|
if (Object.prototype.hasOwnProperty.call(cssVars, n.value)) { // 目前仅考虑 nodes 长度为0
|
cssVarValue = cssVars[n.value]
|
}
|
}
|
})
|
if (cssVarValue !== false) {
|
node.type = 'word'
|
node.value = cssVarValue
|
delete node.before
|
delete node.after
|
delete node.nodes
|
}
|
return false
|
} else {
|
walk(node.nodes, n => {
|
if (n.type === 'word') {
|
parseWord(n, opts)
|
}
|
})
|
}
|
}
|
})
|
.toString()
|
}
|
|
const TAGS = [
|
'ad',
|
'audio',
|
'button',
|
'camera',
|
'canvas',
|
'checkbox',
|
'checkbox-group',
|
'cover-image',
|
'cover-view',
|
'editor',
|
'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'
|
]
|
|
let rewriteUrl
|
/**
|
* 转换 upx
|
* 转换 px
|
*/
|
const fn = function (opts) {
|
opts = {
|
...defaultOpts,
|
...opts
|
}
|
return function (root, result) {
|
if (!rewriteUrl) {
|
rewriteUrl = require('@dcloudio/uni-cli-shared/lib/url-loader').rewriteUrl
|
}
|
rewriteUrl(root)
|
|
if (process.env.UNI_PLATFORM === 'h5') {
|
// Transform CSS AST here
|
|
root.walkRules(rule => {
|
let hasPage = false
|
// Transform each rule here
|
if (!isInsideKeyframes(rule)) {
|
// rule.selectors == comma seperated selectors
|
// a, b.c {} => ["a", "b.c"]
|
rule.selectors = rule.selectors.map(complexSelector => {
|
// complexSelector => simpleSelectors
|
// "a.b#c" => ["a", ".b", "#c"]
|
if (complexSelector === 'page') {
|
hasPage = true
|
}
|
return transformSelector(complexSelector, simpleSelectors =>
|
// 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(
|
0, 4) !== 'uni-') {
|
tag.value = 'uni-' + tag.value
|
}
|
})
|
)
|
})
|
}
|
const bgDecls = []
|
// handle upx unit
|
rule.walkDecls(decl => {
|
if (hasPage) {
|
if (BG_PROPS.indexOf(decl.prop) !== -1) {
|
bgDecls.push(decl.clone())
|
}
|
}
|
// Transform each property declaration here
|
decl.value = tranformValue(decl.value, opts)
|
})
|
|
// handle body background rule
|
if (bgDecls.length) {
|
const bodyRule = postcss.rule({
|
selector: 'body.?%PAGE?%'
|
})
|
bgDecls.forEach(decl => bodyRule.append(decl))
|
rule.after(bodyRule)
|
}
|
})
|
|
root.walkAtRules(rule => {
|
if (rule.name === 'media') {
|
rule.params = tranformValue(rule.params, opts)
|
}
|
})
|
} else {
|
root.walkRules(rule => {
|
const selectors = transformSelector(rule.selectors.join(','), function (selectors) {
|
selectors.walkUniversals(node => {
|
node.parent.remove()
|
})
|
})
|
if (!selectors) {
|
return rule.remove()
|
}
|
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, '')
|
}
|
if (raws.after && raws.after.indexOf(';') !== -1) {
|
raws.after = raws.after.replace(/;/g, '')
|
}
|
}
|
// Transform each property declaration here
|
decl.value = tranformValue(decl.value, opts)
|
})
|
if (process.env.UNI_PLATFORM !== 'quickapp-native') {
|
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
|
}
|
})
|
})
|
})
|
}
|
})
|
}
|
}
|
}
|
|
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
|
}
|
}
|