chromakode / react-html-email

Create elegant HTML email templates using React.
MIT License
896 stars 115 forks source link

Keep package simple #40

Closed nicobrinkkemper closed 6 years ago

nicobrinkkemper commented 7 years ago

Is it possible to separate the injectReactEmailAttributes functionality from the other stuff? This is really the only feature I need, but I'm not sure if it's as simple as copy pasta. Furthermore I don't believe it's wise to set the head in react/jsx. Email head elements can get really complex so it should just be a string IMO. This would allow for something like:

import * as React from 'react';
import {StaticRouter} from "react-router";
import {renderToStaticMarkup} from "react-dom/server";
import {createLocation} from 'history';
import Logo from "./components/Logo";
import head from "./head";
import injectReactEmailAttributes from "./inject-react-email-attributes":

injectReactEmailAttributes();
export default function(locals:Utils.Locals){
    const location = createLocation(locals.path);
    return `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">`
        + `<html data-editor-version="2" class="sg-campaigns" xmlns="http://www.w3.org/1999/xhtml">`
        + head
        + `<body>`
        + renderToStaticMarkup(
            <StaticRouter location={location} context={locals}>
                <Logo />
            </StaticRouter>
        )
        + `</body></html>`;
chromakode commented 7 years ago

Is it possible to separate the injectReactEmailAttributes functionality from the other stuff?

You mean as a separate package? This is totally a hack (and might be difficult to maintain stability), but I could see it being useful separated out. It's a little tricky to pin down the right level of generalization though -- would it still just be for email attributes? Do you want a default set of attributes injected, or do you want to supply your own?

If you're just importing the lib for your own code, it's already a one-liner. All you really need for the attribute injection is:

DOMProperty.injection.injectDOMPropertyConfig({
  Properties: {
    'xmlns': 0,
    'align': 0,
    'valign': 0,
    'bgcolor': 0,
    'border': 0,
    /* any other attributes you care about */
  },
})

Is that worth having a separate dep for to you? Perhaps so that it manages the hacks across React versions?

Furthermore I don't believe it's wise to set the head in react/jsx. Email head elements can get really complex so it should just be a string IMO.

Yes, I agree that the <head> content is highly specific to your use-case. The philosophy of this library is to have a sane default with batteries included, since part of the difficulty of writing HTML emails is onboarding all of the legacy cruft that goes into formatting them. The intent is that once you have specific requirements for your wrapper component, you can use your own.

nicobrinkkemper commented 7 years ago

Hey dude,

Appreciate the response. However I have chosen a different approach to do emails+JSX+React+Typescript. My solution doesn't inject anything because it was just too hacky for Typescript and React to play nice. Instead I use custom components which by default do not parse any of the attributes/props. I will give you an example, you might want to consider it as an alternative to prop injection:

<legacy-table width="100%" cellpadding="0" cellspacing="0" border="0">
    <tbody>
    <tr>
        <td>
            <if-mso-600>
                <legacy-table width="100%" cellpadding="0" cellspacing="0"
                              border="0"
                              stringStyle="width: 100%; max-width:600px;"
                              align="center">
                    <tbody>
                    <tr>
                        <legacy-td {...{
                            width: "100%",
                            align: "left",
                            bgcolor:'#FFF',
                            style: {
                                color:'#111',
                                textAlign:'left',
                                padding:'12px 0px 0px 0px'
                            }
                        }}>
                            <Preheader>
                                {preheader}
                            </Preheader>
                            {children}
                        </legacy-td>
                    </tr>
                    </tbody>
                </legacy-table>
            </if-mso-600>
        </td>
    </tr>
    </tbody>
</legacy-table>

then later in my code I apply this epic email fix, which does the trick:

export function emailify(content:string){
    const ifMso_600_Start = `<!--[if mso]><center><table><tr><td width="600"><![endif]-->`;
    const ifMso_Col_1_Start = `<!--[if mso]><center><table><tr><td width="99%"><![endif]-->`;
    const ifMso_Col_2_Start = `<!--[if mso]><center><table><tr><td width="49%"><![endif]-->`;
    const ifMso_Col_3_Start = `<!--[if mso]><center><table><tr><td width="32.333%"><![endif]-->`;
    const ifMso_End = `<!--[if mso]></td></tr></table></center><![endif]-->`;
    return content.split('stringStyle')
        .join('style')
        .split('<if-mso-600>')
        .join(ifMso_600_Start)
        .split('</if-mso-600>')
        .join(ifMso_End)
        .split('<if-mso-of-col-1>')
        .join(ifMso_Col_1_Start)
        .split('</if-mso-of-col-1>')
        .join(ifMso_End)
        .split('<if-mso-of-col-2>')
        .join(ifMso_Col_2_Start)
        .split('</if-mso-of-col-2>')
        .join(ifMso_End)
        .split('<if-mso-of-col-3>')
        .join(ifMso_Col_3_Start)
        .split('</if-mso-of-col-3>')
        .join(ifMso_End)
        .split('legacy-')
        .join('')
        .split('></img>')
        .join('/>')
}