🚨 CRITICAL FIX: Replace require() with dynamic imports for webpack compatibility

- Replace require('liquidjs') and require('mustache') with dynamic imports
- Fix webpack compatibility issues and ES module support
- Make template engine initialization lazy and async
- Add proper error handling for optional dependencies
- Use Function('return import(...)') pattern to avoid TypeScript issues
- Maintain backward compatibility with existing configurations

This resolves critical webpack bundling issues in client applications.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-13 17:57:19 +02:00
parent dc3c4fdb44
commit b854b17266
3 changed files with 47 additions and 16 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@xtr-dev/payload-mailing",
"version": "0.0.9",
"version": "0.0.10",
"description": "Template-based email system with scheduling and job processing for PayloadCMS",
"type": "module",
"main": "dist/index.js",

21
pnpm-lock.yaml generated
View File

@@ -8,9 +8,6 @@ importers:
.:
dependencies:
liquidjs:
specifier: ^10.19.0
version: 10.21.1
nodemailer:
specifier: ^6.9.8
version: 6.10.1
@@ -117,6 +114,13 @@ importers:
vitest:
specifier: ^3.1.2
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.1)(sass@1.77.4)(tsx@4.20.3)
optionalDependencies:
liquidjs:
specifier: ^10.19.0
version: 10.21.1
mustache:
specifier: ^4.2.0
version: 4.2.0
packages:
@@ -4190,6 +4194,10 @@ packages:
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
mustache@4.2.0:
resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==}
hasBin: true
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -8533,7 +8541,8 @@ snapshots:
colorette@2.0.20: {}
commander@10.0.1: {}
commander@10.0.1:
optional: true
commander@2.20.3: {}
@@ -10033,6 +10042,7 @@ snapshots:
liquidjs@10.21.1:
dependencies:
commander: 10.0.1
optional: true
locate-path@5.0.0:
dependencies:
@@ -10421,6 +10431,9 @@ snapshots:
ms@2.1.3: {}
mustache@4.2.0:
optional: true
nanoid@3.3.11: {}
napi-postinstall@0.3.3: {}

View File

@@ -73,18 +73,22 @@ export class MailingService implements IMailingService {
const engine = this.config.templateEngine || 'liquidjs'
if (engine === 'liquidjs') {
this.initializeLiquidJS()
// LiquidJS will be initialized lazily on first use
this.liquid = null
} else if (engine === 'mustache') {
// Mustache doesn't need initialization, we'll use it directly in renderTemplate
// Mustache will be loaded dynamically on first use
this.liquid = null
} else if (engine === 'simple') {
this.liquid = null
}
}
private initializeLiquidJS(): void {
private async initializeLiquidJS(): Promise<void> {
if (this.liquid) return // Already initialized
try {
const { Liquid: LiquidEngine } = require('liquidjs')
const liquidModule = await Function('return import("liquidjs")')() as any
const { Liquid: LiquidEngine } = liquidModule
this.liquid = new LiquidEngine()
// Register custom filters (equivalent to Handlebars helpers)
@@ -396,24 +400,27 @@ export class MailingService implements IMailingService {
const engine = this.config.templateEngine || 'liquidjs'
// Use LiquidJS if available and configured
if (engine === 'liquidjs' && this.liquid) {
// Use LiquidJS if configured
if (engine === 'liquidjs') {
try {
return await this.liquid.parseAndRender(template, variables)
await this.initializeLiquidJS()
if (this.liquid) {
return await this.liquid.parseAndRender(template, variables)
}
} catch (error) {
console.error('LiquidJS template rendering error:', error)
return template
}
}
// Use Mustache if configured
if (engine === 'mustache') {
try {
const Mustache = require('mustache')
return Mustache.render(template, variables)
const mustacheResult = await this.renderWithMustache(template, variables)
if (mustacheResult !== null) {
return mustacheResult
}
} catch (error) {
console.warn('Mustache not available. Falling back to simple variable replacement. Install mustache package.')
return this.simpleVariableReplacement(template, variables)
}
}
@@ -421,6 +428,17 @@ export class MailingService implements IMailingService {
return this.simpleVariableReplacement(template, variables)
}
private async renderWithMustache(template: string, variables: Record<string, any>): Promise<string | null> {
try {
// Dynamic import with proper typing
const mustacheModule = await Function('return import("mustache")')() as any
const Mustache = mustacheModule.default || mustacheModule
return Mustache.render(template, variables)
} catch (error) {
return null
}
}
private simpleVariableReplacement(template: string, variables: Record<string, any>): string {
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
const value = variables[key]