使用Maizzle进行邮件开发

130 阅读7分钟

最近在尝试使用maizzle框架进行邮件开发,想记录一下这一整个开发过程,希望可以帮助到遇到同样问题的小伙伴。框架安装的过程就不赘述,详情可以查阅官方文档 简单介绍一下目录结构,我本次开发是在maizzle的5版本(也是从4切换到5的,配置项的字段含义变化不大,只是配置的方式发生了改变)

目录结构分析

image.png

build_production

用于存放打包过后的html文件,这份打包过后的html文件是可以直接用于浏览器和邮件渲染的。

components

这个文件夹用于自定义组件,在maizzle中可以将一个html相同或者相似的部分抽取为组件,比如说button card之类的。在maizzle框架的安装过程中,它已经默认生成了一些组件。

image.png

组件中也是拆分为script标签和html部分

注意:邮件中无法执行js代码 现在的组件的概念以及script标签及内容的编写,最终都会被编译成常规的html与css的集合体,如果在script中去编写js的代码逻辑,是不会生效的。其实打开组件就可以看到,组件中传入的props都是设置样式的。

那么组件编写完毕之后,在模板中的使用方式是直接写标签即可。如下图是官方示例,其中的x-button就是使用了components组件下的button组件。

image.png

组件放在components下是不需要去引用的,直接使用即可。

emails

emails是我们正式编写主体内容的文件夹,在这个目录下去开发。当然也可以不在这个目录下去开发,这种情况需要更改打包配置config.js或者config.prodution.js下(参考webpack打包,分为开发环境和正式环境)。

build: {

 current: {

  path: {

  root: 'build_production',

  dir: 'build_production/emails',
 
  base: 'transactional.html',

  ext: '.html',

  name: 'transactional'
  },
 }
}

layouts

用于存放整体的布局模板,其中<yield />部分类似于一个插槽,用于渲染我们在emails下定义的模板,这样就成为了一个完整的html模板文件,然后进入编译过程。用法同组件,不需要引用。

配置文件

最重要的部分就是配置文件了。在模板中写html和css对于任何一个前端工程师来说都是很简单的。但是如果和配置联系起来,就需要花时间理解一下了。

关于适配

邮件开发的大头就是适配问题,一个邮件内容编写完毕之后,如果只能在电脑端显示,或者在手机端显示,都是很局限的。如果我们能够在一份代码里面做好这个适配规则,让其自适应不同终端,就是最理想的情况了。但是,需要注意的是:邮件中无法编写JS代码,我们如何去设置html根字体,从而达到我们理想中的适配效果?

maizzle中引入了taiwindcss来帮助我们解决这样的问题。众所周知这是一个原子css库,它内置是支持设置rem的。但是无法设置根字体,能设置rem有什么用呢?

这就要引出邮件的另一个特性,我们虽然无法设置根字体(因为邮件端有自己的HTML文档,我们编写的内容是在它本身的html下作为内容展示的),但是终端的宽度我们是可以知道的。

这样媒体查询就闪亮登场了。

我们需要在config.js中这样去配置:

export default {
  screens: {
    sm: { max: "800px" },
    xs: { max: "400px" },
  },
};

这样最终编译出来的结果是这样的:

@media (max-width:430px){
 /* ..... */
}

这样我们是不是就非常熟悉了,就是我们常见的做适配的方案,不需要去设置rem,只需要去设置几个阈值,在这个阈值下分别编写不同的样式(需要不同的设计稿)就可以完成适配。

那么我们再编写的过程中sm xs 这些怎么用呢?其实文档上面都可以查阅到,这里我举个例子:

image.png

比如原来我们要设置这个内容是760px,而在max-width:430px这个条件下,需要加上xs:的前缀。如果我想让宽度默认就这么宽,就可以就写w-[760px]不加前缀。

所以分析到现在应该可以明白的一件事是:在maizzle中,邮件的样式编写是借助了taiwindcss,而邮件的适配则是借助了taiwindcss去设置媒体查询规则,从而实现了多端适配。

注意:taiwindcss中有专门针对邮件编写的插件叫做tailwindcss-preset-email,这个插件是安装maizzle框架自动安装的,里面有些预设的样式,可以点开看看。

关于压缩体积

压缩体积的控制也是在配置中进行的,毕竟模板要经过配置的编译,才能输出最终的结果文件。那maizzle中的邮件模板有哪些需要压缩的呢?

其实就是两部分,第一个部分是html,第二个部分是css

先来看看html是怎么压缩的:

 export default {
    minify: {
        removeHTMLComments:true, // 移除html注释
        // other options 具体可以查阅文档
    }
 }

maizzle为我们提供了压缩的api就是minify,这个api的使用方式有两种,一种是直接在配置文件中配置,然后走编译流程。还有一种情况是,我们需要抵用api处理模板,如:

import { minify } from '@maizzle/framework'

const options = {/* html-crush options */}

const html = await minify('html string', options)

通过设置各种压缩选项,就完成了对html部分的压缩

再看看css是怎么压缩的:

在maizzle中我们使用的是tailwindcss原子样式,在编译的过程中,有一些api可以对这一部分进行设置。

css: {
    inline: true, // 使css内联,减少了在style标签中的 !important 的使用,可以减少一部分体积
    // purge编译的过程中删除没有使用的css
    purge:{
        uglify: true, // 丑化类名,可以让类名由原来的10几个字符,转化为一个字符,也可以减少一部分体积
        removeCSSComments: true, // 移除css注释
    }, 
    shorthand: false, // 合并margin/padding/border的写法,也可以减少字符
}

通过这些设置,我们可以将原来冗长的css也压缩为更小的体积。将html的压缩与css压缩配合使用,最终编译完成的文件体积也很小,不会对数据传输造成太大压力。

关于taiwindcss在maizzle中的配置

我们在项目初始化之后就可以看到一个tailwind.config.js文件,关于taiwind的配置,需要翻阅tailwind的文档进行查看。我们在执行npm run dev npm run build的时候,都会通过tailwindcss的配置进行处理。

但是,需要注意的是:如果使用API操作模板的方式,需要在配置中明确设置tailwindcss选项,否则不会生效。如下:

css: {
  inline: true,
  purge: {
    uglify: true,
    removeHTMLComments: true,
    removeCSSComments: true,
  },
  tailwind: {
     presets: [tailwindcssPresetEmail],
     content: [
        {
           raw: template,
           extension: "html",
        },
     ],
     theme: {
        extend: {
        // ......
        },
     },
   },
},

关于模板中的变量设置,以及模板的编译过程

模板中是可以编写变量的(示例中就可以看到),通常情况下是这样去用的:

<div>{{{ page.label }}}</div>

那么这个变量是在哪里设置的呢? 答案是Front Matter

---
title: "Please confirm your email address"
---

<p>{{ page.title }}</p>

如果只是单一文件的话直接在Font Matter中设置即可,如果想在编译的过程中改变这个值,则需要借助API的用法,在maizzle为我们设置的钩子函数中进行设置,如:

import axios from 'axios'

export default {
  async beforeRender({ html, config, matter }) {
    const url = 'https://baconipsum.com/api/?type=all-meat&sentences=1&start-with-lorem=1'

    config.preheader = await axios(url).then(result => result.data).catch(error => 'Could not fetch preheader, using default one.')

    return html
  }
}

我们在beforeRender的钩子函数中,进行了preheader的设置,那么如果模板中有用到这个变量的地方,就会替换为我们编译过程中的值。

关于maizzle的编译过程,大致是这样的:

graph TD
读取配置文件 --> beforeCreate 
--> 清理打包目录 --> 读取模板 --> 读取FrontMatter --> 合并配置文件与FrontMatter --> beforeRender --> render --> afterRender --> transfomer --> afterTransformer --> plainText --> 写到磁盘 --> 拷贝静态文件 --> afterBuild

在这个构建链路上,maizzle为我们提供了跟多API可以去设定我们期待的编译选项。其中transformer转换器,包含了文中提到的一些minify cssinline等,具体查阅文档即可完成。

以上就是我在使用maizzle开发邮件的过程中遇到的问题以及思路梳理,希望可以帮助到大家!!!