@maizzle/framework 4.0.0-alpha.1 → 4.0.0-alpha.10
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/bin/maizzle +3 -0
- package/package.json +16 -12
- package/src/commands/build.js +32 -0
- package/src/commands/serve.js +156 -0
- package/src/functions/plaintext.js +5 -0
- package/src/functions/render.js +5 -0
- package/src/generators/output/to-disk.js +90 -77
- package/src/generators/output/to-string.js +2 -6
- package/src/generators/plaintext.js +49 -52
- package/src/generators/postcss.js +29 -0
- package/src/generators/posthtml.js +11 -6
- package/src/generators/tailwindcss.js +116 -115
- package/src/index.js +14 -148
- package/src/transformers/baseUrl.js +33 -9
- package/src/transformers/filters/defaultFilters.js +126 -0
- package/src/transformers/filters/index.js +55 -0
- package/src/transformers/index.js +13 -7
- package/src/transformers/inlineCss.js +1 -14
- package/src/transformers/minify.js +1 -1
- package/src/transformers/prettify.js +16 -9
- package/src/transformers/removeInlineBackgroundColor.js +1 -1
- package/src/transformers/removeInlinedSelectors.js +70 -0
- package/src/transformers/removeUnusedCss.js +40 -20
- package/src/transformers/shorthandInlineCSS.js +19 -0
- package/src/transformers/sixHex.js +24 -1
- 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 +15 -0
- package/test/expected/transformers/{base-image-url.html → base-url.html} +18 -2
- package/test/expected/transformers/filters.html +81 -0
- package/test/expected/transformers/preserve-transform-css.html +36 -0
- package/test/expected/useConfig.html +9 -9
- package/test/fixtures/basic.html +9 -9
- 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 → base-url.html} +18 -2
- package/test/fixtures/transformers/filters.html +87 -0
- package/test/fixtures/transformers/preserve-transform-css.html +25 -0
- package/test/fixtures/useConfig.html +9 -9
- 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/stubs/templates/1.html +1 -1
- package/test/stubs/templates/2.test +1 -0
- package/test/test-config.js +19 -19
- package/test/test-postcss.js +8 -0
- package/test/test-posthtml.js +72 -0
- package/test/{test-tailwind.js → test-tailwindcss.js} +117 -100
- package/test/test-todisk.js +79 -28
- package/test/test-tostring.js +148 -132
- package/test/test-transformers.js +216 -49
- package/src/transformers/transform.js +0 -22
- package/test/expected/transformers/transform-postcss.html +0 -19
- package/test/stubs/templates/2.html +0 -1
- package/test/stubs/templates/3.mzl +0 -1
package/bin/maizzle
ADDED
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maizzle/framework",
|
|
3
|
-
"version": "4.0.0-alpha.
|
|
3
|
+
"version": "4.0.0-alpha.10",
|
|
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",
|
|
7
|
+
"bin": {
|
|
8
|
+
"maizzle": "bin/maizzle"
|
|
9
|
+
},
|
|
7
10
|
"repository": {
|
|
8
11
|
"type": "git",
|
|
9
12
|
"url": "https://github.com/maizzle/framework.git"
|
|
@@ -33,10 +36,11 @@
|
|
|
33
36
|
"release": "np"
|
|
34
37
|
},
|
|
35
38
|
"dependencies": {
|
|
39
|
+
"@maizzle/cli": "^1.4.0",
|
|
36
40
|
"autoprefixer": "^10.4.0",
|
|
37
41
|
"browser-sync": "^2.26.13",
|
|
38
42
|
"color-shorthand-hex-to-six-digit": "^3.0.2",
|
|
39
|
-
"email-comb": "^5.
|
|
43
|
+
"email-comb": "^5.2.0",
|
|
40
44
|
"front-matter": "^4.0.0",
|
|
41
45
|
"fs-extra": "^10.0.0",
|
|
42
46
|
"glob-promise": "^4.1.0",
|
|
@@ -48,27 +52,27 @@
|
|
|
48
52
|
"postcss": "^8.4.4",
|
|
49
53
|
"postcss-import": "^14.0.0",
|
|
50
54
|
"postcss-merge-longhand": "^5.0.1",
|
|
51
|
-
"posthtml": "^0.16.
|
|
55
|
+
"posthtml": "^0.16.6",
|
|
52
56
|
"posthtml-attrs-parser": "^0.1.1",
|
|
53
57
|
"posthtml-base-url": "^1.0.1",
|
|
54
|
-
"posthtml-content": "^0.0
|
|
58
|
+
"posthtml-content": "^0.1.0",
|
|
55
59
|
"posthtml-expressions": "^1.8.1",
|
|
56
60
|
"posthtml-extend": "^0.6.0",
|
|
57
61
|
"posthtml-extra-attributes": "^1.0.0",
|
|
58
|
-
"posthtml-fetch": "^2.
|
|
59
|
-
"posthtml-markdownit": "^1.
|
|
60
|
-
"posthtml-
|
|
61
|
-
"posthtml-
|
|
62
|
+
"posthtml-fetch": "^2.2.0",
|
|
63
|
+
"posthtml-markdownit": "^1.3.0",
|
|
64
|
+
"posthtml-match-helper": "^1.0.3",
|
|
65
|
+
"posthtml-modules": "^0.9.0",
|
|
66
|
+
"posthtml-mso": "^1.0.4",
|
|
62
67
|
"posthtml-postcss-merge-longhand": "^1.0.2",
|
|
63
68
|
"posthtml-remove-attributes": "^1.0.0",
|
|
64
|
-
"posthtml-safe-class-names": "^1.0.
|
|
69
|
+
"posthtml-safe-class-names": "^1.0.8",
|
|
65
70
|
"posthtml-url-parameters": "^1.0.4",
|
|
66
71
|
"pretty": "^2.0.0",
|
|
67
72
|
"prevent-widows": "^1.0.2",
|
|
68
73
|
"query-string": "^7.1.0",
|
|
69
74
|
"string-strip-html": "^8.2.0",
|
|
70
|
-
"tailwindcss": "^3.0.0"
|
|
71
|
-
"tailwindcss-box-shadow": "^1.0.0"
|
|
75
|
+
"tailwindcss": "^3.0.0"
|
|
72
76
|
},
|
|
73
77
|
"devDependencies": {
|
|
74
78
|
"ava": "^4.0.1",
|
|
@@ -77,7 +81,7 @@
|
|
|
77
81
|
"xo": "0.39.1"
|
|
78
82
|
},
|
|
79
83
|
"engines": {
|
|
80
|
-
"node": ">=
|
|
84
|
+
"node": ">=14.0.0"
|
|
81
85
|
},
|
|
82
86
|
"ava": {
|
|
83
87
|
"files": [
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const ora = require('ora')
|
|
2
|
+
const {get} = require('lodash')
|
|
3
|
+
const Output = require('../generators/output')
|
|
4
|
+
const {clearConsole} = require('../utils/helpers')
|
|
5
|
+
|
|
6
|
+
const build = async (env = 'local', config = {}) => {
|
|
7
|
+
const start = new Date()
|
|
8
|
+
const spinner = ora('Building emails...').start()
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const {files, parsed} = await Output.toDisk(env, spinner, config)
|
|
12
|
+
|
|
13
|
+
const elapsedSeconds = (Date.now() - start) / 1000
|
|
14
|
+
|
|
15
|
+
if (get(config, 'build.command') === 'serve') {
|
|
16
|
+
if (get(config, 'build.console.clear')) {
|
|
17
|
+
clearConsole()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
spinner.succeed(`Re-built ${parsed.length} templates in ${elapsedSeconds}s`)
|
|
21
|
+
} else {
|
|
22
|
+
spinner.succeed(`Built ${parsed.length} templates in ${elapsedSeconds}s`)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return {files}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
spinner.fail(error.message)
|
|
28
|
+
throw error
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = build
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
const ora = require('ora')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const fs = require('fs-extra')
|
|
4
|
+
|
|
5
|
+
const Config = require('../generators/config')
|
|
6
|
+
const buildToFile = require('../commands/build')
|
|
7
|
+
const renderToString = require('../functions/render')
|
|
8
|
+
|
|
9
|
+
const {get, merge, isObject} = require('lodash')
|
|
10
|
+
const {clearConsole} = require('../utils/helpers')
|
|
11
|
+
|
|
12
|
+
const browsersync = () => {
|
|
13
|
+
if (!global.cachedBrowserSync) {
|
|
14
|
+
const bs = require('browser-sync')
|
|
15
|
+
global.cachedBrowserSync = bs.create()
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return global.cachedBrowserSync
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const serve = async (env = 'local', config = {}) => {
|
|
22
|
+
config = merge(
|
|
23
|
+
config,
|
|
24
|
+
await Config.getMerged(env),
|
|
25
|
+
{
|
|
26
|
+
build: {
|
|
27
|
+
command: 'serve'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
const spinner = ora()
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
await buildToFile(env, config)
|
|
36
|
+
|
|
37
|
+
let templates = get(config, 'build.templates')
|
|
38
|
+
templates = Array.isArray(templates) ? templates : [templates]
|
|
39
|
+
|
|
40
|
+
const templatePaths = [...new Set(templates.map(config => `${get(config, 'source', 'src')}/**`))]
|
|
41
|
+
const globalPaths = [
|
|
42
|
+
'src/**',
|
|
43
|
+
get(config, 'build.tailwind.config', 'tailwind.config.js'),
|
|
44
|
+
...new Set(get(config, 'build.browsersync.watch', []))
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
// Watch for Template file changes
|
|
48
|
+
browsersync()
|
|
49
|
+
.watch(templatePaths)
|
|
50
|
+
.on('change', async file => {
|
|
51
|
+
if (config.events && typeof config.events.beforeCreate === 'function') {
|
|
52
|
+
await config.events.beforeCreate(config)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Don't render if file type is not configured
|
|
56
|
+
// eslint-disable-next-line
|
|
57
|
+
const filetypes = templates.reduce((acc, template) => {
|
|
58
|
+
return [...acc, ...get(template, 'filetypes', ['html'])]
|
|
59
|
+
}, [])
|
|
60
|
+
|
|
61
|
+
if (!filetypes.includes(path.extname(file).slice(1))) {
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (get(config, 'build.console.clear')) {
|
|
66
|
+
clearConsole()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const start = new Date()
|
|
70
|
+
|
|
71
|
+
spinner.start('Building email...')
|
|
72
|
+
|
|
73
|
+
file = file.replace(/\\/g, '/')
|
|
74
|
+
|
|
75
|
+
const renderOptions = {
|
|
76
|
+
maizzle: config,
|
|
77
|
+
...config.events
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
renderToString(
|
|
81
|
+
await fs.readFile(file, 'utf8'),
|
|
82
|
+
renderOptions
|
|
83
|
+
)
|
|
84
|
+
.then(async ({html, config}) => {
|
|
85
|
+
let source = ''
|
|
86
|
+
let dest = ''
|
|
87
|
+
let ext = ''
|
|
88
|
+
|
|
89
|
+
if (Array.isArray(config.build.templates)) {
|
|
90
|
+
const match = config.build.templates.find(template => template.source === path.parse(file).dir)
|
|
91
|
+
source = get(match, 'source')
|
|
92
|
+
dest = get(match, 'destination.path', 'build_local')
|
|
93
|
+
ext = get(match, 'destination.ext', 'html')
|
|
94
|
+
} else if (isObject(config.build.templates)) {
|
|
95
|
+
source = get(config, 'build.templates.source')
|
|
96
|
+
dest = get(config, 'build.templates.destination.path', 'build_local')
|
|
97
|
+
ext = get(config, 'build.templates.destination.ext', 'html')
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const fileDir = path.parse(file).dir.replace(source, '')
|
|
101
|
+
const finalDestination = path.join(dest, fileDir, `${path.parse(file).name}.${ext}`)
|
|
102
|
+
|
|
103
|
+
await fs.outputFile(config.permalink || finalDestination, html)
|
|
104
|
+
})
|
|
105
|
+
.then(() => {
|
|
106
|
+
browsersync().reload()
|
|
107
|
+
spinner.succeed(`Compiled in ${(Date.now() - start) / 1000}s [${file}]`)
|
|
108
|
+
})
|
|
109
|
+
.catch(() => spinner.warn(`Received empty HTML, please save your file again [${file}]`))
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
// Watch for changes in all other files
|
|
113
|
+
browsersync()
|
|
114
|
+
.watch(globalPaths, {ignored: templatePaths})
|
|
115
|
+
.on('change', () => buildToFile(env, config).then(() => browsersync().reload()))
|
|
116
|
+
.on('unlink', () => buildToFile(env, config).then(() => browsersync().reload()))
|
|
117
|
+
|
|
118
|
+
// Watch for changes in config files
|
|
119
|
+
browsersync()
|
|
120
|
+
.watch('config*.js')
|
|
121
|
+
.on('change', async file => {
|
|
122
|
+
const parsedEnv = path.parse(file).name.split('.')[1] || 'local'
|
|
123
|
+
|
|
124
|
+
Config
|
|
125
|
+
.getMerged(parsedEnv)
|
|
126
|
+
.then(config => buildToFile(parsedEnv, config).then(() => browsersync().reload()))
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
// Browsersync options
|
|
130
|
+
const baseDir = templates.map(t => t.destination.path)
|
|
131
|
+
|
|
132
|
+
// Initialize Browsersync
|
|
133
|
+
browsersync()
|
|
134
|
+
.init(
|
|
135
|
+
merge(
|
|
136
|
+
{
|
|
137
|
+
notify: false,
|
|
138
|
+
open: false,
|
|
139
|
+
port: 3000,
|
|
140
|
+
server: {
|
|
141
|
+
baseDir,
|
|
142
|
+
directory: true
|
|
143
|
+
},
|
|
144
|
+
tunnel: false,
|
|
145
|
+
ui: {port: 3001},
|
|
146
|
+
logFileChanges: false
|
|
147
|
+
},
|
|
148
|
+
get(config, 'build.browsersync', {})
|
|
149
|
+
), () => {})
|
|
150
|
+
} catch (error) {
|
|
151
|
+
spinner.fail(error)
|
|
152
|
+
throw error
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
module.exports = serve
|
|
@@ -29,7 +29,7 @@ module.exports = async (env, spinner, config) => {
|
|
|
29
29
|
|
|
30
30
|
const css = (typeof get(config, 'tailwind.compiled') === 'string')
|
|
31
31
|
? config.tailwind.compiled
|
|
32
|
-
: await Tailwind.compile('
|
|
32
|
+
: await Tailwind.compile('', '', {}, config, spinner)
|
|
33
33
|
|
|
34
34
|
// Parse each template config object
|
|
35
35
|
await asyncForEach(templatesConfig, async templateConfig => {
|
|
@@ -46,26 +46,39 @@ module.exports = async (env, spinner, config) => {
|
|
|
46
46
|
*
|
|
47
47
|
* */
|
|
48
48
|
const templateSource = []
|
|
49
|
+
const templateTypeErrorMessage = 'Invalid template source: expected string or array of strings, got '
|
|
49
50
|
|
|
50
51
|
if (typeof templateConfig.source === 'function') {
|
|
51
|
-
const sources = templateConfig.source()
|
|
52
|
+
const sources = templateConfig.source(config)
|
|
53
|
+
|
|
52
54
|
if (Array.isArray(sources)) {
|
|
53
55
|
templateSource.push(...sources)
|
|
54
|
-
} else {
|
|
56
|
+
} else if (typeof sources === 'string') {
|
|
55
57
|
templateSource.push(sources)
|
|
58
|
+
} else {
|
|
59
|
+
throw new TypeError(templateTypeErrorMessage + typeof sources)
|
|
56
60
|
}
|
|
57
61
|
} else {
|
|
58
62
|
if (Array.isArray(templateConfig.source)) {
|
|
59
63
|
templateSource.push(...templateConfig.source)
|
|
60
|
-
} else {
|
|
64
|
+
} else if (typeof templateConfig.source === 'string') {
|
|
61
65
|
templateSource.push(templateConfig.source)
|
|
66
|
+
} else {
|
|
67
|
+
throw new TypeError(templateTypeErrorMessage + typeof templateConfig.source)
|
|
62
68
|
}
|
|
63
69
|
}
|
|
64
70
|
|
|
65
71
|
// Parse each template source
|
|
66
72
|
await asyncForEach(templateSource, async source => {
|
|
73
|
+
/**
|
|
74
|
+
* Copy single-file sources correctly
|
|
75
|
+
* If `src` is a file, `dest` cannot be a directory
|
|
76
|
+
* https://github.com/jprichardson/node-fs-extra/issues/323
|
|
77
|
+
*/
|
|
78
|
+
const out = fs.lstatSync(source).isFile() ? `${outputDir}/${path.basename(source)}` : outputDir
|
|
79
|
+
|
|
67
80
|
await fs
|
|
68
|
-
.copy(source,
|
|
81
|
+
.copy(source, out)
|
|
69
82
|
.then(async () => {
|
|
70
83
|
const extensions = Array.isArray(templateConfig.filetypes)
|
|
71
84
|
? templateConfig.filetypes.join('|')
|
|
@@ -78,9 +91,6 @@ module.exports = async (env, spinner, config) => {
|
|
|
78
91
|
return
|
|
79
92
|
}
|
|
80
93
|
|
|
81
|
-
// Store template config currently being processed
|
|
82
|
-
config.build.currentTemplates = templateConfig
|
|
83
|
-
|
|
84
94
|
if (config.events && typeof config.events.beforeCreate === 'function') {
|
|
85
95
|
await config.events.beforeCreate(config)
|
|
86
96
|
}
|
|
@@ -88,76 +98,79 @@ module.exports = async (env, spinner, config) => {
|
|
|
88
98
|
await asyncForEach(templates, async file => {
|
|
89
99
|
const html = await fs.readFile(file, 'utf8')
|
|
90
100
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
.then(async ({html, config}) => {
|
|
102
|
-
const destination = config.permalink || file
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Generate plaintext
|
|
106
|
-
*
|
|
107
|
-
* We do this first so that we can remove the <plaintext>
|
|
108
|
-
* tags from the markup before outputting the file.
|
|
109
|
-
*/
|
|
110
|
-
|
|
111
|
-
const plaintextConfig = get(templateConfig, 'plaintext')
|
|
112
|
-
const plaintextDestination = get(plaintextConfig, 'destination', config.permalink || file)
|
|
113
|
-
|
|
114
|
-
if ((typeof plaintextConfig === 'boolean' && plaintextConfig) || !isEmpty(plaintextConfig)) {
|
|
115
|
-
await Plaintext
|
|
116
|
-
.generate(html, plaintextDestination, merge(config, {filepath: file}))
|
|
117
|
-
.then(({plaintext, destination}) => fs.outputFile(destination, plaintext))
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
html = removePlaintextTags(html, config)
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Output file
|
|
124
|
-
*/
|
|
125
|
-
const parts = path.parse(destination)
|
|
126
|
-
const extension = get(templateConfig, 'destination.extension', 'html')
|
|
127
|
-
const finalDestination = `${parts.dir}/${parts.name}.${extension}`
|
|
128
|
-
|
|
129
|
-
await fs.outputFile(finalDestination, html)
|
|
130
|
-
.then(async () => {
|
|
131
|
-
/**
|
|
132
|
-
* Remove original file if its path is different
|
|
133
|
-
* from the final destination path.
|
|
134
|
-
*
|
|
135
|
-
* This ensures non-HTML files do not pollute
|
|
136
|
-
* the build destination folder.
|
|
137
|
-
*/
|
|
138
|
-
if (finalDestination !== file) {
|
|
139
|
-
await fs.remove(file)
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Keep track of handled files
|
|
143
|
-
files.push(file)
|
|
144
|
-
parsed.push(file)
|
|
145
|
-
})
|
|
146
|
-
})
|
|
147
|
-
.catch(error => {
|
|
148
|
-
switch (config.build.fail) {
|
|
149
|
-
case 'silent':
|
|
150
|
-
spinner.warn(`Failed to compile template: ${path.basename(file)}`)
|
|
151
|
-
break
|
|
152
|
-
case 'verbose':
|
|
153
|
-
spinner.warn(`Failed to compile template: ${path.basename(file)}`)
|
|
154
|
-
console.error(error)
|
|
155
|
-
break
|
|
156
|
-
default:
|
|
157
|
-
spinner.fail(`Failed to compile template: ${path.basename(file)}`)
|
|
158
|
-
throw error
|
|
159
|
-
}
|
|
101
|
+
try {
|
|
102
|
+
const compiled = await render(html, {
|
|
103
|
+
maizzle: {
|
|
104
|
+
...config,
|
|
105
|
+
env
|
|
106
|
+
},
|
|
107
|
+
tailwind: {
|
|
108
|
+
compiled: css
|
|
109
|
+
},
|
|
110
|
+
...config.events
|
|
160
111
|
})
|
|
112
|
+
|
|
113
|
+
const destination = config.permalink || file
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Generate plaintext
|
|
117
|
+
*
|
|
118
|
+
* We do this first so that we can remove the <plaintext>
|
|
119
|
+
* tags from the markup before outputting the file.
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
const plaintextConfig = get(templateConfig, 'plaintext')
|
|
123
|
+
const plaintextPath = get(plaintextConfig, 'destination.path', config.permalink || file)
|
|
124
|
+
|
|
125
|
+
if (Boolean(plaintextConfig) || !isEmpty(plaintextConfig)) {
|
|
126
|
+
await Plaintext
|
|
127
|
+
.generate(
|
|
128
|
+
compiled.html,
|
|
129
|
+
plaintextPath,
|
|
130
|
+
merge(plaintextConfig, {filepath: file})
|
|
131
|
+
)
|
|
132
|
+
.then(({plaintext, destination}) => fs.outputFile(destination, plaintext))
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
compiled.html = removePlaintextTags(compiled.html, config)
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Output file
|
|
139
|
+
*/
|
|
140
|
+
const parts = path.parse(destination)
|
|
141
|
+
const extension = get(templateConfig, 'destination.extension', 'html')
|
|
142
|
+
const finalDestination = `${parts.dir}/${parts.name}.${extension}`
|
|
143
|
+
|
|
144
|
+
await fs.outputFile(finalDestination, compiled.html)
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Remove original file if its path is different
|
|
148
|
+
* from the final destination path.
|
|
149
|
+
*
|
|
150
|
+
* This ensures non-HTML files do not pollute
|
|
151
|
+
* the build destination folder.
|
|
152
|
+
*/
|
|
153
|
+
if (finalDestination !== file) {
|
|
154
|
+
await fs.remove(file)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Keep track of handled files
|
|
158
|
+
files.push(file)
|
|
159
|
+
parsed.push(file)
|
|
160
|
+
} catch (error) {
|
|
161
|
+
switch (config.build.fail) {
|
|
162
|
+
case 'silent':
|
|
163
|
+
spinner.warn(`Failed to compile template: ${path.basename(file)}`)
|
|
164
|
+
break
|
|
165
|
+
case 'verbose':
|
|
166
|
+
spinner.warn(`Failed to compile template: ${path.basename(file)}`)
|
|
167
|
+
console.error(error)
|
|
168
|
+
break
|
|
169
|
+
default:
|
|
170
|
+
spinner.fail(`Failed to compile template: ${path.basename(file)}`)
|
|
171
|
+
throw error
|
|
172
|
+
}
|
|
173
|
+
}
|
|
161
174
|
})
|
|
162
175
|
|
|
163
176
|
const assets = {source: '', destination: 'assets', ...get(templateConfig, 'assets')}
|
|
@@ -22,13 +22,9 @@ 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
|
-
|
|
28
|
-
|
|
29
|
-
if (frontmatter) {
|
|
30
|
-
frontmatter = await posthtml(frontmatter, config)
|
|
31
|
-
}
|
|
27
|
+
const {frontmatter} = fm(html)
|
|
32
28
|
|
|
33
29
|
html = `---\n${frontmatter}\n---\n\n${fm(html).body}`
|
|
34
30
|
|
|
@@ -1,52 +1,49 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const {get} = require('lodash')
|
|
3
|
-
const {stripHtml} = require('string-strip-html')
|
|
4
|
-
|
|
5
|
-
module.exports.generate = async (html, destination, config) => {
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const plaintext = stripHtml(html, {
|
|
10
|
-
dumpLinkHrefsNearby: {
|
|
11
|
-
enabled: true
|
|
12
|
-
},
|
|
13
|
-
...options
|
|
14
|
-
}).result
|
|
15
|
-
|
|
16
|
-
// If we set plaintext.destination.path in config/fm
|
|
17
|
-
if (configDestinationPath) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
return {plaintext, destination}
|
|
52
|
-
}
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const {get} = require('lodash')
|
|
3
|
+
const {stripHtml} = require('string-strip-html')
|
|
4
|
+
|
|
5
|
+
module.exports.generate = async (html, destination, config) => {
|
|
6
|
+
const configDestinationPath = get(config, 'destination.path')
|
|
7
|
+
const extension = get(config, 'destination.extension', 'txt')
|
|
8
|
+
|
|
9
|
+
const plaintext = stripHtml(html, {
|
|
10
|
+
dumpLinkHrefsNearby: {
|
|
11
|
+
enabled: true
|
|
12
|
+
},
|
|
13
|
+
...get(config, 'options', {})
|
|
14
|
+
}).result
|
|
15
|
+
|
|
16
|
+
// If we set plaintext.destination.path in config/fm
|
|
17
|
+
if (configDestinationPath) {
|
|
18
|
+
/**
|
|
19
|
+
* Using a file path will generate a single plaintext file,
|
|
20
|
+
* no matter how many templates there are.
|
|
21
|
+
*
|
|
22
|
+
* It will be based on the last-processed template.
|
|
23
|
+
*/
|
|
24
|
+
if (path.extname(configDestinationPath)) {
|
|
25
|
+
destination = configDestinationPath
|
|
26
|
+
|
|
27
|
+
return {plaintext, destination}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Using a directory-like path for plaintext.destination.path
|
|
32
|
+
*/
|
|
33
|
+
destination = path.join(configDestinationPath, path.basename(config.filepath, path.extname(config.filepath)) + '.' + extension)
|
|
34
|
+
|
|
35
|
+
return {plaintext, destination}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Use template's `permalink` Front Matter key,
|
|
40
|
+
* fall back to the original `destination`.
|
|
41
|
+
*/
|
|
42
|
+
destination = get(config, 'permalink', destination)
|
|
43
|
+
|
|
44
|
+
if (typeof destination === 'string') {
|
|
45
|
+
destination = path.join(path.dirname(destination), path.basename(destination, path.extname(destination)) + '.' + extension)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {plaintext, destination}
|
|
49
|
+
}
|
|
@@ -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
|
+
}
|