diff --git a/codepress-swc-plugin/src/lib.rs b/codepress-swc-plugin/src/lib.rs index e9ccdfb..d79cd1d 100644 --- a/codepress-swc-plugin/src/lib.rs +++ b/codepress-swc-plugin/src/lib.rs @@ -2122,12 +2122,15 @@ impl CodePressTransform { // Build the config object: window.__CODEPRESS_CONFIG__ = { repo: "...", branch: "..." } // Uses Object.assign to avoid overwriting if somehow multiple modules try to set it - // Also injects and tags - // for content script detection (content scripts run in isolated JS context) + // Also injects a hidden div with data attributes for content script detection + // (content scripts run in isolated JS context and can't access window.__CODEPRESS_CONFIG__) let escaped_repo = repo.replace('\\', "\\\\").replace('"', "\\\""); let escaped_branch = branch.replace('\\', "\\\\").replace('"', "\\\""); + // Inject into document.body (not head) to avoid conflicts with React Portal-based libraries + // (like @react-oauth/google) which manipulate head and cause "removeChild" errors. + // Using setTimeout(0) to defer DOM manipulation until after React's render cycle. let js = format!( - "try{{if(typeof window!=='undefined'){{window.__CODEPRESS_CONFIG__=Object.assign(window.__CODEPRESS_CONFIG__||{{}},{{repo:\"{}\",branch:\"{}\"}});}}if(typeof document!=='undefined'&&document.head&&!document.querySelector('meta[name=\"codepress-repo\"]')){{var m=document.createElement('meta');m.name='codepress-repo';m.content='{}';document.head.appendChild(m);var b=document.createElement('meta');b.name='codepress-branch';b.content='{}';document.head.appendChild(b);}}}}catch(_){{}}", + "try{{if(typeof window!=='undefined'){{window.__CODEPRESS_CONFIG__=Object.assign(window.__CODEPRESS_CONFIG__||{{}},{{repo:\"{}\",branch:\"{}\"}});}}setTimeout(function(){{try{{if(typeof document!=='undefined'&&document.body&&!document.getElementById('__codepress_config')){{var d=document.createElement('div');d.id='__codepress_config';d.style.display='none';d.setAttribute('data-codepress-repo','{}');d.setAttribute('data-codepress-branch','{}');document.body.appendChild(d);}}}}catch(_){{}}}},0);}}catch(_){{}}", escaped_repo, escaped_branch, escaped_repo, escaped_branch ); diff --git a/src/index.ts b/src/index.ts index 61241d1..6006462 100644 --- a/src/index.ts +++ b/src/index.ts @@ -197,6 +197,25 @@ export default function codePressPlugin( return t.isJSXMemberExpression(name) || t.isJSXNamespacedName(name); } + function isReactFragment(name: Babel.types.JSXIdentifier | Babel.types.JSXMemberExpression | Babel.types.JSXNamespacedName): boolean { + // Check for + if (t.isJSXIdentifier(name) && name.name === "Fragment") { + return true; + } + // Check for + if (t.isJSXMemberExpression(name)) { + if ( + t.isJSXIdentifier(name.object) && + name.object.name === "React" && + t.isJSXIdentifier(name.property) && + name.property.name === "Fragment" + ) { + return true; + } + } + return false; + } + return { name: "babel-plugin-codepress-html", visitor: { @@ -322,6 +341,11 @@ try { } const { node } = nodePath; + + // Skip React.Fragment - it can only accept key and children props + if (isReactFragment(node.name)) { + return; + } const startLine = node.loc?.start.line ?? 0; const parentLoc = nodePath.parent.loc; const endLine = parentLoc?.end.line ?? startLine;