#!/usr/bin/env node /** * Postinstall fix: patch remove-scoped.js to guard unsafe `.spaces` access. * * Root cause: remove-scoped.js in @dcloudio/vue-cli-plugin-uni accesses * `selector.first.spaces.before` without checking if `selector.first` exists. * When postcss-selector-parser produces an empty selector (e.g. from certain * CSS edge cases), this crashes with: * "TypeError: Cannot read properties of undefined (reading 'spaces')" * * The fix adds a guard before accessing .spaces on selector.first. * * Patches BOTH: * 1. Project local node_modules (for vue-cli-service / npm build) * 2. HBuilderX bundled uniapp-cli (for HBuilderX build) */ const fs = require('fs'); const path = require('path'); /** Find all remove-scoped.js files to patch */ function findRemoveScopedFiles() { const files = []; // 1. Project local node_modules const localPath = path.join(__dirname, 'node_modules', '@dcloudio', 'vue-cli-plugin-uni', 'packages', '@vue', 'component-compiler-utils', 'dist', 'stylePlugins', 'remove-scoped.js'); if (fs.existsSync(localPath)) files.push(localPath); // 2. HBuilderX bundled uniapp-cli (common install paths) const hbxPaths = [ 'E:\\develop\\HBuilderX\\plugins\\uniapp-cli', 'C:\\Program Files\\HBuilderX\\plugins\\uniapp-cli', 'C:\\Program Files (x86)\\HBuilderX\\plugins\\uniapp-cli', path.join(process.env.LOCALAPPDATA || '', 'Programs', 'HBuilderX', 'plugins', 'uniapp-cli'), ]; for (const base of hbxPaths) { const hbxPath = path.join(base, 'node_modules', '@dcloudio', 'vue-cli-plugin-uni', 'packages', '@vue', 'component-compiler-utils', 'dist', 'stylePlugins', 'remove-scoped.js'); if (fs.existsSync(hbxPath)) files.push(hbxPath); } return files; } /** Patch a single remove-scoped.js file */ function patchFile(filePath) { let content = fs.readFileSync(filePath, 'utf8'); // Fix: selector.first.spaces.before = ''; → if (selector.first) { ... } if (content.includes("selector.first.spaces.before = '';")) { content = content.replace( /selector\.first\.spaces\.before = '';/, "if (selector.first) { selector.first.spaces.before = ''; }" ); fs.writeFileSync(filePath, content, 'utf8'); console.log(` ✅ ${filePath}`); return true; } else if (content.includes("if (selector.first) { selector.first.spaces.before = ''; }")) { console.log(` ⏭️ ${filePath} (already patched)`); return true; } else { console.log(` ❌ ${filePath} (unexpected format)`); return false; } } // Main const files = findRemoveScopedFiles(); if (files.length === 0) { console.log('remove-scoped.js not found in any location, skipping patch'); process.exit(0); } console.log(`Found ${files.length} remove-scoped.js to patch:`); let patched = 0; for (const f of files) { if (patchFile(f)) patched++; } console.log(`Done: ${patched}/${files.length} patched`);