const fs = require('node:fs') const path = require('node:path') const { spawnSync } = require('node:child_process') const runner = require.resolve('@tarojs/webpack5-runner') const postcss = require(require.resolve('postcss', { paths: [runner] })) const parseSelector = require(require.resolve('postcss-selector-parser', { paths: [runner] })) const dist = path.resolve(__dirname, '../dist') function collect(folder) { return fs.readdirSync(folder, { withFileTypes: true }).flatMap(entry => { const file = path.join(folder, entry.name) return entry.isDirectory() ? collect(file) : file.endsWith('.wxss') ? [file] : [] }) } function validateWxss(css, label) { postcss.parse(css).walkRules(rule => { if (rule.parent.type === 'atrule' && /keyframes$/i.test(rule.parent.name)) return parseSelector(selectors => selectors.walkUniversals(() => { throw new Error(`${label}:WXSS 不支持通配选择器 ${rule.selector}`) })).processSync(rule.selector) parseSelector(selectors => selectors.walkPseudos(pseudo => { if (/^:(?:first|last|nth|only)-(?:child|of-type)$/.test(pseudo.value) && (!pseudo.prev() || pseudo.prev().type === 'combinator')) { throw new Error(`${label}:WXSS 结构伪类前需明确元素或类名 ${rule.selector}`) } })).processSync(rule.selector) }) } function main() { if (!fs.existsSync(path.join(dist, 'app.wxss'))) throw new Error('请先构建微信小程序') const files = collect(dist) for (const file of files) validateWxss(fs.readFileSync(file, 'utf8'), path.relative(dist, file)) console.log(`WXSS 选择器兼容检查通过:${files.length} 个文件`) const compiler = process.env.WECHAT_WXSS_COMPILER || '/Applications/wechatwebdevtools.app/Contents/Resources/app.asar.unpacked/node_modules/wcc-exec/wcsc' if (!fs.existsSync(compiler)) { if (process.env.WECHAT_WXSS_COMPILER) throw new Error('指定的微信 WXSS 编译器不存在') console.warn('未找到微信原生 WXSS 编译器:本次仅完成静态检查,仍需开发者工具编译验收。可设置 WECHAT_WXSS_COMPILER。') } else { // The native compiler resolves @import from its supplied file collection. const result = spawnSync(compiler, ['-lc', '-pc', String(files.length), ...files.map(file => `./${path.relative(dist, file)}`)], { cwd: dist, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 }) if (result.error) throw result.error if (result.status !== 0) throw new Error(`微信原生编译失败:${result.stderr.slice(0, 3000)}`) console.log(`微信原生 WXSS 编译通过:${files.length} 个文件`) } } module.exports = { validateWxss } if (require.main === module) main()