diff --git a/packages/react-email/package.json b/packages/react-email/package.json index cd6f66ceea..1c72b112f0 100644 --- a/packages/react-email/package.json +++ b/packages/react-email/package.json @@ -42,7 +42,8 @@ "next": "^15.3.1", "normalize-path": "^3.0.0", "ora": "^8.0.0", - "socket.io": "^4.8.1" + "socket.io": "^4.8.1", + "tsconfig-paths": "4.2.0" }, "devDependencies": { "@babel/core": "7.26.10", diff --git a/packages/react-email/src/cli/utils/preview/hot-reloading/create-dependency-graph.spec.ts b/packages/react-email/src/cli/utils/preview/hot-reloading/create-dependency-graph.spec.ts index 493e455529..3dc9f1738c 100644 --- a/packages/react-email/src/cli/utils/preview/hot-reloading/create-dependency-graph.spec.ts +++ b/packages/react-email/src/cli/utils/preview/hot-reloading/create-dependency-graph.spec.ts @@ -52,7 +52,11 @@ test('createDependencyGraph()', async () => { }, 'create-dependency-graph.ts': { path: 'create-dependency-graph.ts', - dependencyPaths: ['../start-dev-server.ts', 'get-imported-modules.ts'], + dependencyPaths: [ + '../start-dev-server.ts', + 'get-imported-modules.ts', + 'resolve-path-aliases.ts', + ], dependentPaths: [ 'create-dependency-graph.spec.ts', 'setup-hot-reloading.ts', @@ -71,6 +75,27 @@ test('createDependencyGraph()', async () => { moduleDependencies: ['node:path'], path: '../../../utils/preview/get-env-variables-for-preview-app.ts', }, + './test/some-file.ts': { + dependencyPaths: [], + dependentPaths: [], + moduleDependencies: [], + path: '/home/gabriel/Projects/Resend/react-email/packages/react-email/src/cli/utils/preview/hot-reloading/test/some-file.ts', + }, + 'resolve-path-aliases.ts': { + path: 'resolve-path-aliases.ts', + dependentPaths: [ + 'create-dependency-graph.ts', + 'resolve-path-aliases.spec.ts', + ], + dependencyPaths: [], + moduleDependencies: ['node:path', 'tsconfig-paths'], + }, + 'resolve-path-aliases.spec.ts': { + path: 'resolve-path-aliases.spec.ts', + dependencyPaths: ['resolve-path-aliases.ts'], + dependentPaths: [], + moduleDependencies: ['node:path'], + }, 'get-imported-modules.ts': { path: 'get-imported-modules', dependentPaths: [ diff --git a/packages/react-email/src/cli/utils/preview/hot-reloading/create-dependency-graph.ts b/packages/react-email/src/cli/utils/preview/hot-reloading/create-dependency-graph.ts index 418d66f3ab..0462779dbb 100644 --- a/packages/react-email/src/cli/utils/preview/hot-reloading/create-dependency-graph.ts +++ b/packages/react-email/src/cli/utils/preview/hot-reloading/create-dependency-graph.ts @@ -3,6 +3,7 @@ import path from 'node:path'; import type { EventName } from 'chokidar/handler'; import { isDev } from '../start-dev-server'; import { getImportedModules } from './get-imported-modules'; +import { resolvePathAliases } from './resolve-path-aliases'; interface Module { path: string; @@ -93,9 +94,8 @@ export const createDependencyGraph = async (directory: string) => { const getDependencyPaths = async (filePath: string) => { const contents = await fs.readFile(filePath, 'utf8'); - const importedPaths = isJavascriptModule(filePath) - ? getImportedModules(contents) + ? resolvePathAliases(getImportedModules(contents), path.dirname(filePath)) : []; const importedPathsRelativeToDirectory = importedPaths.map( (dependencyPath) => { diff --git a/packages/react-email/src/cli/utils/preview/hot-reloading/resolve-path-aliases.spec.ts b/packages/react-email/src/cli/utils/preview/hot-reloading/resolve-path-aliases.spec.ts new file mode 100644 index 0000000000..8e50824db2 --- /dev/null +++ b/packages/react-email/src/cli/utils/preview/hot-reloading/resolve-path-aliases.spec.ts @@ -0,0 +1,11 @@ +import path from 'node:path'; +import { resolvePathAliases } from './resolve-path-aliases'; + +test('resolveImports()', async () => { + expect( + resolvePathAliases( + ['@/some-file'], + path.resolve(import.meta.dirname, './test'), + ), + ).toEqual(['./some-file']); +}); diff --git a/packages/react-email/src/cli/utils/preview/hot-reloading/resolve-path-aliases.ts b/packages/react-email/src/cli/utils/preview/hot-reloading/resolve-path-aliases.ts new file mode 100644 index 0000000000..c7a42aa71f --- /dev/null +++ b/packages/react-email/src/cli/utils/preview/hot-reloading/resolve-path-aliases.ts @@ -0,0 +1,32 @@ +import path from 'node:path'; +import { createMatchPath, loadConfig } from 'tsconfig-paths'; + +export const resolvePathAliases = ( + importPaths: string[], + projectPath: string, +) => { + const configLoadResult = loadConfig(projectPath); + + if (configLoadResult.resultType === 'success') { + const matchPath = createMatchPath( + configLoadResult.absoluteBaseUrl, + configLoadResult.paths, + ); + return importPaths.map((importedPath) => { + const unaliasedPath = matchPath(importedPath, undefined, undefined, [ + '.tsx', + '.ts', + '.js', + '.jsx', + '.cjs', + '.mjs', + ]); + if (unaliasedPath) { + return `./${path.relative(projectPath, unaliasedPath)}`; + } + return importedPath; + }); + } + + return importPaths; +}; diff --git a/packages/react-email/src/cli/utils/preview/hot-reloading/test/some-file.ts b/packages/react-email/src/cli/utils/preview/hot-reloading/test/some-file.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/react-email/src/cli/utils/preview/hot-reloading/test/tsconfig.json b/packages/react-email/src/cli/utils/preview/hot-reloading/test/tsconfig.json new file mode 100644 index 0000000000..e7b79fe3aa --- /dev/null +++ b/packages/react-email/src/cli/utils/preview/hot-reloading/test/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "paths": { + "@/*": ["./*"] + } + }, + "include": ["**/*.ts", "**/*.tsx"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ad037dc7cc..290382e5f2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -656,6 +656,9 @@ importers: socket.io: specifier: ^4.8.1 version: 4.8.1 + tsconfig-paths: + specifier: 4.2.0 + version: 4.2.0 devDependencies: '@babel/core': specifier: 7.26.10 @@ -6167,6 +6170,9 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} @@ -7615,6 +7621,10 @@ packages: ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -14246,6 +14256,8 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimist@1.2.8: {} + minipass@3.3.6: dependencies: yallist: 4.0.0 @@ -16138,6 +16150,12 @@ snapshots: ts-interface-checker@0.1.13: {} + tsconfig-paths@4.2.0: + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 + tslib@1.14.1: {} tslib@2.8.1: {}