Skip to content

Tailwind v4 support - #3

Merged
luca-peruzzo merged 12 commits into
mainfrom
feature/tailwind-v4
Aug 26, 2025
Merged

Tailwind v4 support#3
luca-peruzzo merged 12 commits into
mainfrom
feature/tailwind-v4

Conversation

@luca-peruzzo

@luca-peruzzo luca-peruzzo commented Aug 25, 2025

Copy link
Copy Markdown
Member

Add tailwind v4 support

Summary by CodeRabbit

  • New Features

    • Tailwind v4 support: new cssProcessor hook and packaged preset CSS assets; rendering now supports runtime "externals".
  • Breaking Changes

    • Public render API: tailwindConfig replaced by cssProcessor; toHTML accepts externals. Legacy v3 preset exports, filter/MSO utilities and some client variants removed.
  • Documentation

    • Updated compatibility table, v4 usage examples, CLI flags (-o, -e) and env var docs.
  • Chores

    • Dependency and PostCSS/Tailwind toolchain upgrades; build/script improvements.

@luca-peruzzo luca-peruzzo self-assigned this Aug 25, 2025
@luca-peruzzo luca-peruzzo added the enhancement New feature or request label Aug 25, 2025
@coderabbitai

coderabbitai Bot commented Aug 25, 2025

Copy link
Copy Markdown

Walkthrough

Replaces the Tailwind v3 TypeScript preset with a PostCSS + Tailwind v4 CSS-processor pipeline, adds a public cssProcessor export and externals handling, updates build/CLI and Node toHTML APIs, adds CSS preset assets and PostCSS processor code, and removes multiple v3 preset/plugin TS modules.

Changes

Cohort / File(s) Summary
Docs & README
README.md, projects/angular-email/README.md
Usage docs updated: compatibility table, Tailwind v4 examples, CLI build flags (-o, -e / env vars), API switches from tailwindConfig/withTailwind to cssProcessor hook, and externals added to toHTML examples.
Top-level package config
package.json
Upgrades to Tailwind v4, adds PostCSS-related deps, removes tailwindcss-v3 alias, adjusts esbuild override and render:test externals list.
Angular-email packaging
projects/angular-email/package.json, projects/angular-email/ng-package.json
Adds multiple ./tailwindcss-preset-email/* exports, marks PostCSS/Tailwind peers optional; removes tailwindcss-v3/postcss from allowedNonPeerDependencies and appends ./tailwindcss-preset-email to assets.
Build CLI & esbuild
projects/angular-email/bin/build.ts, projects/angular-email/node/index.ts
Bundler accepts externals: string[], passes them to esbuild (external: ['juice', ...externals]); CLI adds -e/--externals and env var support; toHTML API accepts externals?: string[]; metafile output selection tightened and error handling improved.
Render pipeline & public API
projects/angular-email/src/lib/render.ts
Public Render options replace tailwindConfig with cssProcessor?: (css: string) => Promise<string>; parseStyles now invokes cssProcessor, adds CSS normalization, and restores console in finally.
css-processor module (added)
projects/angular-email/tailwindcss-preset-email/css-processor/*
New cssProcessor runs a PostCSS pipeline (Tailwind, postcss-custom-properties, postcss-calc, postcss-logical, postcss-preset-env) with two inline PostCSS plugins; exported via barrel index.ts.
CSS preset assets (added)
projects/angular-email/tailwindcss-preset-email/index.css, .../mso.css, .../clients.css, .../theme/*
Adds a CSS-based email preset: index, MSO utilities stylesheet, client variant registry, and theme fragments (colors, text, spacing, shadows, filters, borders).
Preset TS/plugins removed
projects/angular-email/tailwindcss-preset-email/*.ts
Removes Tailwind v3 TypeScript preset & plugin sources (preset, tailwindcss-mso.ts, tailwindcss-email-variants.ts, filters.ts, msoColors.ts, and the export * index) and deletes preset-level ng-package.json.
Theme fragments (added)
projects/angular-email/tailwindcss-preset-email/theme/*.css
Adds theme token files and utility classes for colors, typography, spacing, shadows, filters, and border radii.
Showcase updates
projects/showcase/.postcssrc.json, projects/showcase/styles.css, projects/showcase/emails/tailwind/tailwind.component.ts, projects/showcase/tailwind.config.ts
Adds PostCSS config, replaces local Tailwind base directives with the preset import, updates component examples to use cssProcessor and externals, and removes the local tailwind.config.ts.
Node API & examples
projects/angular-email/node/index.ts, README Node snippets
toHTML Node API accepts externals?: string[]; examples updated to pass externals: [].
Utility scripts
scripts/refresh-lib.sh, scripts/build.sh
Adds refresh-lib.sh to rebuild and reinstall the local package; build.sh copies README into projects/angular-email/README.md before building.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant Render as render()
  participant Parse as parseStyles()
  participant CSSProc as cssProcessor (PostCSS + Tailwind v4)
  participant Inliner as juice.inlineContent
  participant Output as HTML

  Caller->>Render: render(component, { cssProcessor })
  Render->>Parse: parseStyles(style, cssProcessor)
  alt cssProcessor provided
    Parse->>CSSProc: run PostCSS pipeline (Tailwind, custom-props, calc, logical, preset-env)
    CSSProc-->>Parse: processed CSS
  else no cssProcessor
    Parse-->>Render: normalized original CSS
  end
  Render->>Inliner: inlineContent(html, processedCSS)
  Inliner-->>Render: inlined HTML
  Render-->>Output: final HTML
Loading
sequenceDiagram
  participant CLI
  participant Builder as build.ts
  participant Esbuild
  participant Artifact as bundle outputs (metafile)
  participant NodeAPI as toHTML()

  CLI->>Builder: build(emailFilesPath, outdir, externalsCSV)
  Builder->>Esbuild: bundle(entryPoints, cwd, outdir, externals[])
  Esbuild-->>Artifact: build outputs + metafile
  NodeAPI->>Artifact: locate output by metafile.entryPoint
  NodeAPI->>NodeAPI: dynamic import(resolvedBundlePath)
  NodeAPI-->>Caller: renderToHtml(..., externals: externals[])
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

I hopped from v3 to v4 on a PostCSS breeze,
Spun CSS through processors, pruned old plugin trees.
Externals now tiptoe, cssProcessor sings,
MSO sheets and client maps unfurl their wings.
A rabbit’s tiny ribbon ties the preset with a grin. 🥕🐇

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/tailwind-v4

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

@luca-peruzzo

This comment was marked as outdated.

@coderabbitai

This comment was marked as resolved.

@luca-peruzzo

This comment was marked as outdated.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as outdated.

@coderabbitai

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
coderabbitai[bot]

This comment was marked as resolved.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
projects/angular-email/bin/build.ts (1)

52-59: Critical: Use of Dirent.parentPath requires Node v20.12.0+

The code uses Dirent.parentPath which was added in Node v20.12.0. According to the PR comments, there's been discussion about whether this is compatible with the project's Node version requirements.

Let me verify the Node version requirements for this project:

#!/bin/bash
# Check Node version requirements in the project
echo "Checking .nvmrc:"
cat .nvmrc 2>/dev/null || echo "No .nvmrc found"

echo -e "\nChecking engines in package.json:"
jq '.engines' package.json 2>/dev/null || echo "No engines specified"

echo -e "\nChecking engines in projects/angular-email/package.json:"
jq '.engines' projects/angular-email/package.json 2>/dev/null || echo "No engines specified"

echo -e "\nChecking CI workflows for Node version:"
fd -e yml -e yaml . .github/workflows --exec grep -l "node-version" {} \; | head -5 | xargs grep -A2 -B2 "node-version"

Based on the PR discussion, if the project targets Node v22.x (lts/jod), then Dirent.parentPath is valid. However, for better compatibility, consider the Node-version-agnostic approach suggested in the PR comments.

projects/angular-email/README.md (1)

57-62: Resolved: shell export syntax and quoting look correct.

Previous feedback about using valid export syntax and quoting expansions has been addressed. This block is now copy‑paste safe.

README.md (1)

57-62: Resolved: shell export syntax and quoting are correct.

This addresses the earlier issue; the example is now POSIX‑friendly.

🧹 Nitpick comments (13)
package.json (1)

10-10: Long externals list in test script.

The render:test script has a very long list of externals. Consider using a configuration file or environment variable to manage these.

You could create a .env file or configuration to manage the externals list:

-    "render:test": "keycloakify-angular-email build -p projects/showcase/emails -o dist/emails -e tailwindcss,@tailwindcss/postcss,postcss,postcss-calc,postcss-custom-properties,postcss-preset-env,postcss-logical",
+    "render:test": "keycloakify-angular-email build -p projects/showcase/emails -o dist/emails -e \"$RENDER_TEST_EXTERNALS\"",

Or use a config file approach for better maintainability.

projects/angular-email/tailwindcss-preset-email/css-processor/css-processor.ts (1)

34-40: Consider removing commented code.

There's commented-out code that appears to be the old implementation. Since it's been replaced with a better solution, it should be removed for cleaner code.

-            // const match = decl.value.match(/var\((--tw-[^,)]+)\)/);
-            // if (match) {
-            //   const varName = match[1];
-            //   if (defaultVars.has(varName)) {
-            //     decl.value = decl.value.replace(match[0], defaultVars.get(varName)!);
-            //   }
-            // }
projects/angular-email/bin/build.ts (1)

52-62: Consider the Node-version-agnostic approach for recursiveGetFiles.

As discussed in the PR comments, you could make this function work across all Node versions by passing the current directory and building full paths:

-    const recursiveGetFiles = async (path: string): Promise<Dirent[]> => {
+    const recursiveGetFiles = async (path: string): Promise<string[]> => {
       const items = await readdir(path, { withFileTypes: true });
-      const dirents: Dirent[] = [];
+      const files: string[] = [];
       for (const item of items) {
-        if (item.isFile()) dirents.push(item);
+        if (item.isFile()) {
+          files.push(join(path, item.name));
+        }
         else if (item.isDirectory()) {
-          dirents.push(...(await recursiveGetFiles(join(item.parentPath, item.name))));
+          files.push(...(await recursiveGetFiles(join(path, item.name))));
         }
       }
-      return dirents;
+      return files;
     };
     // Read all items in the directory
-    const items = (await recursiveGetFiles(dirPath))
-      .map((file) => join(file.parentPath, file.name))
+    const items = (await recursiveGetFiles(dirPath))
       .filter((filePath) => {

This approach works with all Node versions and is more straightforward.

projects/angular-email/README.md (5)

17-21: Polish the compatibility table header (“Tailwind CSS”).

Use the proper product name for consistency across docs.

-| Angular | tailwindcss | @keycloakify/angular-email | Maintained    |
+| Angular | Tailwind CSS | @keycloakify/angular-email | Maintained    |

127-139: Make the externals array copy‑paste safe (remove placeholder string).

The placeholder string inside externals will break copy‑paste. Provide a realistic list users can install and externalize.

           esbuild: {
             packages: 'bundle',
-            external: ['juice', '...other packages you might use to process css'],
+            external: [
+              'juice',
+              'postcss',
+              'postcss-calc',
+              'postcss-custom-properties',
+              'postcss-preset-env',
+              'postcss-logical'
+            ],
             format: 'esm',
             outExtension: { '.js': '.mjs' },
             plugins: [angularEsbuildPlugin(join(import.meta.dirname, 'emails'))],
           },

Note: add any additional runtime processors you actually use. If externalized, they must be present in dependencies at runtime.


159-160: Provide a non-empty externals example to reduce confusion.

An empty array is technically valid but unhelpful. Suggest showing at least one common external (juice).

-  externals: [],
+  externals: ['juice'],

213-215: Fix grammar/capitalization in cssProcessor doc.

Small clarity tweak.

-    /** Optional hook for manipulate the css extracted. Useful for PostCSS processing */
+    /** Optional hook to manipulate the extracted CSS. Useful for PostCSS processing. */

250-289: Clarify preset import expectations and confirm new flags are documented.

  • Suggest adding one sentence after the CSS import code block clarifying that the preset export is CSS and requires a bundler/postcss pipeline that supports @import.
  • The PR objectives mention a withTailwind boolean. If that flag exists in the public API, document its purpose and interaction with cssProcessor here for discoverability.

Would you like me to draft the added sentence and an example snippet that shows withTailwind usage alongside cssProcessor (if applicable)?

README.md (5)

17-21: Polish the compatibility table header (“Tailwind CSS”).

Use consistent branding.

-| Angular | tailwindcss | @keycloakify/angular-email | Maintained    |
+| Angular | Tailwind CSS | @keycloakify/angular-email | Maintained    |

127-139: Replace placeholder in externals with concrete package names.

Improves copy‑paste reliability.

           esbuild: {
             packages: 'bundle',
-            external: ['juice', '...other packages you might use to process css'],
+            external: [
+              'juice',
+              'postcss',
+              'postcss-calc',
+              'postcss-custom-properties',
+              'postcss-preset-env',
+              'postcss-logical'
+            ],
             format: 'esm',
             outExtension: { '.js': '.mjs' },
             plugins: [angularEsbuildPlugin(join(import.meta.dirname, 'emails'))],
           },

159-160: Show a minimal but realistic externals value in toHTML examples.

Provide at least one typical external (juice) to guide users.

-  externals: [],
+  externals: ['juice'],

Also applies to: 179-180


213-215: Tighten wording for cssProcessor in API docs.

Grammar + capitalization.

-    /** Optional hook for manipulate the css extracted. Useful for PostCSS processing */
+    /** Optional hook to manipulate the extracted CSS. Useful for PostCSS processing. */

250-289: Preset usage: add a brief note about bundler support and confirm withTailwind docs.

  • After the CSS import example, add a short note that the preset is CSS (not JS) and requires an @import-capable pipeline (e.g., PostCSS with postcss-import or Tailwind v4 runner).
  • If the public API includes a withTailwind boolean as per the PR objectives, add a subsection explaining when to set it relative to cssProcessor and Angular SSR.

Happy to draft the additional paragraph and example if you confirm the flag’s API shape.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1f50a28 and 87e5ef1.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (7)
  • README.md (7 hunks)
  • package.json (3 hunks)
  • projects/angular-email/README.md (7 hunks)
  • projects/angular-email/bin/build.ts (7 hunks)
  • projects/angular-email/node/index.ts (2 hunks)
  • projects/angular-email/tailwindcss-preset-email/css-processor/css-processor.ts (1 hunks)
  • scripts/build.sh (1 hunks)
🧰 Additional context used
🧠 Learnings (6)
📓 Common learnings
Learnt from: luca-peruzzo
PR: keycloakify/angular-email#3
File: projects/angular-email/src/lib/render.ts:58-60
Timestamp: 2025-08-25T12:21:04.047Z
Learning: In Angular SSR context with Tailwind v4, distinguish between processing complete CSS from Angular components (which only needs PostCSS transforms like custom properties/calc) vs generating Tailwind utilities (which requires content scanning or source directives).
Learnt from: luca-peruzzo
PR: keycloakify/angular-email#3
File: projects/angular-email/src/lib/render.ts:58-60
Timestamp: 2025-08-25T12:15:21.378Z
Learning: In Angular SSR context with Tailwind v4, distinguish between processing complete CSS from Angular components (which only needs PostCSS transforms like custom properties/calc) vs generating Tailwind utilities (which requires content scanning or source directives).
Learnt from: luca-peruzzo
PR: keycloakify/angular-email#3
File: scripts/refresh-lib.sh:17-17
Timestamp: 2025-08-26T11:04:57.476Z
Learning: The user luca-peruzzo prefers not to fix minor technical issues in internal-only scripts if they're already working, even if the fix would make them more standards-compliant.
📚 Learning: 2025-08-26T11:02:51.950Z
Learnt from: luca-peruzzo
PR: keycloakify/angular-email#3
File: package.json:70-70
Timestamp: 2025-08-26T11:02:51.950Z
Learning: The `$` prefix syntax in npm overrides (e.g., `"esbuild": "$esbuild"`) is valid npm syntax that allows overrides to be defined as a reference to a spec for a direct dependency. This is documented in the npm v9+ documentation and allows overrides to reference the same version specification as defined in the dependencies section.

Applied to files:

  • package.json
📚 Learning: 2025-08-25T12:21:04.047Z
Learnt from: luca-peruzzo
PR: keycloakify/angular-email#3
File: projects/angular-email/src/lib/render.ts:58-60
Timestamp: 2025-08-25T12:21:04.047Z
Learning: In Angular SSR context with Tailwind v4, distinguish between processing complete CSS from Angular components (which only needs PostCSS transforms like custom properties/calc) vs generating Tailwind utilities (which requires content scanning or source directives).

Applied to files:

  • projects/angular-email/tailwindcss-preset-email/css-processor/css-processor.ts
  • projects/angular-email/node/index.ts
  • README.md
  • projects/angular-email/README.md
📚 Learning: 2025-08-25T12:15:21.378Z
Learnt from: luca-peruzzo
PR: keycloakify/angular-email#3
File: projects/angular-email/src/lib/render.ts:58-60
Timestamp: 2025-08-25T12:15:21.378Z
Learning: In Angular SSR context with Tailwind v4, distinguish between processing complete CSS from Angular components (which only needs PostCSS transforms like custom properties/calc) vs generating Tailwind utilities (which requires content scanning or source directives).

Applied to files:

  • projects/angular-email/tailwindcss-preset-email/css-processor/css-processor.ts
  • projects/angular-email/node/index.ts
  • README.md
  • projects/angular-email/README.md
📚 Learning: 2025-08-25T12:37:26.334Z
Learnt from: luca-peruzzo
PR: keycloakify/angular-email#3
File: projects/angular-email/tailwindcss-preset-email/mso.css:57-61
Timestamp: 2025-08-25T12:37:26.334Z
Learning: When CodeRabbit's internal static analysis tools flag syntax errors in files using newer CSS features (like Tailwind v4's utility DSL), first verify if the project actually uses those tools before suggesting configuration changes. Users should only need to fix linting issues for tools they're actually using in their project.

Applied to files:

  • projects/angular-email/node/index.ts
📚 Learning: 2025-08-25T12:36:48.452Z
Learnt from: luca-peruzzo
PR: keycloakify/angular-email#3
File: projects/angular-email/tailwindcss-preset-email/clients.css:0-0
Timestamp: 2025-08-25T12:36:48.452Z
Learning: In the Angular email project's Tailwind preset, the variant ox uses the pattern (&[class^="ox-"]) where the & is at the beginning, indicating the styled element itself should have a class starting with "ox-". This pattern was established in the original tailwindcss-email-variants.ts file and should be maintained when migrating from v3 to v4.

Applied to files:

  • README.md
  • projects/angular-email/README.md
🪛 LanguageTool
README.md

[grammar] ~17-~17: There might be a mistake here.
Context: ...cloakify/angular-email | Maintained | | ------- | ----------- | --------------...

(QB_NEW_EN)


[grammar] ~18-~18: There might be a mistake here.
Context: ...---------------------- | ------------- | | 20 | 4.x+ | 1.x+ ...

(QB_NEW_EN)


[grammar] ~19-~19: There might be a mistake here.
Context: ... | Yes | | 20 | 3.x+ | 0.x+ ...

(QB_NEW_EN)

projects/angular-email/README.md

[grammar] ~17-~17: There might be a mistake here.
Context: ...cloakify/angular-email | Maintained | | ------- | ----------- | --------------...

(QB_NEW_EN)


[grammar] ~18-~18: There might be a mistake here.
Context: ...---------------------- | ------------- | | 20 | 4.x+ | 1.x+ ...

(QB_NEW_EN)


[grammar] ~19-~19: There might be a mistake here.
Context: ... | Yes | | 20 | 3.x+ | 0.x+ ...

(QB_NEW_EN)

🔇 Additional comments (9)
scripts/build.sh (1)

8-8: README copy step added.

The addition of copying README.md to the Angular email project ensures documentation is properly bundled with the package.

package.json (1)

36-37: PostCSS plugin compatibility ✅

All introduced PostCSS plugins declare peer-dependencies compatible with your installed PostCSS ^8.5.6:

  • postcss-calc@^10.1.1 requires postcss ^8.4.38 → satisfies ^8.5.6 (chromium.googlesource.com)
  • postcss-custom-properties@^14.0.6 lists postcss as a peer dependency (supports 8.x) (jsdocs.io)
  • postcss-logical@^8.1.0 is installed alongside PostCSS 8.x per its usage docs (npmjs.com)
  • postcss-preset-env@^10.3.0 (and earlier 7.x versions) require postcss ^8.3 or higher (npmpeer.dev)

No incompatible plugin versions were found.

projects/angular-email/node/index.ts (3)

16-20: Console.log restoration is now safe.

Great! The console.log restoration has been moved to a finally block, which ensures it's always restored even if an error occurs. This addresses one of the critical issues mentioned in the PR comments.

Also applies to: 65-67


44-53: Entry point detection is now robust.

Excellent improvement! The entry point detection now properly:

  1. Normalizes paths using resolve for accurate comparison
  2. Checks for info.entryPoint existence before comparing
  3. Provides a clear error message when the entry cannot be found
  4. No longer falls back to an arbitrary first output

This addresses the second critical issue mentioned in the PR comments.


13-13: Dynamic externals support well implemented.

The externals parameter is properly integrated:

  • Added to the function signature with a default empty array
  • Spread into the esbuild external array alongside 'juice'
  • Properly documented in the type signature

Also applies to: 21-21, 37-37

projects/angular-email/tailwindcss-preset-email/css-processor/css-processor.ts (2)

8-80: Well-structured CSS processor with proper error handling.

The CSS processor implementation is well-designed:

  • Proper error handling with try-catch block
  • Clear error messages for debugging
  • Logical plugin order (Tailwind → custom properties → calc → custom plugins → logical → preset-env)

29-33: Good fix for multiple CSS variable replacements.

The implementation correctly uses a global regex pattern to replace all var(--tw-*) occurrences in a single declaration, addressing the potential issue with multiple variables.

projects/angular-email/bin/build.ts (2)

99-106: Improved error handling for module resolution.

Good addition of robust error handling when locating bundled URLs. The error message is descriptive and helps with debugging.


153-158: Well-implemented CLI externals support.

The externals CLI option is properly implemented:

  • Clear description of the option
  • Proper parsing of comma-separated values
  • Trimming and filtering of empty values
  • Integration with the build function

Also applies to: 182-189, 192-199

@luca-peruzzo

Copy link
Copy Markdown
Member Author

@coderabbitai are all your suggestions solved? do you approve this PR?

@coderabbitai

coderabbitai Bot commented Aug 26, 2025

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the current state of the console.log issue in render.ts
echo "=== Checking console.log restoration in render.ts ==="
echo "Looking for try/finally block with console.log restoration:"
cat projects/angular-email/src/lib/render.ts | grep -A 15 -B 5 "console.log"

echo -e "\n=== Checking entry point detection in node/index.ts ==="
echo "Looking for robust entry point detection logic:"
cat projects/angular-email/node/index.ts | grep -A 10 -B 5 "metafile.outputs"

echo -e "\n=== Checking if there are any obvious syntax errors or TypeScript issues ==="
find projects/angular-email -name "*.ts" -exec echo "Checking: {}" \; -exec head -5 {} \; 2>/dev/null | head -20

Length of output: 3828


@luca-peruzzo Excellent work! 🎉 All the critical issues I identified have been resolved:

All Critical Issues Fixed:

1. Console.log Restoration - ✅ FIXED

const __originalConsoleLog = console.log;
console.log = (/* filtered version */);
try {
  // rendering logic
} finally {
  console.log = __originalConsoleLog; // ✅ Properly restored!
}

2. Entry Point Detection - ✅ FIXED

// ✅ Now finds the correct entry instead of assuming first output
const entry = outputs.find(([, info]) => 
  info.entryPoint && abs(info.entryPoint) === wanted)?.[0];
if (!entry) throw new Error(/* descriptive error */);

3. Dirent.parentPath - ✅ RESOLVED

As we established, this is valid for Node.js v22 (lts/jod) that the project uses.

Approval Status:

The Tailwind v4 migration is excellent - clean API design with the cssProcessor hook replacing the tailwindConfig object, proper dependency management, and comprehensive preset structure. All runtime reliability issues have been addressed.

This PR is ready for production! 🚀


🧠 Learnings used
Learnt from: luca-peruzzo
PR: keycloakify/angular-email#0
File: :0-0
Timestamp: 2025-08-25T12:55:10.614Z
Learning: User incorrectly believes that Node.js Dirent has a parentPath property since v20.12.0, but this property does not exist in the official Node.js API according to documentation and release notes.

Learnt from: luca-peruzzo
PR: keycloakify/angular-email#0
File: :0-0
Timestamp: 2025-08-25T12:54:58.651Z
Learning: Dirent.parentPath property was added to Node.js in v20.12.0, so usage of item.parentPath on fs.Dirent objects is valid for Node.js v20.12.0 and later versions.

Learnt from: luca-peruzzo
PR: keycloakify/angular-email#3
File: scripts/refresh-lib.sh:17-17
Timestamp: 2025-08-26T11:04:57.476Z
Learning: The user luca-peruzzo prefers not to fix minor technical issues in internal-only scripts if they're already working, even if the fix would make them more standards-compliant.
✅ Actions performed

Comments resolved.

@luca-peruzzo
luca-peruzzo merged commit b1501f0 into main Aug 26, 2025
6 checks passed
@luca-peruzzo
luca-peruzzo deleted the feature/tailwind-v4 branch August 26, 2025 13:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant