resend / react-email

💌 Build and send emails using React
https://react.email
MIT License
12.67k stars 583 forks source link

fix(tailwind): Performance and stability #1024

Closed gabrielmfern closed 6 months ago

gabrielmfern commented 6 months ago
average ms per render
before ~3197.14ms
after ~27.65ms

What does this PR change?

This PR should implement performance changes and a rewrite with a few fixes. Along with that I have also took the freedom to create a new benchmarks folder in the monorepo that runs a real-world email's render process with and without tailwind to compare the speed.

This PR solves the unbearably long time you needed to wait editing an email due to the slowness from the Tailwind component. It also removes the dependency on tw-to-css because it was not flexible enough to do the approach choosen.

A few issues that I tried solving with this to have the most stability possible for the component were:

How does it fix the problems?

Going in a per-problem basis the fixes were:

eminx commented 6 months ago

Great job!

bukinoshita commented 6 months ago
- feat(tailwind): performance and stability improvements
+ fix(tailwind): Performance an stability
gabrielmfern commented 6 months ago

We just released as a new canary everyone 🎉 !

You guys can now install @react-email/tailwind@0.0.13-canary.1 and things should work

Xexr commented 6 months ago

Whilst this is dramatically faster, it appears to have broken the formatting on gmail for me.

Reverting to the previous version and its back to normal.

gabrielmfern commented 6 months ago

Whilst this is dramatically faster, it appears to have broken the formatting on gmail for me.

Reverting to the previous version and its back to normal.

Interesting, can you maybe elaborate more on that so we can have it fixed? Also, any other problems you had with it?

We will get things fixed as soon as we can to move these changes into stable.

Xexr commented 6 months ago

Sure, happy to.

Here's an email I'm currently working on, and what it looks like the react-email preview and in most email clients:

image

Here's what it looks like in gmail:

image

It almost seems to go back to straight HTML, though clearly it's not quite that as there is the image still.

The same effect also happens on older emails that I know to be working, and are now exhibiting the same behaviour in gmail on the latest tailwind component version.

I've not noticed any other problems so far, but will let you know if I do.

Here's the relevant code (WIP, excuse my mess):


import {
  Html,
  Body,
  Preview,
  Container,
  Heading,
  Text,
  Img,
  Button,
  Hr,
  Link,
  Font,
  Head,
  Section,
  Row,
  Column,
  Tailwind,
} from '@react-email/components';
import * as React from 'react';
import * as tw from '../tailwind.config';
import { type WeeklySummary } from '@/db/getData';
import { cn } from '../src/utils/utils';
import { formatDistance } from 'date-fns';

export const WeeklySummaryEmail = (weeklyData: WeeklySummary) => {
  return (
    <Tailwind config={tw}>
      <Html>
        <Head>
          <Font
            fontFamily="Inter"
            fallbackFontFamily="Verdana"
            webFont={{
              url: 'https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiA.woff2',
              format: 'woff2',
            }}
            fontWeight={400}
            fontStyle="normal"
          />
        </Head>
        <Preview>Keeping you on track</Preview>
        <Body className="bg-black">
          <Container className="bg-black text-gray-200">
            <Container className="py-5">
              <Img
                src={`https://dypt.app/logo_small.png`}
                width="144"
                height="40"
                alt="dypt"
                className="my-5 h-[40px] w-[144px]"
              />
              <Heading as="h2" className="pb-3 text-lg text-gray-200">
                Hello {weeklyData.username}
              </Heading>
              <Text className="text-gray-200">
                Here&apos;s a break down of your unarchived tasks:
              </Text>
              <Section className="m-0 w-[428px]">
                <Row>
                  <Column>
                    <NumberBox
                      number={weeklyData.totalTasks || 0}
                      label="Tasks"
                      bgColor="bg-blue-700"
                      labelColor="text-blue-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.totalTasksCompleted || 0}
                      label="Completed"
                      bgColor="bg-green-700"
                      labelColor="text-green-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.totalTasksOutstanding || 0}
                      label="Remaining"
                      bgColor="bg-orange-700"
                      labelColor="text-orange-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.totalTasksOverdue || 0}
                      label="Overdue"
                      bgColor="bg-red-700"
                      labelColor="text-red-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.totalTasksDueThisWeek || 0}
                      label="This week"
                      bgColor="bg-yellow-700"
                      labelColor="text-yellow-400"
                    />
                  </Column>
                </Row>
              </Section>
              <Text className="mt-5 text-gray-200">
                Your remaining tasks have these priorities assigned:
              </Text>
              <Section className="m-0 w-[343px]">
                <Row>
                  <Column>
                    <NumberBox
                      number={
                        weeklyData.totalTasksOutstanding -
                          weeklyData.lowPriorityTasks -
                          weeklyData.midPriorityTasks -
                          weeklyData.highPriorityTasks || 0
                      }
                      label="None"
                      bgColor="bg-slate-700"
                      labelColor="text-slate-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.lowPriorityTasks || 0}
                      label="Low"
                      bgColor="bg-green-700"
                      labelColor="text-green-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.midPriorityTasks || 0}
                      label="Mid"
                      bgColor="bg-orange-700"
                      labelColor="text-orange-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.highPriorityTasks || 0}
                      label="High"
                      bgColor="bg-red-700"
                      labelColor="text-red-400"
                    />
                  </Column>
                </Row>
              </Section>

              {(weeklyData?.tasksOverdue?.length > 0 && (
                <>
                  <Text className="mt-5 text-gray-200">
                    You have {weeklyData.tasksOverdue.length} overdue tasks:
                  </Text>

                  {weeklyData.tasksOverdue.map((task) => {
                    return (
                      <Task
                        id={task.id}
                        key={task.id}
                        title={task.title}
                        deadline={task.deadline}
                      />
                    );
                  })}
                </>
              )) || (
                <Text className="mt-5 text-gray-200">
                  You have no overdue tasks.
                </Text>
              )}

              {(weeklyData?.tasksDueThisWeek?.length > 0 && (
                <>
                  <Text className="mt-5 text-gray-200">
                    You have {weeklyData.tasksDueThisWeek.length} tasks due this
                    week:
                  </Text>

                  {weeklyData.tasksDueThisWeek.map((task) => {
                    return (
                      <Task
                        id={task.id}
                        key={task.id}
                        title={task.title}
                        deadline={task.deadline}
                      />
                    );
                  })}
                </>
              )) || (
                <Text className="mt-5 text-gray-200">
                  You have no tasks due this week.
                </Text>
              )}

              <Section className="m-0 w-[428px]">
                <Text className="mt-10 italic text-gray-300">
                  Click on one of the info boxes or a task to see the detail on
                  dypt.
                </Text>

                <Text className="mt-3 italic text-gray-300">
                  This is a weekly update email, sent every Monday morning
                  summarising your tasks. Want to unsubscribe? You can disable
                  it in your{' '}
                  <Link
                    href="https://dypt.app/user"
                    className="px-0 text-sm text-blue-500"
                  >
                    dypt account settings
                  </Link>{' '}
                  at any time.
                </Text>

                <Text className="mt-5 text-gray-200">
                  Questions? Find us on twitter{' '}
                  <Link
                    href="https://twitter.com/dyptapp"
                    className="px-0 text-sm text-blue-500"
                  >
                    @dyptapp
                  </Link>{' '}
                  or simply reply to this email.
                </Text>
                <Text className="m-0 p-0 text-gray-200">Best wishes, </Text>
                <Text className="m-0 p-0 text-gray-200">Dane</Text>
                <Button
                  href="https://dypt.app/tasks"
                  className="my-8 rounded-md bg-blue-600 px-3 py-2 text-sm "
                  style={{ color: 'rgb(229 229 229)', padding: '10px 20px' }}
                >
                  Go to your tasks
                </Button>
              </Section>

              <Hr className="border border-blue-700" />
              <Link href="https://dypt.app" className="text-sm text-gray-400">
                dypt.app
              </Link>
              <Text className="text-xs text-gray-400">
                beautiful tasks, infinitely divisible
              </Text>
            </Container>
          </Container>
        </Body>
      </Html>
    </Tailwind>
  );
};

export default WeeklySummaryEmail;

interface NumberBoxProps {
  number: number;
  label: string;
  bgColor: string;
  labelColor: string;
}

const NumberBox = ({ number, label, bgColor, labelColor }: NumberBoxProps) => {
  return (
    <Section className={cn('h-20 w-20 rounded-md', bgColor)}>
      <Row className="mt-[-12px]">
        <Column
          className={cn('pl-2 text-xs font-bold tracking-wider', labelColor)}
          align="left"
        >
          {label}
        </Column>
      </Row>
      <Row className="">
        <Column className={cn('text-3xl text-gray-200')} align="center">
          {number}
        </Column>
      </Row>
    </Section>
  );
};

interface TaskProps {
  id: number;
  title: string;
  deadline: Date | null;
}

const Task = ({ id, title, deadline }: TaskProps) => {
  // create a string using date-fns to display time until deadline
  // if deadline is null, display nothing
  const deadlineString = deadline
    ? formatDistance(deadline, new Date(), { addSuffix: true })
    : 'no deadline';

  return (
    <Link href={`https://dypt.app/tasks/${id}`}>
      <Section
        className={cn(
          'm-0 mb-3 w-[428px] rounded-md bg-slate-600 py-2.5 text-sm outline outline-1 outline-blue-900'
        )}
      >
        <Row className="">
          <Column
            className={cn('pl-2 font-medium', 'text-gray-200')}
            align="left"
          >
            {title}
          </Column>
          <Column
            className={cn('pr-2 text-xs italic text-gray-200')}
            align="right"
          >
            {deadlineString}
          </Column>
        </Row>
      </Section>
    </Link>
  );
};
`
gabrielmfern commented 6 months ago

Sure, happy to.

Here's an email I'm currently working on, and what it looks like the react-email preview and in most email clients:

image

Here's what it looks like in gmail:

image

It almost seems to go back to straight HTML, though clearly it's not quite that as there is the image still.

The same effect also happens on older emails that I know to be working, and are now exhibiting the same behaviour in gmail on the latest tailwind component version.

I've not noticed any other problems so far, but will let you know if I do.

Here's the relevant code (WIP, excuse my mess):

import {
  Html,
  Body,
  Preview,
  Container,
  Heading,
  Text,
  Img,
  Button,
  Hr,
  Link,
  Font,
  Head,
  Section,
  Row,
  Column,
  Tailwind,
} from '@react-email/components';
import * as React from 'react';
import * as tw from '../tailwind.config';
import { type WeeklySummary } from '@/db/getData';
import { cn } from '../src/utils/utils';
import { formatDistance } from 'date-fns';

export const WeeklySummaryEmail = (weeklyData: WeeklySummary) => {
  return (
    <Tailwind config={tw}>
      <Html>
        <Head>
          <Font
            fontFamily="Inter"
            fallbackFontFamily="Verdana"
            webFont={{
              url: 'https://fonts.gstatic.com/s/inter/v12/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiA.woff2',
              format: 'woff2',
            }}
            fontWeight={400}
            fontStyle="normal"
          />
        </Head>
        <Preview>Keeping you on track</Preview>
        <Body className="bg-black">
          <Container className="bg-black text-gray-200">
            <Container className="py-5">
              <Img
                src={`https://dypt.app/logo_small.png`}
                width="144"
                height="40"
                alt="dypt"
                className="my-5 h-[40px] w-[144px]"
              />
              <Heading as="h2" className="pb-3 text-lg text-gray-200">
                Hello {weeklyData.username}
              </Heading>
              <Text className="text-gray-200">
                Here&apos;s a break down of your unarchived tasks:
              </Text>
              <Section className="m-0 w-[428px]">
                <Row>
                  <Column>
                    <NumberBox
                      number={weeklyData.totalTasks || 0}
                      label="Tasks"
                      bgColor="bg-blue-700"
                      labelColor="text-blue-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.totalTasksCompleted || 0}
                      label="Completed"
                      bgColor="bg-green-700"
                      labelColor="text-green-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.totalTasksOutstanding || 0}
                      label="Remaining"
                      bgColor="bg-orange-700"
                      labelColor="text-orange-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.totalTasksOverdue || 0}
                      label="Overdue"
                      bgColor="bg-red-700"
                      labelColor="text-red-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.totalTasksDueThisWeek || 0}
                      label="This week"
                      bgColor="bg-yellow-700"
                      labelColor="text-yellow-400"
                    />
                  </Column>
                </Row>
              </Section>
              <Text className="mt-5 text-gray-200">
                Your remaining tasks have these priorities assigned:
              </Text>
              <Section className="m-0 w-[343px]">
                <Row>
                  <Column>
                    <NumberBox
                      number={
                        weeklyData.totalTasksOutstanding -
                          weeklyData.lowPriorityTasks -
                          weeklyData.midPriorityTasks -
                          weeklyData.highPriorityTasks || 0
                      }
                      label="None"
                      bgColor="bg-slate-700"
                      labelColor="text-slate-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.lowPriorityTasks || 0}
                      label="Low"
                      bgColor="bg-green-700"
                      labelColor="text-green-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.midPriorityTasks || 0}
                      label="Mid"
                      bgColor="bg-orange-700"
                      labelColor="text-orange-400"
                    />
                  </Column>

                  <Column>
                    <NumberBox
                      number={weeklyData.highPriorityTasks || 0}
                      label="High"
                      bgColor="bg-red-700"
                      labelColor="text-red-400"
                    />
                  </Column>
                </Row>
              </Section>

              {(weeklyData?.tasksOverdue?.length > 0 && (
                <>
                  <Text className="mt-5 text-gray-200">
                    You have {weeklyData.tasksOverdue.length} overdue tasks:
                  </Text>

                  {weeklyData.tasksOverdue.map((task) => {
                    return (
                      <Task
                        id={task.id}
                        key={task.id}
                        title={task.title}
                        deadline={task.deadline}
                      />
                    );
                  })}
                </>
              )) || (
                <Text className="mt-5 text-gray-200">
                  You have no overdue tasks.
                </Text>
              )}

              {(weeklyData?.tasksDueThisWeek?.length > 0 && (
                <>
                  <Text className="mt-5 text-gray-200">
                    You have {weeklyData.tasksDueThisWeek.length} tasks due this
                    week:
                  </Text>

                  {weeklyData.tasksDueThisWeek.map((task) => {
                    return (
                      <Task
                        id={task.id}
                        key={task.id}
                        title={task.title}
                        deadline={task.deadline}
                      />
                    );
                  })}
                </>
              )) || (
                <Text className="mt-5 text-gray-200">
                  You have no tasks due this week.
                </Text>
              )}

              <Section className="m-0 w-[428px]">
                <Text className="mt-10 italic text-gray-300">
                  Click on one of the info boxes or a task to see the detail on
                  dypt.
                </Text>

                <Text className="mt-3 italic text-gray-300">
                  This is a weekly update email, sent every Monday morning
                  summarising your tasks. Want to unsubscribe? You can disable
                  it in your{' '}
                  <Link
                    href="https://dypt.app/user"
                    className="px-0 text-sm text-blue-500"
                  >
                    dypt account settings
                  </Link>{' '}
                  at any time.
                </Text>

                <Text className="mt-5 text-gray-200">
                  Questions? Find us on twitter{' '}
                  <Link
                    href="https://twitter.com/dyptapp"
                    className="px-0 text-sm text-blue-500"
                  >
                    @dyptapp
                  </Link>{' '}
                  or simply reply to this email.
                </Text>
                <Text className="m-0 p-0 text-gray-200">Best wishes, </Text>
                <Text className="m-0 p-0 text-gray-200">Dane</Text>
                <Button
                  href="https://dypt.app/tasks"
                  className="my-8 rounded-md bg-blue-600 px-3 py-2 text-sm "
                  style={{ color: 'rgb(229 229 229)', padding: '10px 20px' }}
                >
                  Go to your tasks
                </Button>
              </Section>

              <Hr className="border border-blue-700" />
              <Link href="https://dypt.app" className="text-sm text-gray-400">
                dypt.app
              </Link>
              <Text className="text-xs text-gray-400">
                beautiful tasks, infinitely divisible
              </Text>
            </Container>
          </Container>
        </Body>
      </Html>
    </Tailwind>
  );
};

export default WeeklySummaryEmail;

interface NumberBoxProps {
  number: number;
  label: string;
  bgColor: string;
  labelColor: string;
}

const NumberBox = ({ number, label, bgColor, labelColor }: NumberBoxProps) => {
  return (
    <Section className={cn('h-20 w-20 rounded-md', bgColor)}>
      <Row className="mt-[-12px]">
        <Column
          className={cn('pl-2 text-xs font-bold tracking-wider', labelColor)}
          align="left"
        >
          {label}
        </Column>
      </Row>
      <Row className="">
        <Column className={cn('text-3xl text-gray-200')} align="center">
          {number}
        </Column>
      </Row>
    </Section>
  );
};

interface TaskProps {
  id: number;
  title: string;
  deadline: Date | null;
}

const Task = ({ id, title, deadline }: TaskProps) => {
  // create a string using date-fns to display time until deadline
  // if deadline is null, display nothing
  const deadlineString = deadline
    ? formatDistance(deadline, new Date(), { addSuffix: true })
    : 'no deadline';

  return (
    <Link href={`https://dypt.app/tasks/${id}`}>
      <Section
        className={cn(
          'm-0 mb-3 w-[428px] rounded-md bg-slate-600 py-2.5 text-sm outline outline-1 outline-blue-900'
        )}
      >
        <Row className="">
          <Column
            className={cn('pl-2 font-medium', 'text-gray-200')}
            align="left"
          >
            {title}
          </Column>
          <Column
            className={cn('pr-2 text-xs italic text-gray-200')}
            align="right"
          >
            {deadlineString}
          </Column>
        </Row>
      </Section>
    </Link>
  );
};
`

Just fixed the issues you had with that email. Can you please test out @react-email/tailwind@0.0.13-canary.2?

Xexr commented 6 months ago

Thanks for the quick response Gabriel,

Unfortunately, it's still the same for me. I've installed @react-email/tailwind@0.0.13-canary.2 and switched over the Tailwind component to import from that rather than the components package.

I still get the same broken formatting.

gabrielmfern commented 6 months ago

Thanks for the quick response Gabriel,

Unfortunately, it's still the same for me. I've installed @react-email/tailwind@0.0.13-canary.2 and switched over the Tailwind component to import from that rather than the components package.

I still get the same broken formatting.

Now it just happens to be a different problem, some emails clients seem to just not support the syntax that tailwind uses for rgb so we needed to replace that, older versions already had it and I wasn't aware. Can you try out @react-email/tailwind@0.0.13-canary.3 now?

Xexr commented 6 months ago

Thanks Gabriel,

That has largely fixed it for me.

One remaining bug I noticed: the button component doesn't seem to apply text colour applied through tailwind, I'm having to manually overwrite through a style tag. Makes me wonder if it's a similar RGB related issue?

gabrielmfern commented 6 months ago

Thanks Gabriel,

That has largely fixed it for me.

One remaining bug I noticed: the button component doesn't seem to apply text colour applied through tailwind, I'm having to manually overwrite through a style tag. Makes me wonder if it's a similar RGB related issue?

On what email client are you testing? Also what color are you using?

Xexr commented 6 months ago

It seems to happen on all email clients (including the react-email preview) and across all colours.

Adding a manual non tw style tag resolves it, e.g.: style={{ color: '#d7e5c7' }}

Sample code:


        <Button
          href="https://dypt.app/tasks"
          className="mt-8 rounded-md bg-blue-600 px-3 py-2 text-sm text-gray-200"
        >
          Go to your tasks
        </Button>

It outputs like this, whereas the text should be gray:

image

The colour applied looks to be the typically "visited" url browser colour, but even using tailwinds visited: prefix classes doesn't override it.

gabrielmfern commented 6 months ago
        <Button
          href="https://dypt.app/tasks"
          className="mt-8 rounded-md bg-blue-600 px-3 py-2 text-sm text-gray-200"
        >
          Go to your tasks
        </Button>

Thanks for the feedback and for trying out the canary, you really helped finding the edge cases and rough edges here. This should be fixed on @react-email/tailwind@0.0.13-canary.4.

Xexr commented 6 months ago

Hurrah 🎉

I now get the same in react-email preview and gmail / other clients:

Glad I could be of use, and thanks for all the work Gabriel!

image

tomschenkenberg commented 6 months ago

I'm also testing the performance improvements with:

"@react-email/components": "^0.0.12-canary.0",
"@react-email/tailwind": "^0.0.13-canary.4",
"react-email": "1.9.5",

Am I testing this correct?

I am seeing dramatic performance improvements, but lots of styles are not applied in the resulting email. I can provide the template+demo content if that helps.

gabrielmfern commented 6 months ago

I'm also testing the performance improvements with:

"@react-email/components": "^0.0.12-canary.0",
"@react-email/tailwind": "^0.0.13-canary.4",
"react-email": "1.9.5",

Am I testing this correct?

I am seeing dramatic performance improvements, but lots of styles are not applied in the resulting email. I can provide the template+demo content if that helps.

If you could, it would be awesome.

Xexr commented 6 months ago

Me again, afraid I found another issue.

Canary 4 now works perfectly locally, but deploying on vercel errors out. Reverting to an older version of react-email/tailwind resolves this (I tried 0.0.8).

I get this error in the vercel logs when I call this route (that triggers sending an email):

Error: Cannot find module 'postcss'
Require stack:
- /var/task/.next/server/chunks/934.js
- /var/task/.next/server/webpack-runtime.js
- /var/task/.next/server/app/api/cron/weekly-summary/route.js
- /var/task/node_modules/.pnpm/next@14.0.4-canary.25_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/next-server/server.runtime.prod.js
- /var/task/___next_launcher.cjs
    at Module._resolveFilename (node:internal/modules/cjs/loader:1048:15)
    at /var/task/node_modules/.pnpm/next@14.0.4-canary.25_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:11:25643
    at Module._load (node:internal/modules/cjs/loader:901:27)
    at r.<computed>.e._load (/var/task/___vc/__launcher/__launcher.js:14:2516)
    at Module.require (node:internal/modules/cjs/loader:1115:19)
    at w.require (/var/task/node_modules/.pnpm/next@14.0.4-canary.25_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:11:25859)
    at require (node:internal/modules/helpers:130:18)
    at ../../node_modules/.pnpm/tailwindcss@3.3.2_patch_hash=2ecqyyb3nnd4sclcv6omjvweii/node_modules/tailwindcss/lib/lib/setupContextUtils.js (/var/task/.next/server/chunks/934.js:44:227276)
    at /var/task/.next/server/chunks/934.js:44:9293
    at ../../node_modules/.pnpm/tailwindcss@3.3.2_patch_hash=2ecqyyb3nnd4sclcv6omjvweii/node_modules/tailwindcss/lib/lib/setupTrackingContext.js (/var/task/.next/server/chunks/934.js:2168:21036) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/var/task/.next/server/chunks/934.js',
    '/var/task/.next/server/webpack-runtime.js',
    '/var/task/.next/server/app/api/cron/weekly-summary/route.js',
    '/var/task/node_modules/.pnpm/next@14.0.4-canary.25_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/next-server/server.runtime.prod.js',
    '/var/task/___next_launcher.cjs'
  ],
  page: '/api/cron/weekly-summary'
}
tomschenkenberg commented 6 months ago

I've just published a debug repo: https://github.com/tomschenkenberg/react-email-debug

With pre-canary screenshot of the email and a post-canary screenshot, using email dev

Hope this helps!

gabrielmfern commented 6 months ago

I've just published a debug repo: https://github.com/tomschenkenberg/react-email-debug

With pre-canary screenshot of the email and a post-canary screenshot, using email dev

Hope this helps!

I cloned your repo and tried using the react-email/tailwind@0.0.13-canary.4 and the emails rendered just like in the pre-canary screenshot. The problem doesn't seem to be that you are importing from the wrong module so investigate your setup in depth a bit more, might be some sneaky detail that causes the emails to be rendered that way.

gabrielmfern commented 6 months ago

Me again, afraid I found another issue.

Canary 4 now works perfectly locally, but deploying on vercel errors out. Reverting to an older version of react-email/tailwind resolves this (I tried 0.0.8).

I get this error in the vercel logs when I call this route (that triggers sending an email):

Error: Cannot find module 'postcss'
Require stack:
- /var/task/.next/server/chunks/934.js
- /var/task/.next/server/webpack-runtime.js
- /var/task/.next/server/app/api/cron/weekly-summary/route.js
- /var/task/node_modules/.pnpm/next@14.0.4-canary.25_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/next-server/server.runtime.prod.js
- /var/task/___next_launcher.cjs
    at Module._resolveFilename (node:internal/modules/cjs/loader:1048:15)
    at /var/task/node_modules/.pnpm/next@14.0.4-canary.25_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:11:25643
    at Module._load (node:internal/modules/cjs/loader:901:27)
    at r.<computed>.e._load (/var/task/___vc/__launcher/__launcher.js:14:2516)
    at Module.require (node:internal/modules/cjs/loader:1115:19)
    at w.require (/var/task/node_modules/.pnpm/next@14.0.4-canary.25_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/next-server/server.runtime.prod.js:11:25859)
    at require (node:internal/modules/helpers:130:18)
    at ../../node_modules/.pnpm/tailwindcss@3.3.2_patch_hash=2ecqyyb3nnd4sclcv6omjvweii/node_modules/tailwindcss/lib/lib/setupContextUtils.js (/var/task/.next/server/chunks/934.js:44:227276)
    at /var/task/.next/server/chunks/934.js:44:9293
    at ../../node_modules/.pnpm/tailwindcss@3.3.2_patch_hash=2ecqyyb3nnd4sclcv6omjvweii/node_modules/tailwindcss/lib/lib/setupTrackingContext.js (/var/task/.next/server/chunks/934.js:2168:21036) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/var/task/.next/server/chunks/934.js',
    '/var/task/.next/server/webpack-runtime.js',
    '/var/task/.next/server/app/api/cron/weekly-summary/route.js',
    '/var/task/node_modules/.pnpm/next@14.0.4-canary.25_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/compiled/next-server/server.runtime.prod.js',
    '/var/task/___next_launcher.cjs'
  ],
  page: '/api/cron/weekly-summary'
}

Can you try out @react-email/tailwind@0.0.13-dev.user-build-problems.0 and see if things work well with it?

Xexr commented 6 months ago

That's done the trick 🙂

Seemed like an ESM problem - what was the issue?

gabrielmfern commented 6 months ago

That's done the trick 🙂

Seemed like an ESM problem - what was the issue?

Great to hear! Honestly I'm not exactly sure what the issue was here 😅, but fixing a problem with vite fixed this as well because I changed our build process for the package

tomschenkenberg commented 6 months ago

I've just published a debug repo: https://github.com/tomschenkenberg/react-email-debug With pre-canary screenshot of the email and a post-canary screenshot, using email dev Hope this helps!

I cloned your repo and tried using the react-email/tailwind@0.0.13-canary.4 and the emails rendered just like in the pre-canary screenshot. The problem doesn't seem to be that you are importing from the wrong module so investigate your setup in depth a bit more, might be some sneaky detail that causes the emails to be rendered that way.

Thanks Gabriel for your help, much appreciated! Just to be sure, these were my steps to reproduce the problem:

  1. npm run preview-email (which executes email dev --dir=src/emails)
  2. render the 'content-update' template, and looks OK on screen
  3. use the 'Send' feature to email myself: now looks like the post-canary screenshot in Gmail

The same works fine pre-canary, but takes 7 seconds to render.

gabrielmfern commented 6 months ago

I've just published a debug repo: https://github.com/tomschenkenberg/react-email-debug With pre-canary screenshot of the email and a post-canary screenshot, using email dev Hope this helps!

I cloned your repo and tried using the react-email/tailwind@0.0.13-canary.4 and the emails rendered just like in the pre-canary screenshot. The problem doesn't seem to be that you are importing from the wrong module so investigate your setup in depth a bit more, might be some sneaky detail that causes the emails to be rendered that way.

Thanks Gabriel for your help, much appreciated! Just to be sure, these were my steps to reproduce the problem:

1. `npm run preview-email` (which executes `email dev --dir=src/emails`)

2. render the 'content-update' template, and looks OK on screen

3. use the 'Send' feature to email myself: now looks like the post-canary screenshot in Gmail

The same works fine pre-canary, but takes 7 seconds to render.

Oh, I didn't try sending it to myself.

But still, seems like evenn sending it to gmail it looks fine still. image

tomschenkenberg commented 6 months ago

Thanks Gabriel for your help, much appreciated! Just to be sure, these were my steps to reproduce the problem:

1. `npm run preview-email` (which executes `email dev --dir=src/emails`)

2. render the 'content-update' template, and looks OK on screen

3. use the 'Send' feature to email myself: now looks like the post-canary screenshot in Gmail

The same works fine pre-canary, but takes 7 seconds to render.

Oh, I didn't try sending it to myself.

But still, seems like evenn sending it to gmail it looks fine still.

OK, that's promising! It must be me. I've just added a Docker config to the repo, to rule out my local setup. But still get the post-canary layout in the (Google Workspace and normal) Gmail email. But outlook.com/live.com looks good however.

I'll dig deeper into this.

Xexr commented 6 months ago

Ah I'm back again... sorry!

I was previously checking the gmail web app (as well as apple mail, outlook and protonmail).

All of those are good, but the official gmail app (on iOS) is still borked.

I wonder if this is related to Tom's issue above and we've been talking cross purposes with respect to 'gmail'.

Here's what my email actually looks like in the gmail app:

image

gabrielmfern commented 6 months ago

Ah I'm back again... sorry!

I was previously checking the gmail web app (as well as apple mail, outlook and protonmail).

All of those are good, but the official gmail app (on iOS) is still borked.

I wonder if this is related to Tom's issue above and we've been talking cross purposes with respect to 'gmail'.

Here's what my email actually looks like in the gmail app:

image

Hey thanks for testing that out! That might just be the reason the problem still happens,

I'll tell you guys what, we really want to get these performance improvements into the hands of everybody and since this seems to be a relatively small compatibility issue I'll try fixing that on another minor release, thank you all for the feedback and patience with us on developing this, will get back to you guys soon.

gabrielmfern commented 5 months ago

Ah I'm back again... sorry!

I was previously checking the gmail web app (as well as apple mail, outlook and protonmail).

All of those are good, but the official gmail app (on iOS) is still borked.

I wonder if this is related to Tom's issue above and we've been talking cross purposes with respect to 'gmail'.

Here's what my email actually looks like in the gmail app:

image

@Xexr, Is this issue the same as from this comment https://github.com/resend/react-email/issues/1095#issuecomment-1865394227 or no?

Xexr commented 4 months ago

Ah I'm back again... sorry!

I was previously checking the gmail web app (as well as apple mail, outlook and protonmail).

All of those are good, but the official gmail app (on iOS) is still borked.

I wonder if this is related to Tom's issue above and we've been talking cross purposes with respect to 'gmail'.

Here's what my email actually looks like in the gmail app:

image

@Xexr, Is this issue the same as from this comment https://github.com/resend/react-email/issues/1095#issuecomment-1865394227 or no?

Afraid it appears to be different.

Assuming this was included in the v14 canary?

In the gmail app, it still looks like this:

image