@maizzle/framework 4.0.0-alpha.5 → 4.0.0-alpha.8
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/.github/workflows/nodejs.yml +1 -1
- package/package.json +6 -5
- package/src/commands/serve.js +21 -14
- package/src/generators/output/to-string.js +1 -1
- package/src/generators/postcss.js +29 -0
- package/src/generators/posthtml.js +66 -61
- package/src/generators/tailwindcss.js +2 -2
- package/src/index.js +17 -13
- package/src/transformers/index.js +60 -57
- package/src/transformers/inlineCss.js +1 -1
- package/src/transformers/minify.js +1 -1
- package/src/transformers/prettify.js +1 -1
- package/src/transformers/removeInlineBackgroundColor.js +1 -1
- package/src/transformers/removeInlinedSelectors.js +71 -0
- package/src/transformers/removeUnusedCss.js +17 -2
- package/src/transformers/sixHex.js +24 -1
- package/src/transformers/transform.js +35 -6
- package/test/expected/posthtml/component.html +13 -0
- package/test/expected/{inheritance.html → posthtml/extend-template.html} +2 -2
- package/test/expected/posthtml/fetch.html +5 -0
- package/test/expected/posthtml/layout.html +3 -0
- package/test/expected/transformers/atimport-in-style.html +14 -0
- package/test/expected/transformers/base-image-url.html +83 -83
- package/test/expected/transformers/preserve-transform-css.html +27 -0
- package/test/fixtures/posthtml/component.html +19 -0
- package/test/fixtures/{inheritance.html → posthtml/extend-template.html} +7 -7
- package/test/fixtures/posthtml/fetch.html +9 -0
- package/test/fixtures/posthtml/layout.html +11 -0
- package/test/fixtures/transformers/atimport-in-style.html +11 -0
- package/test/fixtures/transformers/base-image-url.html +85 -85
- package/test/fixtures/transformers/preserve-transform-css.html +25 -0
- package/test/stubs/components/component.html +5 -0
- package/test/stubs/data.json +14 -0
- package/test/stubs/layouts/basic.html +1 -0
- package/test/stubs/{layout.html → layouts/full.html} +0 -0
- package/test/stubs/{layout-basic.html → layouts/template.html} +5 -5
- package/test/stubs/post.css +6 -0
- package/test/stubs/tailwind/{preserve.html → content-source.html} +0 -0
- package/test/stubs/tailwind/tailwind.css +3 -0
- package/test/stubs/template.html +10 -10
- package/test/test-postcss.js +8 -0
- package/test/test-posthtml.js +66 -0
- package/test/{test-tailwind.js → test-tailwindcss.js} +3 -3
- package/test/test-tostring.js +142 -132
- package/test/test-transformers.js +479 -343
- package/test/expected/transformers/transform-postcss.html +0 -19
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maizzle/framework",
|
|
3
|
-
"version": "4.0.0-alpha.
|
|
3
|
+
"version": "4.0.0-alpha.8",
|
|
4
4
|
"description": "Maizzle is a framework that helps you quickly build HTML emails with Tailwind CSS.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"autoprefixer": "^10.4.0",
|
|
37
37
|
"browser-sync": "^2.26.13",
|
|
38
38
|
"color-shorthand-hex-to-six-digit": "^3.0.2",
|
|
39
|
-
"email-comb": "^5.
|
|
39
|
+
"email-comb": "^5.2.0",
|
|
40
40
|
"front-matter": "^4.0.0",
|
|
41
41
|
"fs-extra": "^10.0.0",
|
|
42
42
|
"glob-promise": "^4.1.0",
|
|
@@ -55,9 +55,10 @@
|
|
|
55
55
|
"posthtml-expressions": "^1.8.1",
|
|
56
56
|
"posthtml-extend": "^0.6.0",
|
|
57
57
|
"posthtml-extra-attributes": "^1.0.0",
|
|
58
|
-
"posthtml-fetch": "^2.
|
|
58
|
+
"posthtml-fetch": "^2.2.0",
|
|
59
59
|
"posthtml-markdownit": "^1.3.0",
|
|
60
|
-
"posthtml-
|
|
60
|
+
"posthtml-match-helper": "^1.0.3",
|
|
61
|
+
"posthtml-modules": "^0.9.0",
|
|
61
62
|
"posthtml-mso": "^1.0.4",
|
|
62
63
|
"posthtml-postcss-merge-longhand": "^1.0.2",
|
|
63
64
|
"posthtml-remove-attributes": "^1.0.0",
|
|
@@ -76,7 +77,7 @@
|
|
|
76
77
|
"xo": "0.39.1"
|
|
77
78
|
},
|
|
78
79
|
"engines": {
|
|
79
|
-
"node": ">=
|
|
80
|
+
"node": ">=14.19.1"
|
|
80
81
|
},
|
|
81
82
|
"ava": {
|
|
82
83
|
"files": [
|
package/src/commands/serve.js
CHANGED
|
@@ -72,19 +72,23 @@ const serve = async (env = 'local', config = {}) => {
|
|
|
72
72
|
renderOptions
|
|
73
73
|
)
|
|
74
74
|
.then(async ({html, config}) => {
|
|
75
|
+
let source = ''
|
|
75
76
|
let dest = ''
|
|
76
77
|
let ext = ''
|
|
77
78
|
|
|
78
79
|
if (Array.isArray(config.build.templates)) {
|
|
79
80
|
const match = config.build.templates.find(template => template.source === path.parse(file).dir)
|
|
81
|
+
source = get(match, 'source')
|
|
80
82
|
dest = get(match, 'destination.path', 'build_local')
|
|
81
83
|
ext = get(match, 'destination.ext', 'html')
|
|
82
84
|
} else if (isObject(config.build.templates)) {
|
|
85
|
+
source = get(config, 'build.templates.source')
|
|
83
86
|
dest = get(config, 'build.templates.destination.path', 'build_local')
|
|
84
87
|
ext = get(config, 'build.templates.destination.ext', 'html')
|
|
85
88
|
}
|
|
86
89
|
|
|
87
|
-
const
|
|
90
|
+
const fileDir = path.parse(file).dir.replace(source, '')
|
|
91
|
+
const finalDestination = path.join(dest, fileDir, `${path.parse(file).name}.${ext}`)
|
|
88
92
|
|
|
89
93
|
await fs.outputFile(config.permalink || finalDestination, html)
|
|
90
94
|
})
|
|
@@ -117,19 +121,22 @@ const serve = async (env = 'local', config = {}) => {
|
|
|
117
121
|
|
|
118
122
|
// Initialize Browsersync
|
|
119
123
|
browsersync()
|
|
120
|
-
.init(
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
124
|
+
.init(
|
|
125
|
+
merge(
|
|
126
|
+
{
|
|
127
|
+
notify: false,
|
|
128
|
+
open: false,
|
|
129
|
+
port: 3000,
|
|
130
|
+
server: {
|
|
131
|
+
baseDir,
|
|
132
|
+
directory: true
|
|
133
|
+
},
|
|
134
|
+
tunnel: false,
|
|
135
|
+
ui: {port: 3001},
|
|
136
|
+
logFileChanges: false
|
|
137
|
+
},
|
|
138
|
+
get(config, 'build.browsersync', {})
|
|
139
|
+
), () => {})
|
|
133
140
|
} catch (error) {
|
|
134
141
|
spinner.fail(error)
|
|
135
142
|
throw error
|
|
@@ -22,7 +22,7 @@ module.exports = async (html, options) => {
|
|
|
22
22
|
let config = merge(fileConfig, get(options, 'maizzle', {}))
|
|
23
23
|
|
|
24
24
|
const tailwindConfig = get(options, 'tailwind.config', {})
|
|
25
|
-
const cssString = get(options, 'tailwind.css', '
|
|
25
|
+
const cssString = get(options, 'tailwind.css', '')
|
|
26
26
|
|
|
27
27
|
let {frontmatter} = fm(html)
|
|
28
28
|
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const {get} = require('lodash')
|
|
3
|
+
const postcss = require('postcss')
|
|
4
|
+
const postcssImport = require('postcss-import')
|
|
5
|
+
const postcssNested = require('tailwindcss/nesting')
|
|
6
|
+
const mergeLonghand = require('postcss-merge-longhand')
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
process: async (css = '', maizzleConfig = {}, spinner = null) => {
|
|
10
|
+
const userFilePath = get(maizzleConfig, 'build.tailwind.css', path.join(process.cwd(), 'src/css/tailwind.css'))
|
|
11
|
+
|
|
12
|
+
return postcss([
|
|
13
|
+
postcssImport({path: path.dirname(userFilePath)}),
|
|
14
|
+
postcssNested(),
|
|
15
|
+
maizzleConfig.env === 'local' ? () => {} : mergeLonghand(),
|
|
16
|
+
...get(maizzleConfig, 'build.postcss.plugins', [])
|
|
17
|
+
])
|
|
18
|
+
.process(css, {from: undefined})
|
|
19
|
+
.then(result => result.css)
|
|
20
|
+
.catch(error => {
|
|
21
|
+
console.error(error)
|
|
22
|
+
if (spinner) {
|
|
23
|
+
spinner.stop()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
throw new Error(`PostCSS processing failed`)
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,61 +1,66 @@
|
|
|
1
|
-
const fm = require('front-matter')
|
|
2
|
-
const posthtml = require('posthtml')
|
|
3
|
-
const {get, merge} = require('lodash')
|
|
4
|
-
const fetch = require('posthtml-fetch')
|
|
5
|
-
const layouts = require('posthtml-extend')
|
|
6
|
-
const modules = require('posthtml-modules')
|
|
7
|
-
const expressions = require('posthtml-expressions')
|
|
8
|
-
|
|
9
|
-
module.exports = async (html, config) => {
|
|
10
|
-
const layoutsOptions = get(config, 'build.layouts', {})
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
1
|
+
const fm = require('front-matter')
|
|
2
|
+
const posthtml = require('posthtml')
|
|
3
|
+
const {get, merge} = require('lodash')
|
|
4
|
+
const fetch = require('posthtml-fetch')
|
|
5
|
+
const layouts = require('posthtml-extend')
|
|
6
|
+
const modules = require('posthtml-modules')
|
|
7
|
+
const expressions = require('posthtml-expressions')
|
|
8
|
+
|
|
9
|
+
module.exports = async (html, config) => {
|
|
10
|
+
const layoutsOptions = get(config, 'build.layouts', {})
|
|
11
|
+
|
|
12
|
+
const modulesOptions = get(config, 'build.components', {})
|
|
13
|
+
// Fake `from` option so we can reference modules relatively
|
|
14
|
+
const modulesRoot = modulesOptions.root || './'
|
|
15
|
+
const modulesFrom = modulesOptions.from || `${modulesRoot}/fake`
|
|
16
|
+
|
|
17
|
+
const posthtmlOptions = get(config, 'build.posthtml.options', {})
|
|
18
|
+
const posthtmlPlugins = get(config, 'build.posthtml.plugins', [])
|
|
19
|
+
|
|
20
|
+
const expressionsOptions = merge({strictMode: false}, get(config, 'build.posthtml.expressions', {}))
|
|
21
|
+
|
|
22
|
+
const locals = merge(
|
|
23
|
+
get(expressionsOptions, 'locals', {}),
|
|
24
|
+
get(config, 'locals', {}),
|
|
25
|
+
{page: config}
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
const fetchPlugin = fetch(
|
|
29
|
+
merge(
|
|
30
|
+
{
|
|
31
|
+
expressions: merge({...expressionsOptions, locals})
|
|
32
|
+
},
|
|
33
|
+
get(config, 'build.posthtml.fetch', {})
|
|
34
|
+
)
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
return posthtml([
|
|
38
|
+
fetchPlugin,
|
|
39
|
+
expressions({...expressionsOptions, locals}),
|
|
40
|
+
layouts(
|
|
41
|
+
merge(
|
|
42
|
+
{
|
|
43
|
+
strict: false,
|
|
44
|
+
expressions: merge({...expressionsOptions, locals})
|
|
45
|
+
},
|
|
46
|
+
layoutsOptions
|
|
47
|
+
)
|
|
48
|
+
),
|
|
49
|
+
modules({
|
|
50
|
+
parser: posthtmlOptions,
|
|
51
|
+
attributeAsLocals: true,
|
|
52
|
+
from: modulesFrom,
|
|
53
|
+
root: modulesRoot,
|
|
54
|
+
tag: 'component',
|
|
55
|
+
attribute: 'src',
|
|
56
|
+
plugins: [
|
|
57
|
+
fetchPlugin
|
|
58
|
+
],
|
|
59
|
+
locals,
|
|
60
|
+
...modulesOptions
|
|
61
|
+
}),
|
|
62
|
+
...posthtmlPlugins
|
|
63
|
+
])
|
|
64
|
+
.process(html, {...posthtmlOptions})
|
|
65
|
+
.then(result => fm(result.html).body)
|
|
66
|
+
}
|
|
@@ -90,9 +90,9 @@ module.exports = {
|
|
|
90
90
|
const userFileExists = await fs.pathExists(userFilePath)
|
|
91
91
|
|
|
92
92
|
if (userFileExists) {
|
|
93
|
-
css
|
|
93
|
+
css = await fs.readFile(path.resolve(userFilePath), 'utf8') + css
|
|
94
94
|
} else {
|
|
95
|
-
css =
|
|
95
|
+
css = `@import "tailwindcss/components"; @import "tailwindcss/utilities"; ${css}`
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
return postcss([
|
package/src/index.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
const serve = require('./commands/serve')
|
|
2
|
-
const toFile = require('./commands/build')
|
|
3
|
-
const transformers = require('./transformers')
|
|
4
|
-
const toString = require('./functions/render')
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
const serve = require('./commands/serve')
|
|
2
|
+
const toFile = require('./commands/build')
|
|
3
|
+
const transformers = require('./transformers')
|
|
4
|
+
const toString = require('./functions/render')
|
|
5
|
+
const PostCSS = require('./generators/postcss')
|
|
6
|
+
const toPlaintext = require('./functions/plaintext')
|
|
7
|
+
const TailwindCSS = require('./generators/tailwindcss')
|
|
8
|
+
|
|
9
|
+
module.exports = {
|
|
10
|
+
serve,
|
|
11
|
+
build: toFile,
|
|
12
|
+
...transformers,
|
|
13
|
+
render: toString,
|
|
14
|
+
postcss: PostCSS,
|
|
15
|
+
plaintext: toPlaintext,
|
|
16
|
+
tailwindcss: TailwindCSS
|
|
17
|
+
}
|
|
@@ -1,57 +1,60 @@
|
|
|
1
|
-
const inline = require('./inlineCss')
|
|
2
|
-
const minify = require('./minify')
|
|
3
|
-
const markdown = require('./markdown')
|
|
4
|
-
const prettify = require('./prettify')
|
|
5
|
-
const ensureSixHEX = require('./sixHex')
|
|
6
|
-
const applyBaseImageUrl = require('./baseUrl')
|
|
7
|
-
const addURLParams = require('./urlParameters')
|
|
8
|
-
const transformContents = require('./transform')
|
|
9
|
-
const preventWidows = require('./preventWidows')
|
|
10
|
-
const replaceStrings = require('./replaceStrings')
|
|
11
|
-
const safeClassNames = require('./safeClassNames')
|
|
12
|
-
const removeUnusedCSS = require('./removeUnusedCss')
|
|
13
|
-
const removeAttributes = require('./removeAttributes')
|
|
14
|
-
const attributeToStyle = require('./attributeToStyle')
|
|
15
|
-
const removeInlineSizes = require('./removeInlineSizes')
|
|
16
|
-
const applyExtraAttributes = require('./extraAttributes')
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
html = await
|
|
22
|
-
html = await
|
|
23
|
-
html = await
|
|
24
|
-
html = await
|
|
25
|
-
html = await
|
|
26
|
-
html = await
|
|
27
|
-
html = await
|
|
28
|
-
html = await
|
|
29
|
-
html = await
|
|
30
|
-
html = await
|
|
31
|
-
html = await
|
|
32
|
-
html = await
|
|
33
|
-
html = await
|
|
34
|
-
html = await
|
|
35
|
-
html = await
|
|
36
|
-
html = await
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
exports.
|
|
44
|
-
exports.
|
|
45
|
-
exports.
|
|
46
|
-
exports.
|
|
47
|
-
exports.
|
|
48
|
-
exports.
|
|
49
|
-
exports.
|
|
50
|
-
exports.
|
|
51
|
-
exports.
|
|
52
|
-
exports.removeUnusedCSS = (html, config) => removeUnusedCSS(html, config, true)
|
|
53
|
-
exports.removeAttributes = (html, config) => removeAttributes(html, config, true)
|
|
54
|
-
exports.
|
|
55
|
-
exports.
|
|
56
|
-
exports.
|
|
57
|
-
exports.
|
|
1
|
+
const inline = require('./inlineCss')
|
|
2
|
+
const minify = require('./minify')
|
|
3
|
+
const markdown = require('./markdown')
|
|
4
|
+
const prettify = require('./prettify')
|
|
5
|
+
const ensureSixHEX = require('./sixHex')
|
|
6
|
+
const applyBaseImageUrl = require('./baseUrl')
|
|
7
|
+
const addURLParams = require('./urlParameters')
|
|
8
|
+
const transformContents = require('./transform')
|
|
9
|
+
const preventWidows = require('./preventWidows')
|
|
10
|
+
const replaceStrings = require('./replaceStrings')
|
|
11
|
+
const safeClassNames = require('./safeClassNames')
|
|
12
|
+
const removeUnusedCSS = require('./removeUnusedCss')
|
|
13
|
+
const removeAttributes = require('./removeAttributes')
|
|
14
|
+
const attributeToStyle = require('./attributeToStyle')
|
|
15
|
+
const removeInlineSizes = require('./removeInlineSizes')
|
|
16
|
+
const applyExtraAttributes = require('./extraAttributes')
|
|
17
|
+
const removeInlinedClasses = require('./removeInlinedSelectors')
|
|
18
|
+
const removeInlineBgColor = require('./removeInlineBackgroundColor')
|
|
19
|
+
|
|
20
|
+
exports.process = async (html, config) => {
|
|
21
|
+
html = await safeClassNames(html, config)
|
|
22
|
+
html = await transformContents(html, config)
|
|
23
|
+
html = await markdown(html, config)
|
|
24
|
+
html = await preventWidows(html, config)
|
|
25
|
+
html = await attributeToStyle(html, config)
|
|
26
|
+
html = await inline(html, config)
|
|
27
|
+
html = await removeInlinedClasses(html, config)
|
|
28
|
+
html = await removeUnusedCSS(html, config)
|
|
29
|
+
html = await removeInlineSizes(html, config)
|
|
30
|
+
html = await removeInlineBgColor(html, config)
|
|
31
|
+
html = await removeAttributes(html, config)
|
|
32
|
+
html = await applyExtraAttributes(html, config)
|
|
33
|
+
html = await applyBaseImageUrl(html, config)
|
|
34
|
+
html = await addURLParams(html, config)
|
|
35
|
+
html = await ensureSixHEX(html, config)
|
|
36
|
+
html = await prettify(html, config)
|
|
37
|
+
html = await minify(html, config)
|
|
38
|
+
html = await replaceStrings(html, config)
|
|
39
|
+
|
|
40
|
+
return html
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
exports.minify = (html, config) => minify(html, config, true)
|
|
44
|
+
exports.inlineCSS = (html, config) => inline(html, config, true)
|
|
45
|
+
exports.markdown = (html, config) => markdown(html, config, true)
|
|
46
|
+
exports.prettify = (html, config) => prettify(html, config, true)
|
|
47
|
+
exports.ensureSixHEX = (html, config) => ensureSixHEX(html, config)
|
|
48
|
+
exports.addURLParams = (html, config) => addURLParams(html, config, true)
|
|
49
|
+
exports.preventWidows = (html, config) => preventWidows(html, config, true)
|
|
50
|
+
exports.replaceStrings = (html, config) => replaceStrings(html, config, true)
|
|
51
|
+
exports.safeClassNames = (html, config) => safeClassNames(html, config, true)
|
|
52
|
+
exports.removeUnusedCSS = (html, config) => removeUnusedCSS(html, config, true)
|
|
53
|
+
exports.removeAttributes = (html, config) => removeAttributes(html, config, true)
|
|
54
|
+
exports.attributeToStyle = (html, config) => attributeToStyle(html, config, true)
|
|
55
|
+
exports.removeInlineSizes = (html, config) => removeInlineSizes(html, config, true)
|
|
56
|
+
exports.applyBaseImageUrl = (html, config) => applyBaseImageUrl(html, config, true)
|
|
57
|
+
exports.transformContents = (html, config) => transformContents(html, config, true)
|
|
58
|
+
exports.removeInlineBgColor = (html, config) => removeInlineBgColor(html, config, true)
|
|
59
|
+
exports.applyExtraAttributes = (html, config) => applyExtraAttributes(html, config, true)
|
|
60
|
+
exports.removeInlinedClasses = (html, config) => removeInlinedClasses(html, config)
|
|
@@ -9,7 +9,7 @@ module.exports = async (html, config = {}, direct = false) => {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
const options = direct ? config : get(config, 'inlineCSS', {})
|
|
12
|
-
const removeStyleTags = get(options, 'removeStyleTags',
|
|
12
|
+
const removeStyleTags = get(options, 'removeStyleTags', false)
|
|
13
13
|
const css = get(config, 'customCSS', false)
|
|
14
14
|
|
|
15
15
|
if (get(config, 'inlineCSS') === true || !isEmpty(options)) {
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const {get, has, remove} = require('lodash')
|
|
2
|
+
const postcss = require('postcss')
|
|
3
|
+
const posthtml = require('posthtml')
|
|
4
|
+
const parseAttrs = require('posthtml-attrs-parser')
|
|
5
|
+
const matchHelper = require('posthtml-match-helper')
|
|
6
|
+
|
|
7
|
+
module.exports = async (html, config = {}) => {
|
|
8
|
+
if (get(config, 'removeInlinedClasses') === false) {
|
|
9
|
+
return html
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const posthtmlOptions = get(config, 'build.posthtml.options', {})
|
|
13
|
+
return posthtml([plugin()]).process(html, posthtmlOptions).then(result => result.html)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const plugin = () => tree => {
|
|
17
|
+
const process = node => {
|
|
18
|
+
// For each style tag...
|
|
19
|
+
if (node.tag === 'style') {
|
|
20
|
+
const {root} = postcss().process(node.content)
|
|
21
|
+
|
|
22
|
+
root.walkRules(rule => {
|
|
23
|
+
// Skip media queries and such...
|
|
24
|
+
if (rule.parent.type === 'atrule') {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const {selector} = rule
|
|
29
|
+
const prop = get(rule.nodes[0], 'prop')
|
|
30
|
+
|
|
31
|
+
// If we find the selector in the HTML...
|
|
32
|
+
tree.match(matchHelper(selector), n => {
|
|
33
|
+
const parsedAttrs = parseAttrs(n.attrs)
|
|
34
|
+
const classAttr = get(parsedAttrs, 'class', [])
|
|
35
|
+
const styleAttr = get(parsedAttrs, 'style', {})
|
|
36
|
+
|
|
37
|
+
// If the class is in the style attribute (inlined), remove it
|
|
38
|
+
if (has(styleAttr, prop)) {
|
|
39
|
+
// Remove the class attribute
|
|
40
|
+
// console.log(styleAttr, prop, classAttr)
|
|
41
|
+
remove(classAttr, s => selector.includes(s))
|
|
42
|
+
|
|
43
|
+
// Remove the rule in the <style> tag
|
|
44
|
+
rule.remove()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Remove from <style> selectors that were used to create shorthand declarations
|
|
49
|
+
* like `margin: 0 0 0 16px` (transformed with mergeLonghand when inlining).
|
|
50
|
+
*/
|
|
51
|
+
Object.keys(styleAttr).forEach(key => {
|
|
52
|
+
if (prop.includes(key)) {
|
|
53
|
+
rule.remove()
|
|
54
|
+
remove(classAttr, s => selector.includes(s))
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
n.attrs = parsedAttrs.compose()
|
|
59
|
+
|
|
60
|
+
return n
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
node.content = root.toString()
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return node
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return tree.walk(process)
|
|
71
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const {get, isEmpty} = require('lodash')
|
|
2
1
|
const {comb} = require('email-comb')
|
|
2
|
+
const {get, isEmpty} = require('lodash')
|
|
3
3
|
|
|
4
4
|
module.exports = async (html, config = {}, direct = false) => {
|
|
5
5
|
if (get(config, 'removeUnusedCSS') === false) {
|
|
@@ -8,11 +8,26 @@ module.exports = async (html, config = {}, direct = false) => {
|
|
|
8
8
|
|
|
9
9
|
const options = direct ? config : get(config, 'removeUnusedCSS', {})
|
|
10
10
|
|
|
11
|
+
const safelist = [
|
|
12
|
+
'*body*', // Gmail
|
|
13
|
+
'.outlook*', // Outlook.com
|
|
14
|
+
'.bloop_container', // Airmail
|
|
15
|
+
'.Singleton', // Apple Mail 10
|
|
16
|
+
'.unused', // Notes 8
|
|
17
|
+
'.moz-text-html', // Thunderbird
|
|
18
|
+
'.mail-detail-content', // Comcast, Libero webmail
|
|
19
|
+
'*edo*', // Edison (all)
|
|
20
|
+
'#*', // Freenet uses #msgBody
|
|
21
|
+
'.lang*' // Fenced code blocks
|
|
22
|
+
]
|
|
23
|
+
|
|
11
24
|
if (typeof options === 'boolean' && options) {
|
|
12
|
-
return comb(html).result
|
|
25
|
+
return comb(html, {whitelist: safelist}).result
|
|
13
26
|
}
|
|
14
27
|
|
|
15
28
|
if (!isEmpty(options)) {
|
|
29
|
+
options.whitelist = [...get(options, 'whitelist', []), ...safelist]
|
|
30
|
+
|
|
16
31
|
return comb(html, options).result
|
|
17
32
|
}
|
|
18
33
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const {get} = require('lodash')
|
|
2
|
+
const posthtml = require('posthtml')
|
|
3
|
+
const parseAttrs = require('posthtml-attrs-parser')
|
|
2
4
|
const {conv} = require('color-shorthand-hex-to-six-digit')
|
|
3
5
|
|
|
4
6
|
module.exports = async (html, config = {}) => {
|
|
@@ -6,5 +8,26 @@ module.exports = async (html, config = {}) => {
|
|
|
6
8
|
return html
|
|
7
9
|
}
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
const posthtmlOptions = get(config, 'build.posthtml.options', {})
|
|
12
|
+
return posthtml([sixHex()]).process(html, posthtmlOptions).then(result => result.html)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const sixHex = () => tree => {
|
|
16
|
+
const process = node => {
|
|
17
|
+
const attrs = parseAttrs(node.attrs)
|
|
18
|
+
|
|
19
|
+
const targets = ['bgcolor', 'color']
|
|
20
|
+
|
|
21
|
+
targets.forEach(attribute => {
|
|
22
|
+
if (attrs[attribute]) {
|
|
23
|
+
attrs[attribute] = conv(attrs[attribute])
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
node.attrs = attrs.compose()
|
|
28
|
+
|
|
29
|
+
return node
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return tree.walk(process)
|
|
10
33
|
}
|