diff --git a/package.json b/package.json index 7fb0e6b9e..d32fbce2e 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "pkg-pr-new": "0.0.51", "tsconfig": "workspace:*", "tsup": "8.4.0", + "tsx": "4.19.3", "turbo": "2.5.4", "vite": "6.3.4", "vitest": "3.2.3" diff --git a/packages/preview-server/.gitignore b/packages/preview-server/.gitignore index 659fa846e..49d1ca2df 100644 --- a/packages/preview-server/.gitignore +++ b/packages/preview-server/.gitignore @@ -3,3 +3,5 @@ node_modules # for testing static +emails +.env* diff --git a/packages/preview-server/package.json b/packages/preview-server/package.json index 08932b094..0025caf40 100644 --- a/packages/preview-server/package.json +++ b/packages/preview-server/package.json @@ -3,9 +3,11 @@ "version": "4.1.0-canary.12", "description": "A live preview of your emails right in your browser.", "scripts": { - "caniemail:fetch": "node ./scripts/fill-caniemail-data.mjs", + "build": "tsx ./scripts/build-preview-server.mts", + "caniemail:fetch": "tsx ./scripts/fill-caniemail-data.mts", "clean": "rm -rf dist", - "build": "node ./scripts/build-preview-server.mjs", + "dev": "tsx ./scripts/dev.mts", + "dev:seed": "tsx ./scripts/seed.mts", "test": "vitest run", "test:watch": "vitest" }, diff --git a/packages/preview-server/readme.md b/packages/preview-server/readme.md new file mode 100644 index 000000000..8539cb849 --- /dev/null +++ b/packages/preview-server/readme.md @@ -0,0 +1,35 @@ +
@react-email/preview-server
+
A live preview of your emails right in your browser.
+
+
+Website + · +GitHub + · +Discord +
+ +This package is used to store the preview server, it is also published and versioned so that it can be installed when the [CLI](../react-email) is being used. + +## Development workflow + +### 1. Seed email templates + +```sh +pnpm dev:seed +``` + +This generates a boilerplate emails directory for you to work with. These files can also be modified as you see fit since they are not included in git. + +### 2. Run development server + +```sh +pnpm dev +``` + +This is somewhat equivalent to `next dev` and does not support hot reloading for email templates like the CLI does. It lets you work on the UI for the preview server mainly. + +### 3. Open in your browser + +Go to http://localhost:3000 + diff --git a/packages/preview-server/scripts/build-preview-server.mjs b/packages/preview-server/scripts/build-preview-server.mts similarity index 100% rename from packages/preview-server/scripts/build-preview-server.mjs rename to packages/preview-server/scripts/build-preview-server.mts diff --git a/packages/preview-server/scripts/dev.mts b/packages/preview-server/scripts/dev.mts new file mode 100644 index 000000000..87e65ebdf --- /dev/null +++ b/packages/preview-server/scripts/dev.mts @@ -0,0 +1,47 @@ +import child_process from 'node:child_process'; +import { promises as fs } from 'node:fs'; +import path from 'node:path'; +import url from 'node:url'; + +const filename = url.fileURLToPath(import.meta.url); +const dirname = path.dirname(filename); + +const previewServerRoot = path.resolve(dirname, '..'); +const emailsDirectoryPath = path.join(previewServerRoot, 'emails'); + +const envPath = path.join(previewServerRoot, '.env.local'); + +await fs.writeFile( + envPath, + `EMAILS_DIR_RELATIVE_PATH=./emails +EMAILS_DIR_ABSOLUTE_PATH=${emailsDirectoryPath} +USER_PROJECT_LOCATION=${previewServerRoot} +NEXT_PUBLIC_IS_PREVIEW_DEVELOPMENT=true`, + 'utf8', +); + +const webServerProcess = child_process.spawn('next', ['dev'], { + cwd: previewServerRoot, + shell: true, + stdio: 'inherit', +}); + +webServerProcess.on('exit', async () => { + await fs.rm(envPath); +}); + +process.on('SIGINT', () => { + webServerProcess.kill('SIGINT'); +}); +process.on('SIGUSR1', () => { + webServerProcess.kill('SIGUSR1'); +}); +process.on('SIGUSR2', () => { + webServerProcess.kill('SIGUSR2'); +}); +process.on('uncaughtExceptionMonitor', () => { + webServerProcess.kill(); +}); +process.on('exit', () => { + webServerProcess.kill(); +}); diff --git a/packages/preview-server/scripts/fill-caniemail-data.mjs b/packages/preview-server/scripts/fill-caniemail-data.mts similarity index 94% rename from packages/preview-server/scripts/fill-caniemail-data.mjs rename to packages/preview-server/scripts/fill-caniemail-data.mts index a5330775f..98eb5c9ec 100644 --- a/packages/preview-server/scripts/fill-caniemail-data.mjs +++ b/packages/preview-server/scripts/fill-caniemail-data.mts @@ -14,11 +14,6 @@ This could be happneing for the following reasons: - You don't have internet connectivity - Caniemail is down - Caniemail changed from where to fetch their data from, which means we need to fix this. If this is the case, please open up an issue.`, - { - cause: { - responseFromCaniemail, - }, - }, ); } diff --git a/packages/preview-server/scripts/seed.mts b/packages/preview-server/scripts/seed.mts new file mode 100644 index 000000000..67cee2f82 --- /dev/null +++ b/packages/preview-server/scripts/seed.mts @@ -0,0 +1,21 @@ +import { existsSync, promises as fs } from 'node:fs'; +import path from 'node:path'; +import url from 'node:url'; + +const filename = url.fileURLToPath(import.meta.url); +const dirname = path.dirname(filename); + +const previewServerRoot = path.resolve(dirname, '..'); +const emailsDirectoryPath = path.join(previewServerRoot, 'emails'); + +const seedPath = path.join(dirname, './utils/default-seed/'); + +if (existsSync(emailsDirectoryPath)) { + console.info('Deleting previous emails directory'); + await fs.rm(emailsDirectoryPath, { recursive: true, force: true }); +} + +console.info('Copying over the defalt seed to the emails directory'); +await fs.cp(seedPath, emailsDirectoryPath, { + recursive: true, +}); diff --git a/packages/preview-server/scripts/utils/default-seed/auth/account-confirmation.tsx b/packages/preview-server/scripts/utils/default-seed/auth/account-confirmation.tsx new file mode 100644 index 000000000..b610e8224 --- /dev/null +++ b/packages/preview-server/scripts/utils/default-seed/auth/account-confirmation.tsx @@ -0,0 +1,68 @@ +import { + Body, + Button, + Column, + Container, + Head, + Heading, + Hr, + Html, + Preview, + Row, + Tailwind, + Text, +} from '@react-email/components'; + +interface AccountConfirmationProps { + confirmLink: string; + expiryTime: string; +} + +export default function AccountConfirmation({ + confirmLink, + expiryTime, +}: AccountConfirmationProps) { + return ( + + + + + Confirm your React Email account + + + Welcome to React Email! + + + Thank you for signing up! To complete your registration and start + using React Email, please confirm your email address. + + + Click the button below to verify your email. This link will expire + in {expiryTime}. + + + + + + + - React Email team +
+ + React Email, 999 React St, Email City, EC 12345 + +
+ +
+ + ); +} + +AccountConfirmation.PreviewProps = { + confirmLink: 'https://react.email/confirm/123', + expiryTime: '24 hours', +} satisfies AccountConfirmationProps; diff --git a/packages/preview-server/scripts/utils/default-seed/auth/forgot-password.tsx b/packages/preview-server/scripts/utils/default-seed/auth/forgot-password.tsx new file mode 100644 index 000000000..fdef85c5d --- /dev/null +++ b/packages/preview-server/scripts/utils/default-seed/auth/forgot-password.tsx @@ -0,0 +1,71 @@ +import { + Body, + Button, + Column, + Container, + Head, + Heading, + Hr, + Html, + Preview, + Row, + Tailwind, + Text, +} from '@react-email/components'; + +interface ForgotPasswordProps { + resetLink: string; + expiryTime: string; +} + +export default function ForgotPassword({ + resetLink, + expiryTime, +}: ForgotPasswordProps) { + return ( + + + + + Reset your React Email password + + + Reset Your Password + + + We received a request to reset your password for your React Email + account. + + + Click the button below to create a new password. This link will + expire in {expiryTime}. + + + If you didn't request this, you can safely ignore this email. + + + + + + + - React Email team +
+ + React Email, 999 React St, Email City, EC 12345 + +
+ +
+ + ); +} + +ForgotPassword.PreviewProps = { + resetLink: 'https://react.email/reset-password/123', + expiryTime: '1 hour', +} satisfies ForgotPasswordProps; diff --git a/packages/preview-server/scripts/utils/default-seed/communications/payment-overdue.tsx b/packages/preview-server/scripts/utils/default-seed/communications/payment-overdue.tsx new file mode 100644 index 000000000..0b17537b5 --- /dev/null +++ b/packages/preview-server/scripts/utils/default-seed/communications/payment-overdue.tsx @@ -0,0 +1,82 @@ +import { + Body, + Button, + Column, + Container, + Head, + Heading, + Hr, + Html, + Preview, + Row, + Tailwind, + Text, +} from '@react-email/components'; + +interface PaymentOverdueProps { + customerName: string; + amount: string; + dueDate: string; + invoiceLink: string; +} + +export default function PaymentOverdue({ + customerName, + amount, + dueDate, + invoiceLink, +}: PaymentOverdueProps) { + return ( + + + + + Payment of {amount} is overdue - Action required + + + Payment Overdue + + Dear {customerName}, + + We noticed that your payment of {amount} was due on {dueDate} and + has not been received yet. + + + To avoid any service interruption, please process your payment as + soon as possible. + + + You can view and pay your invoice by clicking the button below: + + + + + + + + If you have already made this payment, please disregard this + message. + + - React Email team +
+ + React Email, 999 React St, Email City, EC 12345 + +
+ +
+ + ); +} + +PaymentOverdue.PreviewProps = { + customerName: 'Jane Smith', + amount: '$99.00', + dueDate: 'June 1st, 2024', + invoiceLink: 'https://react.email/invoice/123', +} satisfies PaymentOverdueProps; diff --git a/packages/preview-server/scripts/utils/default-seed/communications/team-invite.tsx b/packages/preview-server/scripts/utils/default-seed/communications/team-invite.tsx new file mode 100644 index 000000000..836fd78fb --- /dev/null +++ b/packages/preview-server/scripts/utils/default-seed/communications/team-invite.tsx @@ -0,0 +1,78 @@ +import { + Body, + Button, + Column, + Container, + Head, + Heading, + Hr, + Html, + Preview, + Row, + Tailwind, + Text, +} from '@react-email/components'; + +interface TeamInviteProps { + inviterName: string; + teamName: string; + inviteLink: string; + role: string; +} + +export default function TeamInvite({ + inviterName, + teamName, + inviteLink, + role, +}: TeamInviteProps) { + return ( + + + + + + {inviterName} has invited you to join {teamName} on React Email + + + + You've been invited! + + + {inviterName} has invited you to join {teamName} as a {role}. + + + React Email helps teams collaborate on email templates and manage + their email campaigns effectively. + + + Click the button below to accept the invitation and get started: + + + + + + + - React Email team +
+ + React Email, 999 React St, Email City, EC 12345 + +
+ +
+ + ); +} + +TeamInvite.PreviewProps = { + inviterName: 'John Doe', + teamName: 'Marketing Team', + inviteLink: 'https://react.email/join/team/123', + role: 'Editor', +} satisfies TeamInviteProps; diff --git a/packages/preview-server/scripts/utils/default-seed/communications/webhooks-failed.tsx b/packages/preview-server/scripts/utils/default-seed/communications/webhooks-failed.tsx new file mode 100644 index 000000000..af7afc441 --- /dev/null +++ b/packages/preview-server/scripts/utils/default-seed/communications/webhooks-failed.tsx @@ -0,0 +1,89 @@ +import { + Body, + CodeBlock, + Container, + Head, + Heading, + Hr, + Html, + Preview, + Tailwind, + Text, + vesper, +} from '@react-email/components'; + +interface WebhooksFailedProps { + date: string; + error: { + error: string; + timestamp: string; + webhookId: string; + details: { + reason: string; + retryCount: number; + lastAttempt: string; + }; + }; +} + +export default function WebhooksFailed({ date, error }: WebhooksFailedProps) { + return ( + + + + + Some webhooks failed to deliver at {date} + + + Failed webhook attempt + + + We encountered an issue with some of our webhooks. Please check + the logs for more details. Here is the data for the error: + + + + If you have any questions or need assistance, please reach out to + us at{' '} + + support@react.email + + . + + - React Email team +
+ + React Email, 999 React St, Email City, EC 12345 + +
+ +
+ + ); +} + +WebhooksFailed.PreviewProps = { + date: 'June 4th, 202', + error: { + error: 'Webhook delivery failed', + timestamp: '2023-10-01T12:00:00Z', + webhookId: 'wh_1234567890', + details: { + reason: 'Network error', + retryCount: 3, + lastAttempt: '2023-10-01T12:05:00Z', + }, + }, +} satisfies WebhooksFailedProps; diff --git a/packages/preview-server/scripts/utils/default-seed/feedback-request.tsx b/packages/preview-server/scripts/utils/default-seed/feedback-request.tsx new file mode 100644 index 000000000..d3446afc3 --- /dev/null +++ b/packages/preview-server/scripts/utils/default-seed/feedback-request.tsx @@ -0,0 +1,78 @@ +import { + Body, + Button, + Column, + Container, + Head, + Heading, + Hr, + Html, + Preview, + Row, + Tailwind, + Text, +} from '@react-email/components'; + +interface FeedbackRequestProps { + name: string; +} + +export default function FeedbackRequest({ name }: FeedbackRequestProps) { + return ( + + + + + + Thank you for using our service. We would love to hear your + feedback. + + + + Hello {name}, + + + Thank you for using our service. We would love to hear your + thoughts and suggestions. + + + We work hard to improve our service and your feedback is crucial + for us to understand what we are doing well and where we can + improve. + + + If you have any questions about the service or need assistance, + please feel free to reach out to us at{' '} + + support@react.email + + . + + + + + + + - React Email team +
+ + React Email, 999 React St, Email City, EC 12345 + +
+ +
+ + ); +} + +FeedbackRequest.PreviewProps = { + name: 'user', +} satisfies FeedbackRequestProps; diff --git a/packages/preview-server/scripts/utils/default-seed/marketing/changelog.tsx b/packages/preview-server/scripts/utils/default-seed/marketing/changelog.tsx new file mode 100644 index 000000000..b5b8ad8e7 --- /dev/null +++ b/packages/preview-server/scripts/utils/default-seed/marketing/changelog.tsx @@ -0,0 +1,98 @@ +import { + Body, + Container, + Head, + Heading, + Hr, + Html, + Preview, + Section, + Tailwind, + Text, +} from '@react-email/components'; + +interface ChangelogProps { + receiver: string; + changes: Partial>; + date: string; +} + +interface ChangesProps { + title: React.ReactNode; + content: string[]; +} + +function Changes({ title, content }: ChangesProps) { + return ( +
+ + {title} + + +
+ ); +} + +export default function Changelog({ receiver, date, changes }: ChangelogProps) { + return ( + + + + + + The changes as of {date} particularly tailored to you + + + + Hello {receiver}, + + + We've been hard at work making improvements to our service, and we + wanted to share the latest changes as of{' '} + {date} with you. + + {changes.features && changes.features.length > 0 ? ( + + ) : null} + {changes.improvements && changes.improvements.length > 0 ? ( + + ) : null} + {changes.fixes && changes.fixes.length > 0 ? ( + + ) : null} + - React Email team +
+ + React Email, 999 React St, Email City, EC 12345 + +
+ +
+ + ); +} + +Changelog.PreviewProps = { + receiver: 'user', + changes: { + features: [ + 'Added a new feature to enhance user experience', + 'Introduced a dark mode option for better accessibility', + ], + fixes: [ + 'Fixed a bug that caused the app to crash on startup', + 'Resolved an issue with email notifications not being sent', + ], + improvements: [ + 'Improved performance of the application by optimizing database queries', + 'Enhanced security measures to protect user data', + ], + }, + date: 'June 4th, 2025', +} satisfies ChangelogProps; diff --git a/packages/preview-server/src/contexts/emails.tsx b/packages/preview-server/src/contexts/emails.tsx index 60eb2e48a..b4dbb1250 100644 --- a/packages/preview-server/src/contexts/emails.tsx +++ b/packages/preview-server/src/contexts/emails.tsx @@ -1,7 +1,7 @@ 'use client'; import { createContext, useContext, useState } from 'react'; import { getEmailsDirectoryMetadataAction } from '../actions/get-emails-directory-metadata-action'; -import { isBuilding } from '../app/env'; +import { isBuilding, isPreviewDevelopment } from '../app/env'; import { useHotreload } from '../hooks/use-hot-reload'; import type { EmailsDirectory } from '../utils/get-emails-directory-metadata'; @@ -31,7 +31,7 @@ export const EmailsProvider = (props: { const [emailsDirectoryMetadata, setEmailsDirectoryMetadata] = useState(props.initialEmailsDirectoryMetadata); - if (!isBuilding) { + if (!isBuilding && !isPreviewDevelopment) { // biome-ignore lint/correctness/useHookAtTopLevel: this will not change on runtime so it doesn't violate the rules of hooks useHotreload(async () => { const metadata = await getEmailsDirectoryMetadataAction( diff --git a/packages/preview-server/src/contexts/preview.tsx b/packages/preview-server/src/contexts/preview.tsx index 296eab971..302ae68bf 100644 --- a/packages/preview-server/src/contexts/preview.tsx +++ b/packages/preview-server/src/contexts/preview.tsx @@ -5,7 +5,7 @@ import type { EmailRenderingResult, RenderedEmailMetadata, } from '../actions/render-email-by-path'; -import { isBuilding } from '../app/env'; +import { isBuilding, isPreviewDevelopment } from '../app/env'; import { useEmailRenderingResult } from '../hooks/use-email-rendering-result'; import { useHotreload } from '../hooks/use-hot-reload'; import { useRenderingMetadata } from '../hooks/use-rendering-metadata'; @@ -49,7 +49,7 @@ export const PreviewProvider = ({ serverRenderingResult, ); - if (!isBuilding) { + if (!isBuilding && !isPreviewDevelopment) { // biome-ignore lint/correctness/useHookAtTopLevel: this will not change on runtime so it doesn't violate the rules of hooks useHotreload((changes) => { const changeForThisEmail = changes.find((change) => diff --git a/packages/preview-server/src/hooks/use-email-rendering-result.ts b/packages/preview-server/src/hooks/use-email-rendering-result.ts index 59ca9ae87..3f4c848d8 100644 --- a/packages/preview-server/src/hooks/use-email-rendering-result.ts +++ b/packages/preview-server/src/hooks/use-email-rendering-result.ts @@ -4,7 +4,7 @@ import { type EmailRenderingResult, renderEmailByPath, } from '../actions/render-email-by-path'; -import { isBuilding } from '../app/env'; +import { isBuilding, isPreviewDevelopment } from '../app/env'; import { useEmails } from '../contexts/emails'; import { containsEmailTemplate } from '../utils/contains-email-template'; import { useHotreload } from './use-hot-reload'; @@ -19,7 +19,7 @@ export const useEmailRenderingResult = ( const { emailsDirectoryMetadata } = useEmails(); - if (!isBuilding) { + if (!isBuilding && !isPreviewDevelopment) { // biome-ignore lint/correctness/useHookAtTopLevel: This is fine since isBuilding does not change at runtime useHotreload(async (changes) => { for await (const change of changes) { diff --git a/packages/react-email/src/utils/preview/get-env-variables-for-preview-app.ts b/packages/react-email/src/utils/preview/get-env-variables-for-preview-app.ts index ffb1634a6..e7c585d41 100644 --- a/packages/react-email/src/utils/preview/get-env-variables-for-preview-app.ts +++ b/packages/react-email/src/utils/preview/get-env-variables-for-preview-app.ts @@ -1,5 +1,4 @@ import path from 'node:path'; -import { isDev } from './start-dev-server.js'; export const getEnvVariablesForPreviewApp = ( relativePathToEmailsDirectory: string, @@ -9,6 +8,5 @@ export const getEnvVariablesForPreviewApp = ( EMAILS_DIR_RELATIVE_PATH: relativePathToEmailsDirectory, EMAILS_DIR_ABSOLUTE_PATH: path.resolve(cwd, relativePathToEmailsDirectory), USER_PROJECT_LOCATION: cwd, - NEXT_PUBLIC_IS_PREVIEW_DEVELOPMENT: isDev ? 'true' : 'false', } as const; }; diff --git a/packages/react-email/src/utils/preview/hot-reloading/create-dependency-graph.spec.ts b/packages/react-email/src/utils/preview/hot-reloading/create-dependency-graph.spec.ts index a99e6798e..db99db37a 100644 --- a/packages/react-email/src/utils/preview/hot-reloading/create-dependency-graph.spec.ts +++ b/packages/react-email/src/utils/preview/hot-reloading/create-dependency-graph.spec.ts @@ -44,52 +44,21 @@ test('createDependencyGraph()', async () => { }; const initialDependencyGraph = convertPathsToAbsolute({ - '../../../../package.json': { - dependencyPaths: [], - dependentPaths: ['../../packageJson.ts'], - moduleDependencies: [], - path: '../../../../package.json', - }, 'create-dependency-graph.ts': { path: 'create-dependency-graph.ts', - dependencyPaths: [ - '../start-dev-server.ts', - 'get-imported-modules.ts', - 'resolve-path-aliases.ts', - ], + dependencyPaths: ['get-imported-modules.ts', 'resolve-path-aliases.ts'], dependentPaths: [ 'create-dependency-graph.spec.ts', 'setup-hot-reloading.ts', ], moduleDependencies: ['node:fs', 'node:path', 'chokidar/handler.js'], }, - '../../get-preview-server-location.ts': { - dependencyPaths: ['../../packageJson.ts'], - dependentPaths: ['../../preview/start-dev-server.ts'], - moduleDependencies: ['node:path', 'node:url', 'jiti', 'nypm', 'prompts'], - path: '../../get-preview-server-location.ts', - }, - '../../packageJson.ts': { - dependencyPaths: ['../../../../package.json'], - dependentPaths: [ - '../../get-preview-server-location.ts', - '../../preview/start-dev-server.ts', - ], - moduleDependencies: [], - path: '../../packageJson.ts', - }, 'create-dependency-graph.spec.ts': { path: 'create-dependency-graph.spec.ts', dependencyPaths: ['create-dependency-graph.ts'], dependentPaths: [], moduleDependencies: ['node:fs', 'node:path'], }, - '../get-env-variables-for-preview-app.ts': { - dependencyPaths: ['../../preview/start-dev-server.ts'], - dependentPaths: ['../../preview/start-dev-server.ts'], - moduleDependencies: ['node:path'], - path: '../../preview/get-env-variables-for-preview-app.ts', - }, './test/some-file.ts': { dependencyPaths: [], dependentPaths: [], @@ -141,47 +110,6 @@ test('createDependencyGraph()', async () => { 'socket.io', ], }, - '../start-dev-server.ts': { - dependencyPaths: [ - '../../register-spinner-autostopping.ts', - '../../get-preview-server-location.ts', - '../../packageJson.ts', - '../../preview/get-env-variables-for-preview-app.ts', - '../../preview/serve-static-file.ts', - ], - path: '../start-dev-server.ts', - dependentPaths: [ - '../../preview/get-env-variables-for-preview-app.ts', - 'create-dependency-graph.ts', - ], - moduleDependencies: [ - 'node:http', - 'node:path', - 'node:url', - 'chalk', - 'jiti', - 'log-symbols', - 'ora', - ], - }, - '../../preview/serve-static-file.ts': { - dependencyPaths: [], - dependentPaths: ['../../preview/start-dev-server.ts'], - moduleDependencies: [ - 'node:fs', - 'node:http', - 'node:path', - 'node:url', - 'mime-types', - ], - path: '../../preview/serve-static-file.ts', - }, - '../../register-spinner-autostopping.ts': { - dependencyPaths: [], - dependentPaths: ['../../preview/start-dev-server.ts'], - moduleDependencies: ['log-symbols', 'ora'], - path: '../../register-spinner-autostopping.ts', - }, '../../types/hot-reload-event.ts': { dependencyPaths: [], dependentPaths: ['../../types/hot-reload-change.ts'], diff --git a/packages/react-email/src/utils/preview/hot-reloading/create-dependency-graph.ts b/packages/react-email/src/utils/preview/hot-reloading/create-dependency-graph.ts index 1c50fd908..f91ec95f8 100644 --- a/packages/react-email/src/utils/preview/hot-reloading/create-dependency-graph.ts +++ b/packages/react-email/src/utils/preview/hot-reloading/create-dependency-graph.ts @@ -1,7 +1,6 @@ import { existsSync, promises as fs, statSync } from 'node:fs'; import path from 'node:path'; import type { EventName } from 'chokidar/handler.js'; -import { isDev } from '../start-dev-server.js'; import { getImportedModules } from './get-imported-modules.js'; import { resolvePathAliases } from './resolve-path-aliases.js'; @@ -134,8 +133,7 @@ export const createDependencyGraph = async (directory: string) => { ); if (pathWithExtension) { pathToDependencyFromDirectory = pathWithExtension; - } else if (isDev) { - // only warn about this on development as it is probably going to be irrelevant otherwise + } else { console.warn( `Could not find index file for directory at ${pathToDependencyFromDirectory}. This is probably going to cause issues with both hot reloading and your code.`, ); @@ -157,8 +155,7 @@ export const createDependencyGraph = async (directory: string) => { if (pathWithEnsuredExtension) { pathToDependencyFromDirectory = pathWithEnsuredExtension; - } else if (isDev) { - // only warn about this on development as it is probably going to be irrelevant otherwise + } else { console.warn( `Could not find file at ${pathToDependencyFromDirectory}`, ); diff --git a/packages/react-email/src/utils/preview/start-dev-server.ts b/packages/react-email/src/utils/preview/start-dev-server.ts index 192d4f7d0..ab008339e 100644 --- a/packages/react-email/src/utils/preview/start-dev-server.ts +++ b/packages/react-email/src/utils/preview/start-dev-server.ts @@ -27,11 +27,6 @@ const safeAsyncServerListen = (server: http.Server, port: number) => { }); }; -const filename = url.fileURLToPath(import.meta.url); -const dirname = path.dirname(filename); - -export const isDev = !dirname.includes('dist'); - export const startDevServer = async ( emailsDirRelativePath: string, staticBaseDirRelativePath: string, @@ -143,7 +138,7 @@ export const startDevServer = async ( const app = next({ // passing in env here does not get the environment variables there - dev: isDev, + dev: false, conf: { images: { // This is to avoid the warning with sharp diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 641c25dec..fabf3bfc0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,9 @@ importers: tsup: specifier: 8.4.0 version: 8.4.0(@microsoft/api-extractor@7.52.4(@types/node@22.14.1))(@swc/core@1.11.21)(jiti@2.4.2)(postcss@8.5.3)(tsx@4.19.3)(typescript@5.8.3)(yaml@2.6.1) + tsx: + specifier: 4.19.3 + version: 4.19.3 turbo: specifier: 2.5.4 version: 2.5.4 @@ -17006,7 +17009,7 @@ snapshots: picomatch: 4.0.2 postcss: 8.5.3 rollup: 4.39.0 - tinyglobby: 0.2.13 + tinyglobby: 0.2.14 optionalDependencies: '@types/node': 22.14.1 fsevents: 2.3.3