@maizzle/framework 6.0.0-3 → 6.0.0-5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [6.0.0-3] - 2025-07-14
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- added support for skipping CSS compilation on individual `<style>` tags by adding any of the following attributes: `raw`, `plain`, `as-is`, `uncompiled`, `unprocessed`
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- refactored CSS compilation into a custom PostHTML plugin
|
|
16
|
+
|
|
17
|
+
### Removed
|
|
18
|
+
|
|
19
|
+
- removed `posthtml-postcss` dependency
|
|
20
|
+
|
|
7
21
|
## [6.0.0-2] - 2025-07-11
|
|
8
22
|
|
|
9
23
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maizzle/framework",
|
|
3
|
-
"version": "6.0.0-
|
|
3
|
+
"version": "6.0.0-5",
|
|
4
4
|
"description": "Maizzle is a framework that helps you quickly build HTML emails with Tailwind CSS.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -86,7 +86,6 @@
|
|
|
86
86
|
"posthtml-markdownit": "^3.1.0",
|
|
87
87
|
"posthtml-mso": "^3.1.0",
|
|
88
88
|
"posthtml-parser": "^0.12.1",
|
|
89
|
-
"posthtml-postcss": "^1.0.2",
|
|
90
89
|
"posthtml-postcss-merge-longhand": "^3.1.2",
|
|
91
90
|
"posthtml-render": "^3.0.0",
|
|
92
91
|
"posthtml-safe-class-names": "^4.1.0",
|
package/src/posthtml/index.js
CHANGED
|
@@ -6,51 +6,17 @@ import posthtml from 'posthtml'
|
|
|
6
6
|
import posthtmlFetch from 'posthtml-fetch'
|
|
7
7
|
import envTags from './plugins/envTags.js'
|
|
8
8
|
import components from 'posthtml-component'
|
|
9
|
-
import posthtmlPostcss from 'posthtml-postcss'
|
|
10
9
|
import expandLinkTag from './plugins/expandLinkTag.js'
|
|
11
10
|
import envAttributes from './plugins/envAttributes.js'
|
|
12
11
|
import { getPosthtmlOptions } from './defaultConfig.js'
|
|
13
|
-
import lowerCssSyntax from './plugins/lowerCssSyntax.js'
|
|
14
12
|
import combineMediaQueries from './plugins/combineMediaQueries.js'
|
|
13
|
+
import defaultComponentsConfig from './defaultComponentsConfig.js'
|
|
14
|
+
import removeRawStyleAttributes from './plugins/removeRawStyleAttributes.js'
|
|
15
15
|
|
|
16
16
|
// PostCSS
|
|
17
|
-
import
|
|
18
|
-
import postcssCalc from 'postcss-calc'
|
|
19
|
-
import cssVariables from 'postcss-css-variables'
|
|
20
|
-
import postcssSafeParser from 'postcss-safe-parser'
|
|
21
|
-
import removeDuplicateSelectors from './plugins/postcss/removeDuplicateSelectors.js'
|
|
22
|
-
import cleanupTailwindArtifacts from './plugins/postcss/cleanupTailwindArtifacts.js'
|
|
23
|
-
|
|
24
|
-
import defaultComponentsConfig from './defaultComponentsConfig.js'
|
|
17
|
+
import { compileCss } from './plugins/postcss/compileCss.js'
|
|
25
18
|
|
|
26
19
|
export async function process(html = '', config = {}) {
|
|
27
|
-
/**
|
|
28
|
-
* Configure PostCSS pipeline. Plugins defined and added here
|
|
29
|
-
* will apply to all `<style>` tags in the HTML.
|
|
30
|
-
*/
|
|
31
|
-
const resolveCSSProps = get(config, 'css.resolveProps')
|
|
32
|
-
const resolveCalc = get(config, 'css.resolveCalc') !== false
|
|
33
|
-
? get(config, 'css.resolveCalc', { precision: 2 }) // it's true by default, use default precision 2
|
|
34
|
-
: false
|
|
35
|
-
|
|
36
|
-
const postcssPlugin = posthtmlPostcss(
|
|
37
|
-
[
|
|
38
|
-
tailwindcss(get(config, 'css.tailwind', {})),
|
|
39
|
-
resolveCSSProps !== false && cssVariables(resolveCSSProps),
|
|
40
|
-
resolveCalc !== false && postcssCalc(resolveCalc),
|
|
41
|
-
removeDuplicateSelectors(),
|
|
42
|
-
cleanupTailwindArtifacts(get(config, 'css.cleanup', {})),
|
|
43
|
-
...get(config, 'postcss.plugins', []),
|
|
44
|
-
],
|
|
45
|
-
merge(
|
|
46
|
-
get(config, 'postcss.options', {}),
|
|
47
|
-
{
|
|
48
|
-
from: config.cwd || './',
|
|
49
|
-
parser: postcssSafeParser
|
|
50
|
-
}
|
|
51
|
-
)
|
|
52
|
-
)
|
|
53
|
-
|
|
54
20
|
/**
|
|
55
21
|
* Define PostHTML options by merging user-provided ones
|
|
56
22
|
* on top of a default configuration.
|
|
@@ -106,18 +72,17 @@ export async function process(html = '', config = {}) {
|
|
|
106
72
|
|
|
107
73
|
return posthtml([
|
|
108
74
|
...beforePlugins,
|
|
109
|
-
|
|
110
|
-
envAttributes(config.env),
|
|
111
|
-
expandLinkTag(),
|
|
112
|
-
postcssPlugin,
|
|
75
|
+
compileCss(config),
|
|
113
76
|
fetchPlugin,
|
|
114
77
|
components(componentsConfig),
|
|
78
|
+
fetchPlugin,
|
|
115
79
|
expandLinkTag(),
|
|
116
|
-
postcssPlugin,
|
|
117
80
|
envTags(config.env),
|
|
118
81
|
envAttributes(config.env),
|
|
119
|
-
|
|
120
|
-
get(config, 'css.combineMediaQueries') !== false
|
|
82
|
+
compileCss(config),
|
|
83
|
+
get(config, 'css.combineMediaQueries') !== false
|
|
84
|
+
&& combineMediaQueries(get(config, 'css.combineMediaQueries', { sort: 'mobile-first' })),
|
|
85
|
+
removeRawStyleAttributes(),
|
|
121
86
|
...get(
|
|
122
87
|
config,
|
|
123
88
|
'posthtml.plugins.after',
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import postcss from 'postcss'
|
|
2
|
+
import get from 'lodash-es/get.js'
|
|
3
|
+
import { defu as merge } from 'defu'
|
|
4
|
+
import postcssCalc from 'postcss-calc'
|
|
5
|
+
import { transform } from 'lightningcss'
|
|
6
|
+
import tailwindcss from '@tailwindcss/postcss'
|
|
7
|
+
import cssVariables from 'postcss-css-variables'
|
|
8
|
+
import postcssSafeParser from 'postcss-safe-parser'
|
|
9
|
+
import removeDuplicateSelectors from './removeDuplicateSelectors.js'
|
|
10
|
+
import cleanupTailwindArtifacts from './cleanupTailwindArtifacts.js'
|
|
11
|
+
|
|
12
|
+
const attributes = new Set([
|
|
13
|
+
'raw',
|
|
14
|
+
'plain',
|
|
15
|
+
'as-is',
|
|
16
|
+
'uncompiled',
|
|
17
|
+
'unprocessed',
|
|
18
|
+
])
|
|
19
|
+
|
|
20
|
+
// export attributes
|
|
21
|
+
export const validAttributeNames = attributes
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* PostHTML plugin to process Tailwind CSS within style tags.
|
|
25
|
+
*
|
|
26
|
+
* This plugin processes CSS content in `<style>` tags and
|
|
27
|
+
* compiles it with PostCSS. `<style>` tags marked as
|
|
28
|
+
* `no-process` will be skipped.
|
|
29
|
+
*/
|
|
30
|
+
export function compileCss(config = {}) {
|
|
31
|
+
return tree => {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const stylePromises = []
|
|
34
|
+
|
|
35
|
+
tree.walk(node => {
|
|
36
|
+
if (node.tag === 'style' && node.content) {
|
|
37
|
+
if (node.attrs && Object.keys(node.attrs).some(attr => attributes.has(attr))) {
|
|
38
|
+
return node
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const css = Array.isArray(node.content)
|
|
42
|
+
? node.content.join('')
|
|
43
|
+
: node.content
|
|
44
|
+
|
|
45
|
+
const promise = processCss(css, config)
|
|
46
|
+
.then(processedCss => {
|
|
47
|
+
node.content = [processedCss]
|
|
48
|
+
})
|
|
49
|
+
.catch(error => {
|
|
50
|
+
console.warn('Error processing CSS in style tag:', error.message)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
stylePromises.push(promise)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return node
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
Promise.all(stylePromises)
|
|
60
|
+
.then(() => resolve(tree))
|
|
61
|
+
.catch(reject)
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function processCss(css, config) {
|
|
67
|
+
/**
|
|
68
|
+
* PostCSS pipeline. Plugins defined and added here
|
|
69
|
+
* will apply to all `<style>` tags in the HTML,
|
|
70
|
+
* unless marked to be excluded.
|
|
71
|
+
*/
|
|
72
|
+
const resolveCSSProps = get(config, 'css.resolveProps')
|
|
73
|
+
const resolveCalc = get(config, 'css.resolveCalc') !== false
|
|
74
|
+
? get(config, 'css.resolveCalc', { precision: 2 })
|
|
75
|
+
: false
|
|
76
|
+
|
|
77
|
+
const lightningCssOptions = merge(
|
|
78
|
+
get(config, 'css.lightning', {}),
|
|
79
|
+
{
|
|
80
|
+
targets: {
|
|
81
|
+
ie: 1,
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const processor = postcss([
|
|
88
|
+
tailwindcss(get(config, 'css.tailwind', {})),
|
|
89
|
+
resolveCSSProps !== false && cssVariables(resolveCSSProps),
|
|
90
|
+
resolveCalc !== false && postcssCalc(resolveCalc),
|
|
91
|
+
removeDuplicateSelectors(),
|
|
92
|
+
cleanupTailwindArtifacts(get(config, 'css.cleanup', {})),
|
|
93
|
+
...get(config, 'postcss.plugins', []),
|
|
94
|
+
].filter(Boolean))
|
|
95
|
+
|
|
96
|
+
const result = await processor.process(css, merge(
|
|
97
|
+
get(config, 'postcss.options', {}),
|
|
98
|
+
{
|
|
99
|
+
from: config.cwd || './',
|
|
100
|
+
parser: postcssSafeParser
|
|
101
|
+
}
|
|
102
|
+
))
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Lightning CSS processing
|
|
106
|
+
*
|
|
107
|
+
* We use this to lower the modern Tailwind CSS 4 syntax
|
|
108
|
+
* to be more email-friendly.
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
if (result.css?.trim()) {
|
|
112
|
+
try {
|
|
113
|
+
const { code } = transform(
|
|
114
|
+
merge(
|
|
115
|
+
lightningCssOptions,
|
|
116
|
+
{
|
|
117
|
+
code: Buffer.from(result.css)
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
return code.toString()
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.warn('Failed to lower syntax with Lightning CSS:', error.message)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return result.css
|
|
129
|
+
} catch (error) {
|
|
130
|
+
console.warn('Error compiling CSS:', error.message)
|
|
131
|
+
return css
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { validAttributeNames } from "./postcss/compileCss"
|
|
2
|
+
|
|
3
|
+
const plugin = () => tree => {
|
|
4
|
+
const process = node => {
|
|
5
|
+
if (node.tag === 'style') {
|
|
6
|
+
if (node.attrs && Object.keys(node.attrs).some(attr => validAttributeNames.has(attr))) {
|
|
7
|
+
// Remove the attribute
|
|
8
|
+
for (const attr of Object.keys(node.attrs)) {
|
|
9
|
+
if (validAttributeNames.has(attr)) {
|
|
10
|
+
delete node.attrs[attr]
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return node
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return tree.walk(process)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default plugin
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { defu as merge } from 'defu'
|
|
2
|
-
import { transform } from 'lightningcss'
|
|
3
|
-
|
|
4
|
-
const plugin = (options = {}) => tree => {
|
|
5
|
-
options = merge(options, {
|
|
6
|
-
targets: options.targets ? {} : {
|
|
7
|
-
ie: 1,
|
|
8
|
-
},
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
const process = node => {
|
|
12
|
-
// Check if this is a style tag with content
|
|
13
|
-
if (node.tag === 'style' && node.content && Array.isArray(node.content)) {
|
|
14
|
-
// Get the CSS content from the style tag
|
|
15
|
-
const cssContent = node.content.join('')
|
|
16
|
-
|
|
17
|
-
if (cssContent.trim()) {
|
|
18
|
-
try {
|
|
19
|
-
const { code } = transform(
|
|
20
|
-
merge(
|
|
21
|
-
options,
|
|
22
|
-
{
|
|
23
|
-
code: Buffer.from(cssContent)
|
|
24
|
-
}
|
|
25
|
-
)
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
// Replace the content with processed CSS
|
|
29
|
-
node.content = [code.toString()]
|
|
30
|
-
} catch (error) {
|
|
31
|
-
// If processing fails, leave the content unchanged
|
|
32
|
-
console.warn('Failed to process media queries:', error.message)
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return node
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return tree.walk(process)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
export default plugin
|