juice icon indicating copy to clipboard operation
juice copied to clipboard

Unable to use FreeMarker template tags as juice.codeBlocks

Open ryanwalters opened this issue 8 years ago • 4 comments

Issue I'm using FreeMarker templating tags inside an email template. However, when I try to exclude these using the juice.codeBlocks global, it still parses them.

juice.codeBlocks = {
    start: '<#',
    end: '>'
};

juice('<#list myObject.values as value></#list>');

Expected result <#list myObject.values as value></#list>

Actual result <#list myObject.values="" as="" value=""></#list>

Example https://runkit.com/587926812ee9040013e6cc04/587926812ee9040013e6cc05

ryanwalters avatar Jan 13 '17 20:01 ryanwalters

The way this is documented is misleading, please see below for a working sample. Note that using > as the end tag is probably best replaced by </# since that token might not be parsed correctly.

https://runkit.com/58798a6d4936050013759c0c/58798a6e09267a001378ddde

jrit avatar Jan 14 '17 02:01 jrit

Some more comments for anyone looking at this in the future. The reason @ryanwalters example wasn't working is because:

  1. codeBlocks was formatted incorrectly -- it should follow the format:
{  
  EJS: { start: "<%", end: "%>" },
  HBS: { start: "{{", end: "}}" },
}

Note the immediate children are strings, so it can support multiple languages

  1. you shouldn't overwrite codeBlocks directly, you should modify the reference in place, for example using Object.assign()
Object.assign(juice.codeBlocks, {
    FM: {
            start: '<#',
            end: '</#'
        }
});

const content = juice('<#list myModel.values as values></#list>');

console.log(content);

Output: <#list myModel.values as values></#list>

Example https://runkit.com/wdonnell/5c1285a063adcd0016f35a36

I'm also using juice on freemarker templates -- using </# as your end tag as @jrit suggested works for one liners, but HTML inside freemarker blocks won't be parsed by juice:

Object.assign(juice.codeBlocks, {
    freeMarker: {
        start: '<#',
        end: '</#'
    }
});

const content = juice(`
<style>.red{color:red;}</style>
<#list myModel.values as values>
    <p class="red">this is some text</p>
</#list>`);

Output

<#list myModel.values as values>
    <p class="red">this is some text</p>
</#list>

The freemarker tags aren't mangled, but the <p> inside the list doesn't have its style inlined, either.

I've had good results by setting separate codeBlocks for starting and ending tags, like this:

Object.assign(juice.codeBlocks, {
    freeMarkerStart: {
        start: '<#',
        end: '>'
    },
    freeMarkerEnd: {
        start: '</#',
        end: '>'
    }
});

const content = juice(`
<style>.red{color:red;}</style>
<#list myModel.values as values>
    <p class="red">this is some text</p>
</#list>`);

Output

<#list myModel.values as values>
    <p class="red" style="color: red;">this is some text</p>
</#list>

Example https://runkit.com/wdonnell/5c127b91305cdd00133e2d5d

Now, the styles are correctly inlined and the freemarker templates still work as intended

wdonnell avatar Dec 13 '18 16:12 wdonnell

@wdonnell if you have any interest in opening a PR to integrate that bit about separate start/end blocks especially into the readme that would be rad

jrit avatar Dec 13 '18 17:12 jrit

Juice by default supports HandleBars and EJS templates. Is there any reason why we can't add FreeMarker by default?

It seems that template configs are hardcoded in https://github.com/Automattic/juice/blob/1f823792e78e455760a4fce3b67c0450d7bc4e2d/lib/cheerio.js file.

dovydasvenckus avatar Aug 18 '20 19:08 dovydasvenckus