diff --git a/apps/demo/emails/local-assets.tsx b/apps/demo/emails/local-assets.tsx new file mode 100644 index 00000000..bb7e5623 --- /dev/null +++ b/apps/demo/emails/local-assets.tsx @@ -0,0 +1,68 @@ +import { Body, Container, Head, Hr, Html, Img, Link, Preview, Section, Text } from 'jsx-email'; + +import * as React from 'react'; + +export const TemplateName = 'local-assets'; + +const main = { + backgroundColor: '#f6f9fc', + fontFamily: + '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif' +}; + +const container = { + backgroundColor: '#ffffff', + margin: '0 auto', + marginBottom: '64px', + padding: '20px 0 48px' +}; + +const box = { + padding: '0 48px' +}; + +const hr = { + borderColor: '#e6ebf1', + margin: '20px 0' +}; + +const paragraph = { + color: '#777', + fontSize: '16px', + lineHeight: '24px', + textAlign: 'left' as const +}; + +const anchor: React.CSSProperties = { + color: '#3869d4', + textDecoration: 'underline' +}; + +const baseUrl = import.meta.env.DEV + ? import.meta.resolve('./static/') + : 'https://assets.example.com/'; + +export const Template = () => { + const catUrl = `${baseUrl}cat.jpeg`; + return ( + + + This is our email preview text for + + +
+ Cat +
+ + URL: +
+ + {catUrl} + +
+
+
+ + + ); +}; diff --git a/apps/demo/emails/static/cat.jpeg b/apps/demo/emails/static/cat.jpeg new file mode 100644 index 00000000..6e680aeb Binary files /dev/null and b/apps/demo/emails/static/cat.jpeg differ diff --git a/apps/demo/package.json b/apps/demo/package.json index fb54449f..5f90eee1 100644 --- a/apps/demo/package.json +++ b/apps/demo/package.json @@ -9,5 +9,8 @@ }, "dependencies": { "jsx-email": "workspace:*" + }, + "devDependencies": { + "@types/node": "20.10.5" } } diff --git a/apps/demo/tsconfig.json b/apps/demo/tsconfig.json new file mode 100644 index 00000000..4ebca792 --- /dev/null +++ b/apps/demo/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../shared/tsconfig.base.json", + "compilerOptions": { + "module": "ESNext", + "types": ["./node_modules/jsx-email/node_modules/vite/client", "./node_modules/@types/node"] + } +} diff --git a/docs/components/image.md b/docs/components/image.md index b29b3aab..e918b611 100644 --- a/docs/components/image.md +++ b/docs/components/image.md @@ -28,6 +28,23 @@ referenced, so avoid using these. See [Can I Email](https://www.caniemail.com/features/image-svg/) for more information. ::: +::: tip +To use local images during development, you can resolve the path with node. +Just remember, for production, you'll need to host the images somewhere and +reference them with a URL. + +```jsx +import { Img } from 'jsx-email'; + +const baseUrl = import.meta.DEV ? import.meta.resolve('../assets/') : 'https://assets.example.com/'; + +const Email = () => { + return Cat; +}; +``` + +::: + ## Component Props ```ts diff --git a/packages/jsx-email/src/cli/commands/preview.ts b/packages/jsx-email/src/cli/commands/preview.ts index b2859e59..64f75d6e 100644 --- a/packages/jsx-email/src/cli/commands/preview.ts +++ b/packages/jsx-email/src/cli/commands/preview.ts @@ -65,8 +65,8 @@ export const start = async (targetPath: string, argv: PreviewOptions) => { ...viteConfig.resolve?.alias } }, - server: { host, port: parseInt(port as any, 10) } - } as InlineConfig; + server: { fs: { strict: false }, host, port: parseInt(port.toString(), 10) } + } satisfies InlineConfig; const server = await createServer(mergedConfig); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 080c9373..834c2792 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -84,6 +84,10 @@ importers: react: specifier: 18.2.0 version: 18.2.0 + devDependencies: + '@types/node': + specifier: 20.10.5 + version: 20.10.5 apps/web: devDependencies: @@ -2264,7 +2268,7 @@ packages: resolution: {integrity: sha512-c0hrgAOVYr21EX8J0jBMXGLMgJqVf/v6yxi0dLaJboW9aQPh16Id+z6w2Tx1hm+piJOLv8xPfVKZCLfjPw/IMQ==} dependencies: '@types/jsonfile': 6.1.2 - '@types/node': 20.6.2 + '@types/node': 20.10.5 dev: true /@types/hast@3.0.1: @@ -2296,7 +2300,7 @@ packages: /@types/jsonfile@6.1.2: resolution: {integrity: sha512-8t92P+oeW4d/CRQfJaSqEwXujrhH4OEeHRjGU3v1Q8mUS8GPF3yiX26sw4svv6faL2HfBtGTe2xWIoVgN3dy9w==} dependencies: - '@types/node': 20.6.2 + '@types/node': 20.10.5 dev: true /@types/linkify-it@3.0.3: @@ -2332,6 +2336,12 @@ packages: resolution: {integrity: sha512-MG+oI3oelPKLN2gpkel08v6Tp6zU2zZQRq+eSpRsFtLNTd2kxZolOHQTmQQs0wqXTLOqs+ri3tRUaagH5u0quw==} dev: false + /@types/node@20.10.5: + resolution: {integrity: sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==} + dependencies: + undici-types: 5.26.5 + dev: true + /@types/node@20.6.2: resolution: {integrity: sha512-Y+/1vGBHV/cYk6OI1Na/LHzwnlNCAfU3ZNGrc1LdRe/LAIbdDPTTv/HU3M7yXN448aTVDq3eKRm2cg7iKLb8gw==} @@ -2356,7 +2366,7 @@ packages: /@types/prompts@2.4.8: resolution: {integrity: sha512-fPOEzviubkEVCiLduO45h+zFHB0RZX8tFt3C783sO5cT7fUXf3EEECpD26djtYdh4Isa9Z9tasMQuZnYPtvYzw==} dependencies: - '@types/node': 20.6.2 + '@types/node': 20.10.5 kleur: 3.0.3 dev: true @@ -7640,6 +7650,10 @@ packages: which-boxed-primitive: 1.0.2 dev: true + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + /unified@11.0.4: resolution: {integrity: sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==} dependencies: @@ -7789,7 +7803,7 @@ packages: vfile-message: 4.0.2 dev: false - /vite-node@0.34.5(@types/node@20.6.2): + /vite-node@0.34.5(@types/node@20.10.5): resolution: {integrity: sha512-RNZ+DwbCvDoI5CbCSQSyRyzDTfFvFauvMs6Yq4ObJROKlIKuat1KgSX/Ako5rlDMfVCyMcpMRMTkJBxd6z8YRA==} engines: {node: '>=v14.18.0'} hasBin: true @@ -7799,7 +7813,7 @@ packages: mlly: 1.4.2 pathe: 1.1.1 picocolors: 1.0.0 - vite: 4.4.9(@types/node@20.6.2) + vite: 4.4.9(@types/node@20.10.5) transitivePeerDependencies: - '@types/node' - less @@ -7825,6 +7839,42 @@ packages: - rollup dev: false + /vite@4.4.9(@types/node@20.10.5): + resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 20.10.5 + esbuild: 0.18.20 + postcss: 8.4.30 + rollup: 3.28.1 + optionalDependencies: + fsevents: 2.3.3 + dev: true + /vite@4.4.9(@types/node@20.6.2): resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==} engines: {node: ^14.18.0 || >=16.0.0} @@ -7944,7 +7994,7 @@ packages: dependencies: '@types/chai': 4.3.6 '@types/chai-subset': 1.3.3 - '@types/node': 20.6.2 + '@types/node': 20.10.5 '@vitest/expect': 0.34.5 '@vitest/runner': 0.34.5 '@vitest/snapshot': 0.34.5 @@ -7964,8 +8014,8 @@ packages: strip-literal: 1.3.0 tinybench: 2.5.1 tinypool: 0.7.0 - vite: 4.4.9(@types/node@20.6.2) - vite-node: 0.34.5(@types/node@20.6.2) + vite: 4.4.9(@types/node@20.10.5) + vite-node: 0.34.5(@types/node@20.10.5) why-is-node-running: 2.2.2 transitivePeerDependencies: - less