LoginSignup
4
3

More than 5 years have passed since last update.

React + styled-components + juice でメールテンプレートの作成

Last updated at Posted at 2018-10-23

React + styled-components で、サーバーサイドでのメールテンプレートの作成をすることができました。いい感じに動いています。

なお、汎用的な気がしたので、パッケージ化してみました。

背景

Node.js + TypeScript を使ってサーバーサイドのプログラミングをしているとします。

メールテンプレートの制約を超える

メールテンプレートの場合、

  • 外部ファイルの読み込みができない
  • CSSはインライン化しないと正しくレンダリングされないことがある

なので、CSSをべた書きするか、コンパイル作業が必要になります。

本記事のやり方だと、ライブラリの力でメールテンプレートということを極力意識しなくて良くなります。

メールテンプレートを型安全にする

また、Pug等を使うと、メールテンプレートの内部を型安全にできません。せっかく TypeScript で安全にしているのに、メール部分でエラーが出たらテンション下がりますよね。

JSX での型機能を使えば、型推論を活かしつつ堅牢なメールテンプレートを作ることができます。また、フロントエンドが React だった場合に、統一したテンプレートを使えるというのもあります。

フロントエンドの知見を活かす

styled-somponents によるコンポーネント志向のスタイリングや、 JSX でのテンプレート作成、 Props の渡し方など、フロントエンドの知見をそのままサーバーサイドでのテンプレートに活かすことができます。
場合によっては、コンポーネントと共通化できます。

アプリが React Native、 Web が React Native Dom、デスクトップが Electron、 そしてサーバーサイドのテンプレートが ReactDom/Server だったらテンション上がりそう。

手順

必要なモジュールをインストールします。 TypeScript 前提ですが、他でも動くはずです。

yarn add react react-dom styled-components juice
yarn add -D @types/react @types/react-dom @types/styled-components

emailify という HOC を作ります。

  • react-dom/serverrenderToString で、 React Component を HTML 文字列にコンパイルする
  • juice を使って、 HTML 文字列のCSSをインライン化する
emailify.tsx
import * as React from 'react'
import { renderToString } from 'react-dom/server'
import { ServerStyleSheet } from 'styled-components'
import juice from 'juice'

const HtmlTemplate = ({ body, styles, title }: any) => `
<!DOCTYPE html>
  <html>
    <head>
      <title>${title}</title>
      ${styles}
    </head>
    <body style="margin:0">
      <div id="app">${body}</div>
    </body>
</html>
`

const emailify = <T extends {}>(Component: React.ComponentType<T>) => (props: T, title: string) => {
  const sheet = new ServerStyleSheet()

  const body = renderToString(sheet.collectStyles(<Component {...props} />))
  const styles = sheet.getStyleTags()

  return juice(HtmlTemplate({ body, styles, title }))
}

export default emailify

使い方

使う側はこんな感じです。 emailify に React コンポーネントを食わせると、メール用のテンプレートを返す関数になります。

なお、 TypeScript が型推論してくれるので、 ↑ で書いたジェネリクスの部分は気にしなくて良いです。

import * as React from 'react'
import styled from 'styled-components'
import emailify from 'react-emailify'

interface Props {
  message: string
}

// You can use styled-components, which will be inline in the email template.
const EmailContainer = styled.div`
  font-weight: bold;
  color: #888;
`

// This is a email component, which can be reused across your project
const Template = ({ message }: Props) => (
  <EmailContainer>{message}</EmailContainer>
)

// Here we emailify the template with `emailify` HOC.
const emailTemplate = emailify(Template)

// Here we compile React Compnent to string
// by invoking emailify HOC with template vars and title.
const message = 'Hello World'
const title = 'Hi from React Emailify'
const emailString = emailTemplate({ message }, title)

console.log(emailString)

こんな感じの HTML が出力されます。

<!DOCTYPE html>
<html>
  <head>
    <title>Hi from React Emailify</title>
  </head>
  <body style="margin:0">
    <div id="app">
      <div class="sc-bdVaJa cUChTh" style="font-weight: bold; color: #888;">
        Hello World
      </div>
    </div>
  </body>
</html>

メリット

  • Pug などが不要
    • Reactは必要ですが
  • 型安全
    • テンプレートエンジンに渡した値が null でエラーになった・・・みたいになりません
    • 他のコンポーネントを呼び出しても、入出力が明確
  • コンポーネント志向
    • styled-components により CSS が閉じられているので、再利用性が高いと思われます
  • 勝手にインライン CSS の HTML になる
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3