UNPKG

@roadup/smi

Version:

小程序打包器

274 lines (263 loc) 15.7 kB
const wxml = require("wxml") const babel = require("@babel/core") const types = require("@babel/types") const evnReplace = require("./envReplacePlugin") const Resource = require("./Resource") const { NULL } = require("node-sass") module.exports = class WXMLResource extends Resource { constructor(filePath) { super(filePath) this.pages = new Set() !this.notFound && this.complier() } complier() { const ast = wxml.parse(this.source.toString()) const self = this try { // @ts-ignore wxml.traverse(ast, (node, parent) => { if (node.type === 1) { // element node if (typeof node.attributes["wx:if"] !== "undefined") { let rr = NULL const match = node.attributes["wx:if"].match(/^{{(.+?)}}$/) if (match && match[1]) { const code = babel.transformSync(match[1], { plugins: [evnReplace, "minify-constant-folding"] }).code try { // eslint-disable-next-line no-eval rr = eval(code) } catch (error) { // console.error(error) } } else { rr = !!node.attributes["wx:if"] } if (rr === true) { let remains let index = -1 if (parent) { index = parent.childNodes.findIndex(n => n === node) remains = parent.childNodes } else { index = ast.findIndex(n => n === node) remains = ast } delete node.attributes["wx:if"] let deleteCount = 0 for (let i = index + 1; i < remains.length; i++) { const next = remains[i] if (!next) break if (next.type !== 1) if (next.type === 3 && next.textContent.trim() === "") { deleteCount++ continue } else { break } if (next.attributes["wx:if"]) break if (!next.attributes["wx:elif"] && !next.attributes["wx:else"]) break deleteCount++ // remove wx:elif and wx:else } remains.splice(index + 1, deleteCount) } else if (rr === false) { let remains let index = -1 if (parent) { index = parent.childNodes.findIndex(n => n === node) parent.childNodes.splice(index, 1) remains = parent.childNodes } else { index = ast.findIndex(n => n === node) ast.splice(index, 1) remains = ast } if (remains[index + 1] && remains[index + 1].type === 1) { if (remains[index + 1].attributes["wx:elif"]) { remains[index + 1].attributes["wx:if"] = remains[index + 1].attributes["wx:elif"] delete remains[index + 1].attributes["wx:elif"] } if (remains[index + 1].attributes["wx:else"]) { delete remains[index + 1].attributes["wx:else"] } } return } else { } } if (typeof node.attributes["wx:elif"] !== "undefined") { let rr = NULL const match = node.attributes["wx:elif"].match(/^{{(.+?)}}$/) if (match && match[1]) { const code = babel.transformSync(match[1], { plugins: [evnReplace, "minify-constant-folding"] }).code try { // eslint-disable-next-line no-eval rr = eval(code) } catch (error) { // console.error(error) } } else { rr = !!node.attributes["wx:elif"] } if (rr === true) { let remains let index = -1 if (parent) { index = parent.childNodes.findIndex(n => n === node) remains = parent.childNodes } else { index = ast.findIndex(n => n === node) remains = ast } node.attributes["wx:else"] = true delete node.attributes["wx:elif"] let deleteCount = 0 for (let i = index + 1; i < remains.length; i++) { const next = remains[i] if (!next) break if (next.type !== 1) if (next.type === 3 && next.textContent === "\n") { deleteCount++ continue } else { break } if (next.attributes["wx:if"]) break if (!next.attributes["wx:elif"] && !next.attributes["wx:else"]) break deleteCount++ // remove wx:elif and wx:else } remains.splice(index + 1, deleteCount) } else if (rr === false) { let index = -1 if (parent) { index = parent.childNodes.findIndex(n => n === node) parent.childNodes.splice(index, 1) } else { index = ast.findIndex(n => n === node) ast.splice(index, 1) } return } } Object.keys(node.attributes).forEach(attr => { // console.log(attr, node.attributes[attr]) if (typeof node.attributes[attr] === "string") { let note = false node.attributes[attr] = node.attributes[attr].replace(/{{(.+?)}}/g, (_, snp) => { try { note = true const r = babel.transformSync(snp, { plugins: [evnReplace, { visitor: { StringLiteral(path) { if (attr === "src") if (!/^https?:\/\//.test(path.node.value)) { if (path.node.value) { const index = path.node.value.indexOf("?") let value = path.node.value if (index > 0) { value = value.slice(0, index) } self.resolve(value, self.requires) } else { console.log("[引用错误]".red, self.path.replace(process.cwd(), "."), "src=\"" + path.node.value + "\"") } } if (attr === "url") if (!/^https?:\/\//.test(path.node.value)) { if (path.node.value) { const index = path.node.value.indexOf("?") let value = path.node.value if (index > 0) { value = value.slice(0, index) } self.resolve(value, self.pages) } else { console.log("[引用错误]".red, self.path.replace(process.cwd(), "."), "url=\"" + path.node.value + "\"") } } }, CallExpression(path) { // @ts-ignore if (path.node.callee.name === "page") { // @ts-ignore self.resolve(path.node.arguments[0].value, self.pages) // @ts-ignore path.replaceWith(types.valueToNode(path.node.arguments[0].value.replace(/^@/, "/"))) return } // @ts-ignore if (path.node.callee.name === "file") { // @ts-ignore const file = path.node.arguments[0].value // @ts-ignore path.replaceWith(types.valueToNode(file.replace(/^@/, "/"))) self.resolve(file, self.requires) return } } } }] }) return "{{" + r.code + "}}" } catch (error) { console.error("[语法警告]", ("<" + node.tagName + " ... " + attr + "=\"" + node.attributes[attr] + (node.selfClosing ? "\"/>" : "\"><" + node.tagName + ">")).blue, this.path.replace(process.cwd(), ".")) return "{{" + snp + "}}" } }).replace(/"/g, "'").replace(/;}}/g, "}}") if (!note) { if (attr === "src") if (!/^https?:\/\//.test(node.attributes[attr])) { if (node.attributes[attr]) { const index = node.attributes[attr].indexOf("?") let value = node.attributes[attr] if (index > 0) { value = value.slice(0, index) } this.resolve(value, this.requires) node.attributes[attr] = node.attributes[attr].replace(/^@/, "/") } else { console.log("[引用错误] ".red, self.path, "src=\"" + node.attributes[attr] + "\"") } } if (attr === "url") if (!/^https?:\/\//.test(node.attributes[attr])) { if (node.attributes[attr]) { const index = node.attributes[attr].indexOf("?") let value = node.attributes[attr] if (index > 0) { value = value.slice(0, index) } this.resolve(value, this.pages) node.attributes[attr] = node.attributes[attr].replace(/^@/, "/") } else { console.log("[引用错误] ".red, self.path, "url=\"" + node.attributes[attr] + "\"") } } } } if (attr === "class" && process.env.APP_NAME) node.attributes[attr] = process.env.APP_NAME + " " + node.attributes[attr] }) if (node.tagName === "style") node.childNodes = [] } if (node.type === 3 && node.textContent.replace(/^.$/g, "")) { // text node node.textContent = node.textContent.replace(/{{(.+?)}}/, (_, snp) => { const r = babel.transformSync(snp, { plugins: [evnReplace] }) return "{{" + r.code + "}}" }).replace(/"/g, "'").replace(/;}}/g, "}}") } }) // @ts-ignore this.content = wxml.serialize(ast) } catch (error) { console.log("编译失败".red, this.path) console.log(error) process.exit(0) } } }