Caminho de ativos em arquivos CSS no Symfony 2

101

Problema

Eu tenho um arquivo CSS com alguns caminhos nele (para imagens, fontes, etc. url(..)).

Minha estrutura de caminho é assim:

...
+-src/
| +-MyCompany/
|   +-MyBundle/
|     +-Resources/
|       +-assets/
|         +-css/
|           +-stylesheets...
+-web/
| +-images/
|   +-images...
...

Quero fazer referência às minhas imagens na folha de estilo.

Primeira Solução

Mudei todos os caminhos no arquivo CSS para caminhos absolutos. Isso não é solução, já que o aplicativo deveria (e deve!) Estar funcionando em um subdiretório também.

Segunda Solução

Use Assetic com filter="cssrewrite".

Então, mudei todos os meus caminhos no meu arquivo CSS para

url("../../../../../../web/images/myimage.png")

para representar o caminho real do meu diretório de recursos para o /web/imagesdiretório. Isso não funciona, pois cssrewrite produz o seguinte código:

url("../../Resources/assets/")

que obviamente é o caminho errado.

Depois que assetic:dumpesse caminho é criado, o que ainda está errado:

url("../../../web/images/myimage.png")

O código do galho do Assetic:

{% stylesheets
    '@MyCompanyMyBundle/Resources/assets/css/*.css'
    filter="cssrewrite"
%}
<link rel="stylesheet" href="{{ asset_url }}" />
{% endstylesheets %}

(Terceira) Solução Atual

Como todos os arquivos CSS terminam em /web/css/stylexyz.css, alterei todos os caminhos no arquivo CSS para serem relativos:

url("../images/myimage.png")

Esta (má) solução funciona, exceto no devambiente: o caminho CSS é /app_dev.php/css/stylexyz.csse, portanto, o caminho da imagem resultante disso é /app_dev.php/images/myimage.png, o que resulta em a NotFoundHttpException.

Existe uma solução melhor e funcional?

apfelbox
fonte
1
Postei minha solução aqui: stackoverflow.com/q/9501248/1146363
Cerad
Isso realmente resolve o problema com os caminhos ao usar app_dev.php?
apfelbox

Respostas:

194

Eu me deparei com o mesmo problema.

Em resumo:

  • Desejando ter CSS original em um diretório "interno" (Recursos / ativos / css / a.css)
  • Desejando ter as imagens no diretório "público" (Resources / public / images / devil.png)
  • Desejando que esse galho pegue aquele CSS, recompile-o em web / css / a.css e faça com que aponte a imagem em /web/bundles/mynicebundle/images/devil.png

Eu fiz um teste com TODAS as combinações possíveis (sãs) do seguinte:

  • @notação, notação relativa
  • Analise com cssrewrite, sem ele
  • Imagem de fundo CSS vs tag <img> direta src = para a mesma imagem que CSS
  • CSS analisado com assetic e também sem análise com saída direta assetic
  • E tudo isso multiplicado tentando um "dir público" (as Resources/public/css) com o CSS e um diretório "privado" (as Resources/assets/css).

Isso me deu um total de 14 combinações no mesmo galho, e essa rota foi lançada a partir de

  • "/app_dev.php/"
  • "/app.php/"
  • e "/"

dando assim 14 x 3 = 42 testes.

Além disso, tudo isso foi testado funcionando em um subdiretório, então não há como enganar fornecendo URLs absolutos porque eles simplesmente não funcionariam.

Os testes foram duas imagens não nomeadas e, em seguida, divs nomeados de 'a' a 'f' para o CSS criado a PARTIR da pasta pública e nomeados de 'g para' l 'para aqueles criados a partir do caminho interno.

Observei o seguinte:

Apenas 3 dos 14 testes foram mostrados adequadamente nos três URLs. E NENHUM era da pasta "interna" (Recursos / ativos). Era um pré-requisito ter o CSS PUBLIC sobressalente e então construir com o assetic DE lá.

Estes são os resultados:

  1. Resultado lançado com /app_dev.php/ Resultado lançado com /app_dev.php/

  2. Resultado lançado com /app.php/ Resultado lançado com /app.php/

  3. Resultado lançado com / insira a descrição da imagem aqui

Então ... SOMENTE - A segunda imagem - Div B - Div C são as sintaxes permitidas.

Aqui está o código TWIG:

<html>
    <head>
            {% stylesheets 'bundles/commondirty/css_original/container.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

    {# First Row: ABCDEF #}

            <link href="{{ '../bundles/commondirty/css_original/a.css' }}" rel="stylesheet" type="text/css" />
            <link href="{{ asset( 'bundles/commondirty/css_original/b.css' ) }}" rel="stylesheet" type="text/css" />

            {% stylesheets 'bundles/commondirty/css_original/c.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets 'bundles/commondirty/css_original/d.css' %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '@CommonDirtyBundle/Resources/public/css_original/e.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '@CommonDirtyBundle/Resources/public/css_original/f.css' %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

    {# First Row: GHIJKL #}

            <link href="{{ '../../src/Common/DirtyBundle/Resources/assets/css/g.css' }}" rel="stylesheet" type="text/css" />
            <link href="{{ asset( '../src/Common/DirtyBundle/Resources/assets/css/h.css' ) }}" rel="stylesheet" type="text/css" />

            {% stylesheets '../src/Common/DirtyBundle/Resources/assets/css/i.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '../src/Common/DirtyBundle/Resources/assets/css/j.css' %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '@CommonDirtyBundle/Resources/assets/css/k.css' filter="cssrewrite" %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

            {% stylesheets '@CommonDirtyBundle/Resources/assets/css/l.css' %}
                <link href="{{ asset_url }}" rel="stylesheet" type="text/css" />
            {% endstylesheets %}

    </head>
    <body>
        <div class="container">
            <p>
                <img alt="Devil" src="../bundles/commondirty/images/devil.png">
                <img alt="Devil" src="{{ asset('bundles/commondirty/images/devil.png') }}">
            </p>
            <p>
                <div class="a">
                    A
                </div>
                <div class="b">
                    B
                </div>
                <div class="c">
                    C
                </div>
                <div class="d">
                    D
                </div>
                <div class="e">
                    E
                </div>
                <div class="f">
                    F
                </div>
            </p>
            <p>
                <div class="g">
                    G
                </div>
                <div class="h">
                    H
                </div>
                <div class="i">
                    I
                </div>
                <div class="j">
                    J
                </div>
                <div class="k">
                    K
                </div>
                <div class="l">
                    L
                </div>
            </p>
        </div>
    </body>
</html>

O container.css:

div.container
{
    border: 1px solid red;
    padding: 0px;
}

div.container img, div.container div 
{
    border: 1px solid green;
    padding: 5px;
    margin: 5px;
    width: 64px;
    height: 64px;
    display: inline-block;
    vertical-align: top;
}

E a.css, b.css, c.css, etc: todos idênticos, bastando alterar a cor e o seletor CSS.

.a
{
    background: red url('../images/devil.png');
}

A estrutura dos "diretórios" é:

Diretórios Diretórios

Tudo isso veio, porque eu não queria que os arquivos originais individuais fossem expostos ao público, principalmente se eu quisesse brincar com filtro "menos" ou "atrevimento" ou algo semelhante ... Não queria que meus "originais" fossem publicados, apenas os compilou um.

Mas existem boas notícias . Se você não quiser ter o "CSS sobressalente" nos diretórios públicos ... instale-os não com --symlink, mas realmente fazendo uma cópia. Uma vez que "assetic" construiu o CSS composto, você pode EXCLUIR o CSS original do sistema de arquivos e deixar as imagens:

Processo de compilação Processo de compilação

Observe que faço isso pelo --env=prodmeio ambiente.

Apenas algumas considerações finais:

  • Este comportamento desejado pode ser alcançado tendo as imagens no diretório "public" no Git ou Mercurial e o "css" no diretório "assets". Ou seja, em vez de tê-los em "público", conforme mostrado nos diretórios, imagine a, b, c ... residindo em "ativos" em vez de "público", do que seu instalador / implantador (provavelmente um script Bash ) colocar o CSS temporariamente dentro do diretório "público" antes de assets:installser executado e assets:install, em seguida assetic:dump, automatizar a remoção do CSS do diretório público após a assetic:dumpexecução. Isso atingiria EXATAMENTE o comportamento desejado na pergunta.

  • Outra solução (desconhecida, se possível) seria explorar se "ativos: instalar" só pode ter "público" como a fonte ou também pode levar "ativos" como uma fonte para publicar. Isso ajudaria quando instalado com a --symlinkopção de desenvolvimento.

  • Além disso, se vamos fazer o script da remoção do diretório "público", a necessidade de armazená-los em um diretório separado ("ativos") desaparecerá. Eles podem viver dentro do "público" em nosso sistema de controle de versão, pois serão descartados após a implantação para o público. Isso também permite o --symlinkuso.

MAS DE QUALQUER MANEIRA, ATENÇÃO AGORA: Como agora os originais já não existem ( rm -Rf), existem apenas duas soluções, não três. O div de trabalho "B" não funciona mais porque era uma chamada asset () assumindo que havia o ativo original. Apenas "C" (o compilado) funcionará.

Então ... só há um VENCEDOR FINAL: a Div "C" permite EXATAMENTE o que foi solicitado no tópico: Para ser compilado, respeite o caminho para as imagens e não exponha a fonte original ao público.

O vencedor é C

O vencedor é C

Xavi Montero
fonte
3
Links para as imagens da postagem anterior: 1) Resultado iniciado com /app_dev.php/ , 2) Resultado iniciado com /app.php/ link , 3) resultado iniciado com / link , 4) Link de diretórios , 5) Link do processo de compilação , 6) Quem é o link
Xavi Montero
1
E se você quiser adicionar uma imagem de outro pacote, em vez de background-image: url('../images/devil.png');usar estebackground-image: url('../../../bundles/frontendlayout/images/devil.png');
Xavi Montero
1
Também funciona combinando "cssrewrite" com "less":{% stylesheets filter="cssrewrite,less" "bundles/frontendlayout/less/layout.less" %} <link href="{{ asset_url }}" rel="stylesheet" type="text/css" /> {% endstylesheets %}
Xavi Montero
1
Isso é observado na documentação do symfony. Veja aqui
Noah Duncan
17

O filtro cssrewrite não é compatível com a notação @bundle por enquanto. Então você tem duas opções:

  • Consulte os arquivos CSS na pasta da web (após console assets:install --symlink web:)

    {% stylesheets '/bundles/myCompany/css/*." filter="cssrewrite" %}
  • Use o filtro cssembed para incorporar imagens no CSS como este.

    {% stylesheets '@MyCompanyMyBundle/Resources/assets/css/*.css' filter="cssembed" %}
jeremymarc
fonte
Obrigado pelo seu comentário. A segunda solução soa muito bem se você tiver apenas imagens bastante pequenas. Eu não me sentiria confortável em colocar cerca de 100k + imagens no arquivo CSS.
apfelbox
9

Vou postar o que funcionou para mim, graças a @ xavi-montero.

Coloque seu CSS no Resource/public/cssdiretório do seu pacote e suas imagens, digamos Resource/public/img.

Altere caminhos asséticos para o formulário 'bundles/mybundle/css/*.css', em seu layout.

Em config.yml, adicione regra css_rewritea assetic:

assetic:
    filters:
        cssrewrite:
            apply_to: "\.css$"

Agora instale ativos e compile com assetic:

$ rm -r app/cache/* # just in case
$ php app/console assets:install --symlink
$ php app/console assetic:dump --env=prod

Isso é bom o suficiente para a caixa de desenvolvimento e --symlinké útil, para que você não precise reinstalar seus recursos (por exemplo, você adiciona uma nova imagem) ao entrar app_dev.php.

Para o servidor de produção, acabei de remover a opção '--symlink' (em meu script de implantação) e adicionei este comando no final:

$ rm -r web/bundles/*/css web/bundles/*/js # all this is already compiled, we don't need the originals

Tudo pronto. Com isso, você pode usar caminhos como este em seus arquivos .css:../img/picture.jpeg

ChocoDeveloper
fonte
5

Eu tive o mesmo problema e tentei apenas usar o seguinte como solução alternativa. Parece funcionar até agora. Você pode até criar um modelo fictício que contém apenas referências a todos esses ativos estáticos.

{% stylesheets
    output='assets/fonts/glyphicons-halflings-regular.ttf'
    'bundles/bootstrap/fonts/glyphicons-halflings-regular.ttf'
%}{% endstylesheets %}

Observe a omissão de qualquer saída, o que significa que nada aparece no modelo. Quando executo o assetic: dump, os arquivos são copiados para o local desejado e o css inclui o trabalho conforme o esperado.

Cowlby
fonte
1
Você pode usar uma entrada de configuração para o ativo nomeado e não é obrigado a incluí-la nos modelos. Ele irá despejar de qualquer maneira symfony.com/doc/current/cookbook/assetic/…
venimus
3

Se isso pode ajudar alguém, temos lutado muito com o Assetic, e agora estamos fazendo o seguinte no modo de desenvolvimento:

  • Configure como em Dumping Asset Files no ambiente de desenvolvimento, então config_dev.ymlcomentamos:

    #assetic:
    #    use_controller: true

    E em routing_dev.yml

    #_assetic:
    #    resource: .
    #    type:     assetic
  • Especifique o URL como absoluto da raiz da web. Por exemplo, background-image: url("/bundles/core/dynatree/skins/skin/vline.gif");Observação: nossa raiz da web vhost está apontando web/.

  • Sem uso de filtro cssrewrite

user1041440
fonte
3
Esta é uma solução válida, mas só se você nunca vai servir os arquivos de um subdiretório, por exemplo: http://example.org/sub/.
apfelbox de
1

Eu geralmente gerencio o plugin css / js com o composer, que o instala sob o fornecedor. Eu faço um link simbólico para o diretório web / bundles, que permite ao composer atualizar os bundles conforme necessário.

exemplo:

1 - symlink uma vez (use o comando fromweb / bundles /

ln -sf vendor/select2/select2/dist/ select2

2 - use o ativo quando necessário, no modelo de galho:

{{ asset('bundles/select2/css/fileinput.css) }}

Saudações.

Jean-Luc Barat
fonte