Skip to content

Commit d8b4630

Browse files
gabrielmfernendymion1818bennyburritobenverspeakhank619
committed
feat(tailwind): Smaller bundle size (#1383)
Co-authored-by: Ben Read <[email protected]> Co-authored-by: Benny Burrito <[email protected]> Co-authored-by: Ben Verspeak <[email protected]> Co-authored-by: hank <[email protected]> Co-authored-by: zhanghong <[email protected]> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Ben Gracewood <[email protected]> Co-authored-by: Victor Laforet <[email protected]> Co-authored-by: Bu Kinoshita <[email protected]> Co-authored-by: Vitor Capretz <[email protected]>
1 parent 7ba9b86 commit d8b4630

File tree

78 files changed

+18447
-1770
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+18447
-1770
lines changed

.changeset/quiet-donkeys-brush.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-email/tailwind": minor
3+
---
4+
5+
Refactored internally to have a much smaller bundle size

package.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@
3535
"overrides": {
3636
"@types/react": "npm:[email protected]",
3737
"@types/react-dom": "npm:[email protected]"
38-
},
39-
"patchedDependencies": {
40-
41-
4238
}
4339
}
4440
}

packages/tailwind/.eslintrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/** @type {import('eslint').ESLint.ConfigData} */
22
module.exports = {
33
extends: ["custom/react-internal"],
4+
ignorePatterns: ["integrations/**/*"],
45
plugins: [
56
/* just a plugin to create custom linting rules with regex */
67
"regex"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import path from "node:path";
2+
import { $ } from "./utils/run-testing-command";
3+
4+
test.sequential("Tailwind works on the Next App's build process", () => {
5+
const nextAppLocation = path.resolve(__dirname, "../nextjs");
6+
$("npm install", nextAppLocation);
7+
$("npm run build", nextAppLocation);
8+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import path from "path";
2+
import shell from "shelljs";
3+
4+
/**
5+
* Just a function that runs `shell.exec` and expects it returns code 0, i.e. expects command not to fail
6+
*
7+
* Defaults the CWD to the @react-email/tailwind project's directory
8+
*/
9+
export const $ = (
10+
command: string,
11+
cwd: string = path.resolve(__dirname, ".."),
12+
) => {
13+
expect(
14+
shell.exec(command, { cwd, fatal: true }).code,
15+
`Expected command "${command}" to work properly but it returned a non-zero exit code`,
16+
).toBe(0);
17+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import path from "node:path";
2+
import { $ } from "./utils/run-testing-command";
3+
4+
test.sequential("Tailwind works on the Vite App's build process", () => {
5+
const viteAppLocation = path.resolve(__dirname, "../vite");
6+
$("npm install", viteAppLocation);
7+
$("npm run build", viteAppLocation);
8+
});
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.yalc
7+
yalc.lock
8+
.pnp.js
9+
yalc.lock
10+
.yarn/install-state.gz
11+
12+
# testing
13+
/coverage
14+
15+
# next.js
16+
/.next/
17+
/out/
18+
19+
# production
20+
/build
21+
22+
# misc
23+
.DS_Store
24+
*.pem
25+
26+
# debug
27+
npm-debug.log*
28+
yarn-debug.log*
29+
yarn-error.log*
30+
31+
# local env files
32+
.env*.local
33+
34+
# vercel
35+
.vercel
36+
37+
# typescript
38+
*.tsbuildinfo
39+
next-env.d.ts
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
This is a NextJS project bootstrapped with `create-next-app@latest` that contains a Tailwind
2+
email using most of the features we provide that will be auto-built on testing to
3+
make sure this new release works properly with the latest version of NextJS when being built.
4+
5+
We do this testing so that things are more reliable and this couldn't be done using pnpm
6+
workspaces as they link code instead of actually copying the content into node_modules.
7+
The solution we use to copy the code in a way that mimics the actual `npm install @react-email/tailwind` is `yalc`.
8+
9+
Se [the test file](../_tests/nextjs.spec.ts) for more info.
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
import {
2+
Body,
3+
Button,
4+
Container,
5+
Column,
6+
Head,
7+
Heading,
8+
Hr,
9+
Html,
10+
Img,
11+
Link,
12+
Preview,
13+
Row,
14+
Section,
15+
Text,
16+
} from "@react-email/components";
17+
import { Tailwind } from "@react-email/tailwind";
18+
import * as React from "react";
19+
20+
interface VercelInviteUserEmailProps {
21+
username?: string;
22+
userImage?: string;
23+
invitedByUsername?: string;
24+
invitedByEmail?: string;
25+
teamName?: string;
26+
teamImage?: string;
27+
inviteLink?: string;
28+
inviteFromIp?: string;
29+
inviteFromLocation?: string;
30+
}
31+
32+
const baseUrl = process.env.VERCEL_URL
33+
? `https://${process.env.VERCEL_URL}`
34+
: "";
35+
36+
export const VercelInviteUserEmail = ({
37+
username,
38+
userImage,
39+
invitedByUsername,
40+
invitedByEmail,
41+
teamName,
42+
teamImage,
43+
inviteLink,
44+
inviteFromIp,
45+
inviteFromLocation,
46+
}: VercelInviteUserEmailProps) => {
47+
const previewText = `Join ${invitedByUsername} on Vercel`;
48+
49+
return (
50+
<Html>
51+
<Head />
52+
<Preview>{previewText}</Preview>
53+
<Tailwind>
54+
<Body className="bg-white my-auto mx-auto font-sans px-2">
55+
<Container className="border border-solid border-[#eaeaea] rounded my-[40px] mx-auto p-[20px] max-w-[465px]">
56+
<Section className="mt-[32px]">
57+
<Img
58+
src={`${baseUrl}/static/vercel-logo.png`}
59+
width="40"
60+
height="37"
61+
alt="Vercel"
62+
className="my-0 mx-auto"
63+
/>
64+
</Section>
65+
<Heading className="text-black text-[24px] font-normal text-center p-0 my-[30px] mx-0">
66+
Join <strong>{teamName}</strong> on <strong>Vercel</strong>
67+
</Heading>
68+
<Text className="text-black text-[14px] leading-[24px]">
69+
Hello {username},
70+
</Text>
71+
<Text className="text-black text-[14px] leading-[24px]">
72+
<strong>{invitedByUsername}</strong> (
73+
<Link
74+
href={`mailto:${invitedByEmail}`}
75+
className="text-blue-600 no-underline"
76+
>
77+
{invitedByEmail}
78+
</Link>
79+
) has invited you to the <strong>{teamName}</strong> team on{" "}
80+
<strong>Vercel</strong>.
81+
</Text>
82+
<Section>
83+
<Row>
84+
<Column align="right">
85+
<Img
86+
className="rounded-full"
87+
src={userImage}
88+
width="64"
89+
height="64"
90+
/>
91+
</Column>
92+
<Column align="center">
93+
<Img
94+
src={`${baseUrl}/static/vercel-arrow.png`}
95+
width="12"
96+
height="9"
97+
alt="invited you to"
98+
/>
99+
</Column>
100+
<Column align="left">
101+
<Img
102+
className="rounded-full"
103+
src={teamImage}
104+
width="64"
105+
height="64"
106+
/>
107+
</Column>
108+
</Row>
109+
</Section>
110+
<Section className="text-center mt-[32px] mb-[32px]">
111+
<Button
112+
className="bg-[#000000] rounded text-white text-[12px] font-semibold no-underline text-center px-5 py-3"
113+
href={inviteLink}
114+
>
115+
Join the team
116+
</Button>
117+
</Section>
118+
<Text className="text-black text-[14px] leading-[24px]">
119+
or copy and paste this URL into your browser:{" "}
120+
<Link href={inviteLink} className="text-blue-600 no-underline">
121+
{inviteLink}
122+
</Link>
123+
</Text>
124+
<Hr className="border border-solid border-[#eaeaea] my-[26px] mx-0 w-full" />
125+
<Text className="text-[#666666] text-[12px] leading-[24px]">
126+
This invitation was intended for{" "}
127+
<span className="text-black">{username}</span>. This invite was
128+
sent from <span className="text-black">{inviteFromIp}</span>{" "}
129+
located in{" "}
130+
<span className="text-black">{inviteFromLocation}</span>. If you
131+
were not expecting this invitation, you can ignore this email. If
132+
you are concerned about your account's safety, please reply to
133+
this email to get in touch with us.
134+
</Text>
135+
</Container>
136+
</Body>
137+
</Tailwind>
138+
</Html>
139+
);
140+
};
141+
142+
VercelInviteUserEmail.PreviewProps = {
143+
username: "alanturing",
144+
userImage: `${baseUrl}/static/vercel-user.png`,
145+
invitedByUsername: "Alan",
146+
invitedByEmail: "[email protected]",
147+
teamName: "Enigma",
148+
teamImage: `${baseUrl}/static/vercel-team.png`,
149+
inviteLink: "https://vercel.com/teams/invite/foo",
150+
inviteFromIp: "204.13.186.218",
151+
inviteFromLocation: "São Paulo, Brazil",
152+
} as VercelInviteUserEmailProps;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// <reference types="next" />
2+
/// <reference types="next/image-types/global" />
3+
4+
// NOTE: This file should not be edited
5+
// see https://nextjs.org/docs/basic-features/typescript for more information.

0 commit comments

Comments
 (0)