@mpxjs/webpack-plugin
Version:
mpx compile core
165 lines (151 loc) • 4.15 kB
JavaScript
/**
* 按平台条件编译CSS,用法如下:
* @type {postcss.Plugin<any>}
*/
// `
// /*
// @mpx-if (
// __mpx_mode__ === 'wx' ||
// __mpx_mode__ === 'qq'
// )
// */
// /* @mpx-if (__mpx_mode__ === 'wx') */
// wx {
// background: green;
// }
// /*
// @mpx-elif (__mpx_mode__ === 'qq')
// */
// qq {
// background: black;
// }
// /* @mpx-endif */
// /* @mpx-if (__mpx_mode__ === 'swan') */
// swan {
// background: cyan;
// }
// /* @mpx-endif */
// always {
// background: white;
// }
// /*
// @mpx-else
// */
// other {
// /* @mpx-if (__mpx_mode__ === 'swan') */
// background: blue;
// /* @mpx-else */
// background: red;
// /* @mpx-endif */
// }
// /*
// @mpx-endif
// */
// `
module.exports = (options = {}) => {
const { defs } = options
const defKeys = Object.keys(defs)
const defValues = defKeys.map((key) => {
return defs[key]
})
function evalExp (exp) {
/* eslint-disable no-new-func */
const f = new Function(...defKeys, `return ${exp};`)
return f(...defValues)
}
function isIfStart (content) {
return /@mpx-if/.test(content)
}
function isElseIf (content) {
return /@mpx-elif/.test(content)
}
function isElse (content) {
return /@mpx-else/.test(content)
}
function isEndIf (content) {
return /@mpx-endif/.test(content)
}
function parseCondition (regex, content) {
const exp = regex.exec(content)[1].trim()
const shouldRemove = !evalExp(exp)
return {
shouldRemove,
children: []
}
}
function parseIf (content) {
return parseCondition(/@mpx-if[^(]*?\(([\s\S]*)\)/, content)
}
function parseElseIf (content) {
return parseCondition(/@mpx-elif[^(]*?\(([\s\S]*)\)/, content)
}
return {
postcssPlugin: 'conditional-strip',
Once (root) {
const condsStacks = []
const currentConds = []
let curDepth = -1
root.walk(node => {
let isKeyword = false
if (node.type === 'comment') {
const { text } = node
if (isIfStart(text)) {
isKeyword = true
const cond = parseIf(text)
curDepth++
const parentCond = currentConds[curDepth - 1]
if (parentCond && parentCond.shouldRemove) {
cond.shouldRemove = true
}
cond.children.push(node)
condsStacks.push({
if: cond
})
currentConds[curDepth] = cond
} else if (isElseIf(text)) {
isKeyword = true
const cond = parseElseIf(text)
const parentCond = currentConds[curDepth - 1]
if (parentCond && parentCond.shouldRemove) {
cond.shouldRemove = true
}
cond.children.push(node)
condsStacks[curDepth].elif = cond
currentConds[curDepth] = cond
} else if (isElse(text)) {
isKeyword = true
const curConds = condsStacks[curDepth]
const cond = {
shouldRemove: !(curConds.if.shouldRemove && (!curConds.elif || curConds.elif.shouldRemove)),
children: [node]
}
const parentCond = currentConds[curDepth - 1]
if (parentCond && parentCond.shouldRemove) {
cond.shouldRemove = true
}
condsStacks[curDepth].else = cond
currentConds[curDepth] = cond
} else if (isEndIf(text)) {
isKeyword = true
const curConds = condsStacks.pop()
Object.keys(curConds).forEach(k => {
curConds[k].children.forEach(node => {
node.remove()
})
})
currentConds.pop()
curDepth--
node.remove()
}
}
if (!isKeyword) {
const curCond = currentConds[curDepth]
if (curCond && curCond.shouldRemove) {
curCond.children.push(node)
}
}
})
}
}
}
module.exports.postcss = true