Skip to content

do not add Tailwind compiled CSS in code blocks#879

Merged
hatemhosny merged 1 commit intodevelopfrom
tailwind-blocks
Sep 24, 2025
Merged

do not add Tailwind compiled CSS in code blocks#879
hatemhosny merged 1 commit intodevelopfrom
tailwind-blocks

Conversation

@hatemhosny
Copy link
Copy Markdown
Collaborator

@hatemhosny hatemhosny commented Sep 24, 2025

Summary by CodeRabbit

  • New Features

    • Tailwind compilation now merges styles from HTML <style> blocks, producing more complete output.
    • Improved Tailwind v3/v4 handling by pairing generated CSS with the corresponding HTML context.
  • Bug Fixes

    • Post-processing now skips Tailwind CSS, UnoCSS, and WindiCSS processors, preventing unintended alterations and ensuring consistent styling results.

@netlify
Copy link
Copy Markdown

netlify Bot commented Sep 24, 2025

Deploy Preview for livecodes ready!

Name Link
🔨 Latest commit 5eca80e
🔍 Latest deploy log https://app.netlify.com/projects/livecodes/deploys/68d3d664f51f2f0007d798f6
😎 Deploy Preview https://deploy-preview-879--livecodes.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 24, 2025

Walkthrough

The compiler’s postProcess loop now unconditionally skips Tailwind CSS, UnoCSS, and WindiCSS processors. Tailwind processors were updated to wrap generated CSS with any inline <style> block contents from the related HTML via a new utility, addCodeInStyleBlocks. Tailwind v4’s prepareCode now accepts HTML and applies the same wrapping.

Changes

Cohort / File(s) Summary
Compiler post-process skips
src/livecodes/compiler/compile-blocks.ts
Added guard to skip processors named 'tailwindcss', 'unocss', or 'windicss' during postProcess iteration.
Tailwind processors integration
src/livecodes/languages/tailwindcss/processor-tailwindcss-compiler.ts
Integrated addCodeInStyleBlocks into Tailwind v3 and v4 flows; v4’s prepareCode now accepts HTML, and both versions wrap CSS with HTML <style> contents.
Tailwind utilities
src/livecodes/languages/tailwindcss/utils.ts
New exported function addCodeInStyleBlocks(css, html) that appends non-empty <style> block contents found in HTML to CSS.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Compiler
  participant Processors
  participant Tailwind as Tailwind/Uno/Windi

  Compiler->>Processors: Iterate postProcess(processor)
  alt processor.name in {tailwindcss, unocss, windicss}
    note right of Compiler: Skip postProcess for style frameworks
    Compiler-->>Tailwind: Bypassed
  else
    Compiler->>Processors: Execute processor.postProcess()
  end
Loading
sequenceDiagram
  autonumber
  participant Caller
  participant TW3 as Tailwind v3
  participant TW4 as Tailwind v4
  participant Utils as addCodeInStyleBlocks

  rect rgb(235, 245, 255)
    Caller->>TW3: generate(css) with html
    TW3->>Utils: addCodeInStyleBlocks(css, html)
    Utils-->>TW3: css+inlineStyle
    TW3-->>Caller: wrapped CSS (with html reference)
  end

  rect rgb(240, 255, 240)
    Caller->>TW4: prepareCode(css, html)
    TW4->>Utils: addCodeInStyleBlocks(resultCss, html)
    Utils-->>TW4: css+inlineStyle
    TW4-->>Caller: wrapped CSS
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

I stitched my CSS with threads of style,
From HTML pockets, I borrowed a while.
Skipping breezy winds—Tail, Uno, Windi—
I hop past posts, light-footed and nifty.
Now bundles align, neat as a burrow—
Code carrots stacked for tomorrow. 🥕🐇

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "do not add Tailwind compiled CSS in code blocks" succinctly and accurately captures the primary intent of the changeset: preventing Tailwind (and similar) processors from injecting compiled CSS into code/style blocks by skipping their post-processing and updating the Tailwind compiler to account for style blocks. It is concise, specific, and directly related to the file-level changes described in the PR summary.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch tailwind-blocks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sonarqubecloud
Copy link
Copy Markdown

@github-actions
Copy link
Copy Markdown
Contributor

Size Change: +262 B (+0.03%)

Total Size: 956 kB

ℹ️ View Unchanged
Filename Size Change
./build/404.html 1 kB 0 B
./build/app.html 250 B 0 B
./build/index.html 2.46 kB -1 B (-0.04%)
./build/livecodes/app.js 111 kB -67 B (-0.06%)
./build/livecodes/app.css 22.4 kB 0 B
./build/livecodes/assets.js 8.61 kB -3 B (-0.03%)
./build/livecodes/assets/noop.js 18 B 0 B
./build/livecodes/assets/templates/diagrams-starter.html 2.19 kB 0 B
./build/livecodes/backup.js 3.72 kB -1 B (-0.03%)
./build/livecodes/blockly.js 13.3 kB -46 B (-0.35%)
./build/livecodes/broadcast.js 1.19 kB 0 B
./build/livecodes/bundle-types.js 4.37 kB 0 B
./build/livecodes/code-to-image.js 9.13 kB +8 B (+0.09%)
./build/livecodes/codejar.js 17.6 kB 0 B
./build/livecodes/codemirror.js 6.33 kB 0 B
./build/livecodes/compile.page.js 2.39 kB 0 B
./build/livecodes/compile.worker.js 14.3 kB +26 B (+0.18%)
./build/livecodes/compiler-utils.js 3.16 kB -1 B (-0.03%)
./build/livecodes/custom-editor-utils.js 198 B 0 B
./build/livecodes/deploy.js 6.89 kB +3 B (+0.04%)
./build/livecodes/editor-settings.js 17.7 kB +21 B (+0.12%)
./build/livecodes/embed-ui.js 5.55 kB +3 B (+0.05%)
./build/livecodes/embed.js 89.4 kB +64 B (+0.07%)
./build/livecodes/export.js 3.89 kB 0 B
./build/livecodes/firebase.js 22.7 kB 0 B
./build/livecodes/format.worker.js 13.4 kB -25 B (-0.19%)
./build/livecodes/google-fonts.js 7.12 kB 0 B
./build/livecodes/headless.js 78.2 kB -35 B (-0.04%)
./build/livecodes/i18n-ar-language-info.json 5.23 kB 0 B
./build/livecodes/i18n-ar-translation.json 9.33 kB 0 B
./build/livecodes/i18n-de-language-info.json 5.25 kB 0 B
./build/livecodes/i18n-de-translation.json 9.44 kB 0 B
./build/livecodes/i18n-en-language-info.json 4.54 kB 0 B
./build/livecodes/i18n-en-translation.json 8.03 kB 0 B
./build/livecodes/i18n-es-language-info.json 5 kB 0 B
./build/livecodes/i18n-es-translation.json 9.17 kB 0 B
./build/livecodes/i18n-fa-language-info.json 5.35 kB 0 B
./build/livecodes/i18n-fa-translation.json 9.48 kB 0 B
./build/livecodes/i18n-fr-language-info.json 5.17 kB 0 B
./build/livecodes/i18n-fr-translation.json 9.42 kB 0 B
./build/livecodes/i18n-hi-language-info.json 5.78 kB 0 B
./build/livecodes/i18n-hi-translation.json 9.95 kB 0 B
./build/livecodes/i18n-it-language-info.json 5.04 kB 0 B
./build/livecodes/i18n-it-translation.json 9.26 kB 0 B
./build/livecodes/i18n-ja-language-info.json 5.57 kB 0 B
./build/livecodes/i18n-ja-translation.json 9.61 kB 0 B
./build/livecodes/i18n-pt-language-info.json 5.05 kB 0 B
./build/livecodes/i18n-pt-translation.json 9.35 kB 0 B
./build/livecodes/i18n-ru-language-info.json 5.56 kB 0 B
./build/livecodes/i18n-ru-translation.json 10.3 kB 0 B
./build/livecodes/i18n-ur-language-info.json 5.81 kB 0 B
./build/livecodes/i18n-ur-translation.json 9.78 kB 0 B
./build/livecodes/i18n-zh-CN-language-info.json 4.9 kB 0 B
./build/livecodes/i18n-zh-CN-translation.json 8.64 kB 0 B
./build/livecodes/i18n.js 20.2 kB +56 B (+0.28%)
./build/livecodes/import-src.js 16 kB +13 B (+0.08%)
./build/livecodes/import.js 14.5 kB 0 B
./build/livecodes/index.js 5.35 kB +6 B (+0.11%)
./build/livecodes/lang-art-template-compiler.js 1.65 kB 0 B
./build/livecodes/lang-assemblyscript-compiler.js 290 B 0 B
./build/livecodes/lang-assemblyscript-script.js 386 B 0 B
./build/livecodes/lang-astro-compiler.js 2.34 kB 0 B
./build/livecodes/lang-clio-compiler.js 1.55 kB 0 B
./build/livecodes/lang-commonlisp-script.js 123 B 0 B
./build/livecodes/lang-cpp-script.js 1.75 kB 0 B
./build/livecodes/lang-cpp-wasm-script.js 2.84 kB 0 B
./build/livecodes/lang-csharp-wasm-script.js 2.18 kB 0 B
./build/livecodes/lang-diagrams-compiler-esm.js 5.08 kB 0 B
./build/livecodes/lang-dot-compiler.js 1.66 kB 0 B
./build/livecodes/lang-ejs-compiler.js 1.63 kB 0 B
./build/livecodes/lang-eta-compiler.js 1.65 kB 0 B
./build/livecodes/lang-fennel-compiler.js 1.61 kB 0 B
./build/livecodes/lang-gleam-compiler.js 3.09 kB 0 B
./build/livecodes/lang-go-wasm-script.js 3.26 kB 0 B
./build/livecodes/lang-haml-compiler.js 1.65 kB 0 B
./build/livecodes/lang-handlebars-compiler.js 1.92 kB 0 B
./build/livecodes/lang-imba-compiler.js 147 B 0 B
./build/livecodes/lang-java-script.js 4.05 kB 0 B
./build/livecodes/lang-jinja-compiler.js 1.65 kB 0 B
./build/livecodes/lang-julia-script.js 3.3 kB 0 B
./build/livecodes/lang-liquid-compiler.js 1.68 kB 0 B
./build/livecodes/lang-lua-wasm-script.js 205 B 0 B
./build/livecodes/lang-malina-compiler.js 2.96 kB +21 B (+0.71%)
./build/livecodes/lang-mustache-compiler.js 1.65 kB 0 B
./build/livecodes/lang-nunjucks-compiler.js 1.93 kB 0 B
./build/livecodes/lang-perl-script.js 268 B 0 B
./build/livecodes/lang-php-wasm-script.js 347 B 0 B
./build/livecodes/lang-postgresql-compiler-esm.js 1.73 kB 0 B
./build/livecodes/lang-prolog-script.js 204 B 0 B
./build/livecodes/lang-pug-compiler.js 371 B 0 B
./build/livecodes/lang-python-wasm-script.js 1.92 kB 0 B
./build/livecodes/lang-r-script-esm.js 2.44 kB 0 B
./build/livecodes/lang-rescript-compiler-esm.js 2.16 kB 0 B
./build/livecodes/lang-rescript-formatter.js 1.52 kB 0 B
./build/livecodes/lang-riot-compiler.js 2.81 kB +23 B (+0.82%)
./build/livecodes/lang-ruby-wasm-script.js 1.71 kB 0 B
./build/livecodes/lang-scss-compiler.js 1.71 kB 0 B
./build/livecodes/lang-solid-compiler.js 263 B 0 B
./build/livecodes/lang-sql-compiler.js 1.63 kB 0 B
./build/livecodes/lang-sql-script.js 1.96 kB 0 B
./build/livecodes/lang-svelte-compiler.js 4.69 kB +19 B (+0.41%)
./build/livecodes/lang-tcl-script.js 1.82 kB 0 B
./build/livecodes/lang-teal-compiler.js 1.72 kB 0 B
./build/livecodes/lang-twig-compiler.js 1.64 kB 0 B
./build/livecodes/lang-vento-compiler.js 1.68 kB 0 B
./build/livecodes/lang-vue-compiler.js 6.08 kB +22 B (+0.36%)
./build/livecodes/lang-vue2-compiler.js 3.48 kB +27 B (+0.78%)
./build/livecodes/lang-wat-compiler.js 348 B 0 B
./build/livecodes/lang-wat-script.js 1.58 kB 0 B
./build/livecodes/language-info.js 7.71 kB +4 B (+0.05%)
./build/livecodes/monaco-lang-astro.js 947 B 0 B
./build/livecodes/monaco-lang-clio.js 639 B 0 B
./build/livecodes/monaco-lang-imba.js 7.35 kB 0 B
./build/livecodes/monaco-lang-wat.js 2.46 kB 0 B
./build/livecodes/monaco.js 10.1 kB 0 B
./build/livecodes/open.js 6.2 kB -15 B (-0.24%)
./build/livecodes/processor-lightningcss-compiler.js 1.88 kB 0 B
./build/livecodes/processor-postcss-compiler.js 2.02 kB 0 B
./build/livecodes/processor-tailwindcss-compiler.js 5.21 kB +154 B (+3.05%)
./build/livecodes/processor-unocss-compiler.js 355 B 0 B
./build/livecodes/processor-windicss-compiler.js 450 B 0 B
./build/livecodes/quill.css 697 B 0 B
./build/livecodes/quill.js 5.74 kB 0 B
./build/livecodes/resources.js 3.43 kB 0 B
./build/livecodes/result-utils.js 1.17 kB 0 B
./build/livecodes/share.js 3.81 kB -1 B (-0.03%)
./build/livecodes/snippets.js 6.04 kB -13 B (-0.21%)
./build/livecodes/sync-ui.js 3.25 kB 0 B
./build/livecodes/sync.js 3.55 kB 0 B
./build/livecodes/sync.worker.js 29.7 kB 0 B
./build/livecodes/templates.js 25.4 kB 0 B
./build/sdk/livecodes.js 3.96 kB 0 B
./build/sdk/livecodes.umd.js 4.02 kB 0 B
./build/sdk/package.json 293 B 0 B
./build/sdk/react.js 4.24 kB 0 B
./build/sdk/vue.js 4.35 kB 0 B

compressed-size-action

@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying livecodes with  Cloudflare Pages  Cloudflare Pages

Latest commit: 5eca80e
Status: ✅  Deploy successful!
Preview URL: https://bc4a6d43.livecodes.pages.dev
Branch Preview URL: https://tailwind-blocks.livecodes.pages.dev

View logs

@hatemhosny hatemhosny merged commit b206b43 into develop Sep 24, 2025
20 of 21 checks passed
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
src/livecodes/compiler/compile-blocks.ts (1)

91-93: Intent aligned, but ensure style imports still get processed when Tailwind is active.

Skipping tailwindcss/unocss/windicss here achieves “don’t place compiled CSS in style blocks.” However, with Tailwind active, postcssRequired may remain false (Lines 84-88), so @import rewriting could be skipped for style blocks. Recommend enabling PostCSS for style imports regardless of Tailwind’s activation to preserve import rewriting.

Suggested change (outside this hunk, Lines 84-88):

// let tailwindcss handle style imports if activated, otherwise use postcss
// Before:
if (editorId === 'style' && hasStyleImports(code) && !tailwindcssIsActive) {
  postcssRequired = true;
}

// After: process style imports even when Tailwind is active (since Tailwind is skipped here)
if (editorId === 'style' && hasStyleImports(code)) {
  postcssRequired = true;
}
src/livecodes/languages/tailwindcss/processor-tailwindcss-compiler.ts (1)

190-192: Include script content cautiously

Embedding raw script inside a <script> tag can break the tag if content contains "</script>". If that occurs, scanning still works, but consider a safer wrapper (e.g., splitting the closing tag) or defaulting to empty string when absent.

Example:

const script = (config.script?.content || '').replaceAll('</script>', '<\\/script>');
const html = `<template>${options.html}\n<script>${script}</script></template>`;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b46f8ca and 5eca80e.

📒 Files selected for processing (3)
  • src/livecodes/compiler/compile-blocks.ts (1 hunks)
  • src/livecodes/languages/tailwindcss/processor-tailwindcss-compiler.ts (2 hunks)
  • src/livecodes/languages/tailwindcss/utils.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/livecodes/languages/tailwindcss/processor-tailwindcss-compiler.ts (2)
src/livecodes/languages/tailwindcss/utils.ts (1)
  • addCodeInStyleBlocks (1-13)
src/livecodes/compiler/import-map.ts (1)
  • replaceStyleImports (244-267)
🪛 ast-grep (0.39.5)
src/livecodes/languages/tailwindcss/utils.ts

[warning] 5-5: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(pattern, 'g')
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: Redirect rules - livecodes
  • GitHub Check: Codacy Static Code Analysis
  • GitHub Check: Header rules - livecodes
  • GitHub Check: Pages changed - livecodes
  • GitHub Check: build
  • GitHub Check: tests (18.x, 1)
  • GitHub Check: tests (18.x, 5)
  • GitHub Check: tests (18.x, 3)
  • GitHub Check: tests (18.x, 4)
  • GitHub Check: tests (18.x, 2)
  • GitHub Check: build (18.x)
  • GitHub Check: build (18.x)
🔇 Additional comments (3)
src/livecodes/languages/tailwindcss/utils.ts (1)

5-5: Regex from variable is safe here; consider precompiling only if perf becomes an issue.

The pattern is static and controlled; ReDoS risk is low. No action required unless profiling shows hot-path costs.

src/livecodes/languages/tailwindcss/processor-tailwindcss-compiler.ts (2)

9-9: LGTM: utility import

Importing addCodeInStyleBlocks centralizes handling of inline styles.


203-205: Good: pass HTML into both scanning and CSS prep

Feeding the same HTML to prepareCode and scanner keeps candidates and inline-style merging consistent.

Comment on lines +91 to +93
// do not place compiled css for tailwind and similar in style blocks
if (['tailwindcss', 'unocss', 'windicss'].includes(processor.name)) continue;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

🧩 Analysis chain

Double-check UnoCSS/WindiCSS parity

We’re skipping Unocss/WindiCSS here too. Please verify their processors (if present) also append inline <style> contents to the generated CSS (akin to Tailwind’s new utility), or else inline styles might be omitted from the final generated CSS.


🏁 Script executed:

#!/bin/bash
# Find Unocss/Windi processors and check if they use addCodeInStyleBlocks or similar
rg -n -C3 -i 'unocss|windicss|windi|create.*(uno|windi)' --type=ts
rg -n -C2 'addCodeInStyleBlocks' --type=ts

Length of output: 24237


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "==== compile-blocks.ts ===="
nl -ba src/livecodes/compiler/compile-blocks.ts | sed -n '1,220p'

echo
echo "==== unocss processor ===="
nl -ba src/livecodes/languages/unocss/processor-unocss-compiler.ts | sed -n '1,320p'

echo
echo "==== windicss processor ===="
nl -ba src/livecodes/languages/windicss/processor-windicss-compiler.ts | sed -n '1,320p'

echo
echo "==== tailwind utils (for reference) ===="
nl -ba src/livecodes/languages/tailwindcss/utils.ts | sed -n '1,240p'

Length of output: 68


🏁 Script executed:

#!/bin/bash
set -euo pipefail

files=(
  "src/livecodes/compiler/compile-blocks.ts"
  "src/livecodes/languages/unocss/processor-unocss-compiler.ts"
  "src/livecodes/languages/windicss/processor-windicss-compiler.ts"
  "src/livecodes/languages/tailwindcss/utils.ts"
  "src/livecodes/languages/tailwindcss/processor-tailwindcss-compiler.ts"
)

for f in "${files[@]}"; do
  echo "==== $f ===="
  if [ -f "$f" ]; then
    awk '{printf "%4d: %s\n", NR, $0}' "$f" | sed -n '1,240p'
  else
    echo "MISSING: $f"
  fi
  echo
done

Length of output: 21308


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "==== locate compile-in-compiler.ts ===="
rg -n --hidden "export const compileInCompiler|compileInCompiler" || true

echo
echo "==== src/livecodes/compiler/compile-in-compiler.ts ===="
if [ -f src/livecodes/compiler/compile-in-compiler.ts ]; then
  awk '{printf "%4d: %s\n", NR, $0}' src/livecodes/compiler/compile-in-compiler.ts | sed -n '1,320p'
else
  echo "MISSING: src/livecodes/compiler/compile-in-compiler.ts"
fi

echo
echo "==== search for options.html usage ===="
rg -n "options\\.html" || true

echo
echo "==== search for where compileInCompiler is called with options ===="
rg -n "compileInCompiler\\(" -S || true

Length of output: 9164


🏁 Script executed:

#!/bin/bash
set -euo pipefail

files=(
  "src/livecodes/compiler/compile.worker.ts"
  "src/livecodes/compiler/compiler-utils.ts"
  "src/livecodes/compiler/compile-in-compiler.ts"
)

for f in "${files[@]}"; do
  echo "==== $f ===="
  if [ -f "$f" ]; then
    awk '{printf "%4d: %s\n", NR, $0}' "$f" | sed -n '1,360p'
  else
    echo "MISSING: $f"
  fi
  echo
done

echo "==== locations of 'options.html' occurrences ===="
rg -n "options\\.html" || true

echo
echo "==== search for where worker handles 'compileInCompiler' or builds options ===="
rg -n "compileInCompiler|compileInWorker|compile\\(" src/livecodes -S || true

Length of output: 26160


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "==== search for 'window.compilers' ===="
rg -n "window\\.compilers" || true

echo
echo "==== search for 'compilers[' usage on window ===="
rg -n "compilers\\[" || true

echo
echo "==== list files in src/livecodes/languages ===="
ls -1 src/livecodes/languages | sed -n '1,200p'

Length of output: 2569


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "==== src/livecodes/compiler/import-map.ts (lines 1-360) ===="
if [ -f src/livecodes/compiler/import-map.ts ]; then
  awk '{printf "%4d: %s\n", NR, $0}' src/livecodes/compiler/import-map.ts | sed -n '1,360p'
else
  echo "MISSING: src/livecodes/compiler/import-map.ts"
fi

echo
echo "==== search for 'tailwindcss' or 'unocss' in import-map.ts ===="
rg -n "tailwindcss|unocss|windicss" src/livecodes/compiler/import-map.ts || true

Length of output: 13675


Fix UnoCSS/WindiCSS inline <style> handling — compile-blocks currently skips ['tailwindcss','unocss','windicss'] (src/livecodes/compiler/compile-blocks.ts:90–92). Tailwind explicitly pulls inline <style> contents via addCodeInStyleBlocks; Unocss (src/livecodes/languages/unocss/processor-unocss-compiler.ts) generates only from options.html and won't see inline <style> content, and WindiCSS (src/livecodes/languages/windicss/processor-windicss-compiler.ts) expects the passed CSS/html but is still skipped. Either remove unocss/windicss from the skip list or update their compilers to incorporate inline <style> contents (e.g., call addCodeInStyleBlocks or equivalent) to avoid dropping inline styles.

🤖 Prompt for AI Agents
In src/livecodes/compiler/compile-blocks.ts around lines 91 to 93, the current
if-statement skips ['tailwindcss','unocss','windicss'], which drops inline
<style> content for UnoCSS and WindiCSS; change the logic so only 'tailwindcss'
is skipped, and for 'unocss' and 'windicss' ensure their processors receive
inline styles by calling addCodeInStyleBlocks (or equivalent) before compilation
so inline <style> contents are passed into their compilers rather than being
ignored.

Comment on lines +195 to 201
const prepareCode = (css: string, html: string) => {
let result = replaceStyleImports(css, [/tailwindcss/g]);
if (!result.includes('@import')) {
result = `@import "tailwindcss";${result}`;
}
return result;
return addCodeInStyleBlocks(result, html);
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Bug: Tailwind v4 import detection is too broad

if (!result.includes('@import')) skips injecting @import "tailwindcss"; when other imports exist (e.g., fonts), breaking Tailwind v4. Check specifically for Tailwind import.

Apply this diff:

-const prepareCode = (css: string, html: string) => {
-  let result = replaceStyleImports(css, [/tailwindcss/g]);
-  if (!result.includes('@import')) {
-    result = `@import "tailwindcss";${result}`;
-  }
-  return addCodeInStyleBlocks(result, html);
-};
+const prepareCode = (css: string, html: string) => {
+  let result = replaceStyleImports(css, [/tailwindcss/g]);
+  const hasTailwindImport = /^\s*@import\s+["']tailwindcss["']\s*;?/m.test(result);
+  if (!hasTailwindImport) {
+    result = `@import "tailwindcss";\n${result}`;
+  }
+  return addCodeInStyleBlocks(result, html);
+};
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const prepareCode = (css: string, html: string) => {
let result = replaceStyleImports(css, [/tailwindcss/g]);
if (!result.includes('@import')) {
result = `@import "tailwindcss";${result}`;
}
return result;
return addCodeInStyleBlocks(result, html);
};
const prepareCode = (css: string, html: string) => {
let result = replaceStyleImports(css, [/tailwindcss/g]);
const hasTailwindImport = /^\s*@import\s+["']tailwindcss["']\s*;?/m.test(result);
if (!hasTailwindImport) {
result = `@import "tailwindcss";\n${result}`;
}
return addCodeInStyleBlocks(result, html);
};

Comment on lines +1 to +13
export const addCodeInStyleBlocks = (css: string, html: string) => {
// from compiler/compile-blocks.ts#compileBlocks
const getBlockPattern = (el: 'style', langAttr = 'lang') =>
`(<${el}\\s*)(?:([\\s\\S]*?)${langAttr}\\s*=\\s*["']([A-Za-z0-9 _]*)["'])?((?:[^>]*)>)([\\s\\S]*?)(<\\/${el}>)`;
const pattern = getBlockPattern('style');
for (const arr of [...html.matchAll(new RegExp(pattern, 'g'))]) {
const content = arr[5];
if (content?.trim()) {
css += `\n${content}`;
}
}
return css;
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Avoid appending non-CSS (<style lang="scss"/"less">) into Tailwind input; support type="text/css".

Current implementation appends all <style> contents, including preprocessor languages, which can break Tailwind v4 compilation. Also, it doesn’t consider type="text/css". Filter to CSS-only and handle both lang and type.

Apply this diff:

 export const addCodeInStyleBlocks = (css: string, html: string) => {
-  // from compiler/compile-blocks.ts#compileBlocks
-  const getBlockPattern = (el: 'style', langAttr = 'lang') =>
-    `(<${el}\\s*)(?:([\\s\\S]*?)${langAttr}\\s*=\\s*["']([A-Za-z0-9 _]*)["'])?((?:[^>]*)>)([\\s\\S]*?)(<\\/${el}>)`;
-  const pattern = getBlockPattern('style');
-  for (const arr of [...html.matchAll(new RegExp(pattern, 'g'))]) {
-    const content = arr[5];
-    if (content?.trim()) {
-      css += `\n${content}`;
-    }
-  }
-  return css;
+  // from compiler/compile-blocks.ts#compileBlocks
+  const getBlockPattern = (el: 'style', attr: 'lang' | 'type' = 'lang') =>
+    `(<${el}\\s*)(?:([\\s\\S]*?)${attr}\\s*=\\s*["']([A-Za-z0-9 _\\/-]*)["'])?((?:[^>]*)>)([\\s\\S]*?)(<\\/${el}>)`;
+  const seen = new Set<number>();
+  const collect = (attr: 'lang' | 'type') => {
+    const pattern = getBlockPattern('style', attr);
+    for (const m of html.matchAll(new RegExp(pattern, 'g'))) {
+      // de-dup: tags without the inspected attr match both patterns
+      if (m.index != null) {
+        if (seen.has(m.index)) continue;
+        seen.add(m.index);
+      }
+      const lang = (m[3] || '').trim().toLowerCase();
+      const isCss =
+        !lang ||
+        lang === 'css' ||
+        lang === 'postcss' ||
+        lang === 'text/css' ||
+        lang === 'text/postcss';
+      const content = m[5];
+      if (isCss && content?.trim()) {
+        css += `\n${content}`;
+      }
+    }
+  };
+  collect('lang');
+  collect('type');
+  return css;
 };

Note: If you deliberately want to include preprocessor contents, consider compiling blocks first and passing the compiled HTML here; otherwise, restrict to CSS to avoid syntax errors in Tailwind/LightningCSS.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const addCodeInStyleBlocks = (css: string, html: string) => {
// from compiler/compile-blocks.ts#compileBlocks
const getBlockPattern = (el: 'style', langAttr = 'lang') =>
`(<${el}\\s*)(?:([\\s\\S]*?)${langAttr}\\s*=\\s*["']([A-Za-z0-9 _]*)["'])?((?:[^>]*)>)([\\s\\S]*?)(<\\/${el}>)`;
const pattern = getBlockPattern('style');
for (const arr of [...html.matchAll(new RegExp(pattern, 'g'))]) {
const content = arr[5];
if (content?.trim()) {
css += `\n${content}`;
}
}
return css;
};
export const addCodeInStyleBlocks = (css: string, html: string) => {
// from compiler/compile-blocks.ts#compileBlocks
const getBlockPattern = (el: 'style', attr: 'lang' | 'type' = 'lang') =>
`(<${el}\\s*)(?:([\\s\\S]*?)${attr}\\s*=\\s*["']([A-Za-z0-9 _\\/-]*)["'])?((?:[^>]*)>)([\\s\\S]*?)(<\\/${el}>)`;
const seen = new Set<number>();
const collect = (attr: 'lang' | 'type') => {
const pattern = getBlockPattern('style', attr);
for (const m of html.matchAll(new RegExp(pattern, 'g'))) {
// de-dup: tags without the inspected attr match both patterns
if (m.index != null) {
if (seen.has(m.index)) continue;
seen.add(m.index);
}
const lang = (m[3] || '').trim().toLowerCase();
const isCss =
!lang ||
lang === 'css' ||
lang === 'postcss' ||
lang === 'text/css' ||
lang === 'text/postcss';
const content = m[5];
if (isCss && content?.trim()) {
css += `\n${content}`;
}
}
};
collect('lang');
collect('type');
return css;
};
🧰 Tools
🪛 ast-grep (0.39.5)

[warning] 5-5: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(pattern, 'g')
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html

(regexp-from-variable)

@hatemhosny hatemhosny deleted the tailwind-blocks branch September 24, 2025 11:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant