Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a way to know if Encore is running in dev-server env or not, in Twig #75

Closed
Kocal opened this issue Aug 7, 2019 · 2 comments

Comments

@Kocal
Copy link

commented Aug 7, 2019

Hi,

Context

I'm trying to make Webpack Encore's dev-server working with the new Twig CSS Inliner extension but I'm facing an issue.

I'm using Encore to build Foundation .css files because we want to keep Foundation up-to-date by using npm or yarn, and so I can't directly import a .css like described in the documentation.

This is a part of my webpack.config.js:

Encore
  .addEntry('email', './assets/email/foundation.scss')
  .addEntry('email-responsive', './assets/email/foundation.responsive.css')

This is a part of my config/packages/twig.yaml:

twig:
    paths:
        '%kernel.project_dir%/public/build': build # I can use `source('@build/...')`

And this is my base email template, which works when running encore dev or encore production:

{% set css_to_inline = encore_entry_css_files('email')
    | map(stylesheet => stylesheet|replace({ '/build': '@build' }))
    | map(stylesheet => source(stylesheet))
%}
{% set css_to_ship = encore_entry_css_files('email-responsive')
    | map(stylesheet => stylesheet|replace({ '/build': '@build' }))
    | map(stylesheet => source(stylesheet))
%}

{% apply inky|inline_css(css_to_inline|join('')) %}
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">

    <style>
    {{ css_to_ship|join('') }}
    </style>

    <table class="body" data-made-with-foundation>
        <tr>
            <td class="float-center" align="center" valign="middle">
                <!-- .... -->
            </td>
        </tr>
    </table>
{% endapply %}

But when running encore dev-server, I have the following error when sending an email:
Sélection_999(110)

And this is normal because Twig can not load files from an URL.

Possible solution

A solution would be to introduce a new Twig method encore_is_dev_server() which will returns true or false depending Encore environment. I think this method would read a (new) .json file generated by Encore.

With this new method, I would be able to write something like this and have emails that support Encore dev/prod/dev-server environments:

{% if not encore_is_dev_server() %}
    {% set css_to_inline = encore_entry_css_files('email')
        | map(stylesheet => stylesheet|replace({ '/build': '@build' }))
        | map(stylesheet => source(stylesheet))
    %}
{% endif %}

{% apply inky|inline_css(css_to_inline|default([])|join('')) %}
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">

    {% if encore_is_dev_server() %}
        {{ encore_entry_link_tags('email') }}
        {{ encore_entry_link_tags('email-responsive') }}
    {% else %}
        <style>
        {{ encore_entry_css_files('email-responsive')
            | map(stylesheet => stylesheet|replace({ '/build': '@build' }))
            | map(stylesheet => source(stylesheet))
            | join('') }}
        </style>
    {% endif %}

    <table class="body" data-made-with-foundation>
        <tr>
            <td class="float-center" align="center" valign="middle">
                <!-- ... -->
            </td>
        </tr>
    </table>
{% endapply %}

What do you think?
Thanks!

@Kocal Kocal changed the title Add a way to get the current Webpack Encore environment in Twig Add a way to know if Encore is running in dev-server env or not, in Twig Aug 7, 2019

@tbmatuka

This comment has been minimized.

Copy link

commented Aug 7, 2019

I don't think this is likely to happen, because it seems too complicated for something that I'm not even sure I'd want to have solved. If you really want to inline files like that in development, you could create a twig extension that will get the URLs from encore, figure out how to load them and return their content. This whole approach will get even more complicated if you start using a CDN.

I would also like to suggest using something like MJML. I've been using MJML to generate twig files and it's been great not having to style emails manually. Here's a gist to show how I have it set up on most of my projects: https://gist.github.com/tbmatuka/6b5cdfa1b19829fe12c601e86c7a8e18

@Kocal

This comment has been minimized.

Copy link
Author

commented Aug 9, 2019

That's true. As @Lyrkan pointed out here, my issue is not dev-server specific. It can also occurs when using a CDN.

I think I will go for a Twig extension that will be able to load a file's content directly from a path or by an URL, and I will be able to write something like this:

{% set css_to_inline = encore_entry_css_files('email') | map(stylesheet => encore_source(stylesheet)) %}
{% set css_to_ship = encore_entry_css_files('email-responsive') | map(stylesheet => encore_source(stylesheet)) %}

EDIT: If someone has the same issue that me, this is how I resolved it:

# config/services.yaml
parameters:
    public_dir: '%kernel.project_dir%/public'

App\Twig\EncoreExtension:
    arguments:
        $publicDir: '%public_dir%'
# config/packages/webpack_encore.yaml
webpack_encore:
    output_path: '%public_dir%/build
<?php
// src/Twig/EncoreExtension.php

declare(strict_types=1);

namespace App\Twig;

use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class EncoreExtension extends AbstractExtension
{
    private $publicDir;

    public function __construct(string $publicDir)
    {
        $this->publicDir = $publicDir;
    }

    public function getFunctions(): array
    {
        return [
            new TwigFunction('encore_source', [$this, 'source']),
        ];
    }

    public function source($path)
    {
        if (0 === strpos($path, '/')) {
            $path = $this->publicDir.$path;
        }

        return file_get_contents($path);
    }
}
{# templates/base_email.html.twig #}
{% set css_to_inline = encore_entry_css_files('email') | map(file => encore_source(file)) | join('') %}
{% set css_to_ship = encore_entry_css_files('email-responsive') | map(file => encore_source(file)) | join('') %}

{% apply inky|inline_css(css_to_inline) %}
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">

    <style>
    {{ css_to_ship }}
    </style>

    <table class="body" data-made-with-foundation>
        <tr>
            <td class="float-center" align="center" valign="middle">
                <!-- ... -->
            </td>
        </tr>
    </table>
{% endapply %}

@Kocal Kocal closed this Aug 9, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.