Conn2Flow
Navegação das docs

SDD

Human Request: Otimização de CSS Automático com Filtragem de Redundâncias (req-023)

Esta especificação define o lote de trabalho req-023 (BATCH-023) para o Engenheiro Executor. O escopo abrange a filtragem de regras CSS redundantes geradas pelo Tailwind CSS CDN…

Esta especificação define o lote de trabalho req-023 (BATCH-023) para o Engenheiro Executor. O escopo abrange a filtragem de regras CSS redundantes geradas pelo Tailwind CSS CDN no editor HTML antes de salvá-las no banco de dados, reduzindo o payload final injetado nas páginas públicas.


1. Contexto e Objetivo

No painel de administração, quando o usuário edita um layout ou componente usando o editor HTML com Tailwind CSS, o compilador em tempo real (Tailwind CDN) varre o conteúdo editado e gera as regras CSS correspondentes. Esse CSS gerado é extraído e armazenado no campo de CSS compilado (css_compiled / CodeMirrorCssCompiled) para ser gravado no banco de dados.

No entanto, o Tailwind CDN gera o CSS para todas as classes utilizadas na página, inclusive aquelas que já estão contidas e declaradas globalmente no arquivo de estilos core da aplicação (system-output.css ou output.css).

Isso resulta na injeção de uma tag <style> inline redundante de mais de 100 KB que duplica definições já carregadas pelo navegador do usuário final. O objetivo deste lote é implementar um filtro em JavaScript no editor para extrair apenas as classes utilitárias exclusivas geradas no editor, descartando regras que já estejam presentes nas folhas de estilo globais do sistema.


2. Abordagem Técnica

A filtragem será feita no frontend, no momento em que a função updateCSSCompiled captura o CSS gerado no iframe do pré-visualizador. A API nativa do navegador (document.styleSheets) será utilizada para ler as regras ativas de forma estruturada.

2.1 Passos do Algoritmo de Filtragem

  1. Coleta de Seletores do Sistema: Varrer todas as folhas de estilo carregadas no documento do iframe do previewer. Se o href do stylesheet apontar para system-output.css ou output.css, iterar sobre suas regras de estilo (cssRules) e adicionar os seletores textuais (selectorText) a um conjunto (Set) de controle.

  2. Leitura do CSS do Tailwind CDN: Localizar a tag <style> com os estilos gerados pelo CDN do Tailwind no cabeçalho do iframe.

  3. Extração Robusta: Para suportar compatibilidade com Tailwind v3 e v4 (que pode inserir regras dinamicamente via insertRule, deixando o innerHTML da tag vazio), tentar ler as regras diretamente de styleElement.sheet.cssRules. Se indisponível, utilizar innerHTML como fallback.

  4. Filtragem contra Redundâncias:

    • Para regras comuns (CSSStyleRule): Verificar se o selectorText já existe no conjunto de seletores do sistema. Se existir, descartar; caso contrário, mantê-la.

    • Para regras de media query (CSSMediaRule): Iterar sobre as regras internas da media query e aplicar o mesmo filtro de descarte para seletores duplicados. A regra @media só é mantida se contiver ao menos um seletor não duplicado.

    • Outras regras (@theme, @keyframes, etc.): Podem ser mantidas para preservar variáveis específicas e animações.

  5. Atualização do CodeMirror: Atualizar a instância do editor CodeMirrorCssCompiled com o CSS filtrado e limpo.


3. Especificação de Alteração de Código

Localize a função updateCSSCompiled(iframe, clean = false) no arquivo html-editor-interface.js:

Código Atual:

    function updateCSSCompiled(iframe, clean = false) {
        if (clean) {
            CodeMirrorCssCompiled.getDoc().setValue('');
            return;
        }
        var iframeObject = iframe[0];
        setTimeout(function () {
            const iframeDoc = iframeObject.contentDocument || iframeObject.contentWindow.document;
            const allStyleTags = $(iframeDoc).find('head > style');
            const tailwindStyleElement = allStyleTags[allStyleTags.length - 1];
            if (tailwindStyleElement) {
                const generatedCss = tailwindStyleElement.innerHTML;
                CodeMirrorCssCompiled.getDoc().setValue(generatedCss);
            }
        }, 750);
    }

Código Proposto:

    function updateCSSCompiled(iframe, clean = false) {
        if (clean) {
            CodeMirrorCssCompiled.getDoc().setValue('');
            return;
        }
        var iframeObject = iframe[0];
        setTimeout(function () {
            const iframeDoc = iframeObject.contentDocument || iframeObject.contentWindow.document;
            // 1. Coleta seletores globais já existentes nas folhas de estilos core
            const systemSelectors = new Set();
            for (let i = 0; i < iframeDoc.styleSheets.length; i++) {
                const sheet = iframeDoc.styleSheets[i];
                try {
                    // Mapeia tanto system-output.css quanto output.css
                    if (sheet.href && (sheet.href.indexOf('system-output.css') !== -1 || sheet.href.indexOf('output.css') !== -1)) {
                        const rules = sheet.cssRules || sheet.rules;
                        if (rules) {
                            for (let j = 0; j < rules.length; j++) {
                                const rule = rules[j];
                                if (rule.type === CSSRule.STYLE_RULE) {
                                    systemSelectors.add(rule.selectorText);
                                }
                            }
                        }
                    }
                } catch (e) {
                    console.warn("Nao foi possivel ler a folha de estilo do sistema para filtragem:", e);
                }
            }
            // 2. Localiza a tag de estilo gerada pelo Tailwind CDN (normalmente a última tag <style> no head)
            const allStyleTags = $(iframeDoc).find('head > style');
            const tailwindStyleElement = allStyleTags[allStyleTags.length - 1];
            if (tailwindStyleElement) {
                let generatedCss = "";
                const sheet = tailwindStyleElement.sheet;
                // 3. Extrai e filtra as regras estruturadas (suporta Tailwind v3 e v4)
                if (sheet && sheet.cssRules && sheet.cssRules.length > 0) {
                    const rules = sheet.cssRules;
                    for (let i = 0; i < rules.length; i++) {
                        const rule = rules[i];
                        if (rule.type === CSSRule.STYLE_RULE) {
                            // Se o seletor já existe no core, ignora
                            if (!systemSelectors.has(rule.selectorText)) {
                                generatedCss += rule.cssText + "\n";
                            }
                        }
                        else if (rule.type === CSSRule.MEDIA_RULE) {
                            // Trata sub-regras dentro de media queries (ex: @media (min-width: 768px))
                            let mediaContent = "";
                            const subRules = rule.cssRules || rule.rules;
                            for (let k = 0; k < subRules.length; k++) {
                                const subRule = subRules[k];
                                if (subRule.type === CSSRule.STYLE_RULE && !systemSelectors.has(subRule.selectorText)) {
                                    mediaContent += "  " + subRule.cssText + "\n";
                                }
                            }
                            if (mediaContent) {
                                generatedCss += `@media ${rule.media.mediaText} {\n${mediaContent}}\n`;
                            }
                        }
                        else {
                            // Mantém outras diretivas e regras (@theme, @keyframes etc.)
                            generatedCss += rule.cssText + "\n";
                        }
                    }
                } else {
                    // Fallback se não conseguir ler o objeto sheet (Tailwind v3 innerHTML bruto)
                    generatedCss = tailwindStyleElement.innerHTML;
                }
                // 4. Atualiza o editor CodeMirror com as classes exclusivas filtradas
                CodeMirrorCssCompiled.getDoc().setValue(generatedCss.trim());
            }
        }, 750);
    }

4. Verificação

Para validar a implementação:

  1. Abra um componente/layout no editor HTML do gestor.

  2. Escreva marcações usando classes utilitárias já existentes no core (como p-6, flex, hidden). O editor de CSS compilado (CodeMirrorCssCompiled) deve permanecer vazio ou sem essas regras.

  3. Escreva marcações usando uma classe inédita (ex: bg-emerald-700 ou w-[873px]). O editor de CSS compilado deve gerar a definição exclusivamente para esta classe.

  4. Salve e verifique se o payload inline inserido no banco de dados e renderizado no site final reflete apenas o CSS limpo e reduzido.


5. Limpeza de Templates (Ajustes Manuais Concluídos)

Como parte deste lote, foram removidas manualmente dos templates de layout as referências redundantes aos CDNs de frameworks CSS/JS (Tailwind CSS v3 e Fomantic UI), uma vez que o sistema agora gerencia e injeta essas bibliotecas de forma dinâmica.

Arquivos de Layout Limpos:

Alterações Aplicadas:

  1. Remoção de <script src="[REDACTED]"></script> nos layouts baseados em Tailwind.

  2. Remoção do CSS e JS do Fomantic UI (semantic.min.css, jquery.min.js, semantic.min.js) nos layouts baseados em Fomantic UI.

  3. Inclusão dos placeholders <!-- pagina#titulo --> e <!-- pagina#js --> de forma correta e padronizada.

O Futuro é Híbrido: Humano + IA.

O Conn2Flow é a ferramenta. Se você precisa do Arquiteto para desenhar a estratégia da sua empresa usando essa tecnologia...

Contrate Consultoria Especializada