@maizzle/framework 3.7.3 → 4.0.0-alpha.3

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.
Files changed (42) hide show
  1. package/.github/workflows/nodejs.yml +0 -1
  2. package/package.json +15 -13
  3. package/src/commands/build.js +32 -0
  4. package/src/commands/serve.js +139 -0
  5. package/src/functions/plaintext.js +5 -0
  6. package/src/functions/render.js +5 -0
  7. package/src/generators/output/to-disk.js +208 -167
  8. package/src/generators/output/to-string.js +5 -2
  9. package/src/generators/plaintext.js +49 -52
  10. package/src/generators/posthtml.js +61 -60
  11. package/src/generators/tailwindcss.js +114 -84
  12. package/src/index.js +13 -163
  13. package/src/transformers/{attribute-to-style.js → attributeToStyle.js} +0 -0
  14. package/src/transformers/baseUrl.js +45 -0
  15. package/src/transformers/{extra-attributes.js → extraAttributes.js} +0 -0
  16. package/src/transformers/index.js +57 -57
  17. package/src/transformers/{inline.js → inlineCss.js} +0 -0
  18. package/src/transformers/{posthtml-mso.js → posthtmlMso.js} +0 -0
  19. package/src/transformers/{prevent-widows.js → preventWidows.js} +0 -0
  20. package/src/transformers/{remove-attributes.js → removeAttributes.js} +1 -1
  21. package/src/transformers/{remove-inline-bgcolor.js → removeInlineBackgroundColor.js} +0 -0
  22. package/src/transformers/{remove-inline-sizes.js → removeInlineSizes.js} +0 -0
  23. package/src/transformers/{remove-unused-css.js → removeUnusedCss.js} +0 -0
  24. package/src/transformers/{replace-strings.js → replaceStrings.js} +0 -0
  25. package/src/transformers/{safe-class-names.js → safeClassNames.js} +8 -2
  26. package/src/transformers/{six-hex.js → sixHex.js} +0 -0
  27. package/src/transformers/transform.js +4 -6
  28. package/src/transformers/{url-params.js → urlParameters.js} +0 -0
  29. package/src/utils/helpers.js +2 -8
  30. package/test/expected/transformers/base-image-url.html +82 -6
  31. package/test/expected/transformers/transform-postcss.html +19 -0
  32. package/test/expected/useConfig.html +9 -0
  33. package/test/fixtures/basic.html +9 -9
  34. package/test/fixtures/transformers/base-image-url.html +84 -6
  35. package/test/fixtures/useConfig.html +9 -0
  36. package/test/stubs/tailwind/preserve.html +1 -0
  37. package/test/test-tailwind.js +68 -24
  38. package/test/test-todisk.js +497 -418
  39. package/test/test-tostring.js +132 -124
  40. package/test/test-transformers.js +25 -2
  41. package/xo.config.js +3 -0
  42. package/src/transformers/base-image-url.js +0 -9
@@ -7,7 +7,6 @@ on:
7
7
  push:
8
8
  branches: [master]
9
9
  pull_request:
10
- branches: [master]
11
10
 
12
11
  jobs:
13
12
  build:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maizzle/framework",
3
- "version": "3.7.3",
3
+ "version": "4.0.0-alpha.3",
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",
@@ -27,11 +27,13 @@
27
27
  "access": "public"
28
28
  },
29
29
  "scripts": {
30
- "test": "xo && nyc ava -s",
30
+ "test": "c8 ava -s",
31
+ "pretest": "xo",
31
32
  "style": "xo",
32
33
  "release": "np"
33
34
  },
34
35
  "dependencies": {
36
+ "autoprefixer": "^10.4.0",
35
37
  "browser-sync": "^2.26.13",
36
38
  "color-shorthand-hex-to-six-digit": "^3.0.2",
37
39
  "email-comb": "^5.0.0",
@@ -39,38 +41,38 @@
39
41
  "fs-extra": "^10.0.0",
40
42
  "glob-promise": "^4.1.0",
41
43
  "html-crush": "^4.0.0",
44
+ "is-url-superb": "^5.0.0",
42
45
  "juice": "^8.0.0",
43
46
  "lodash": "^4.17.20",
44
47
  "ora": "^5.1.0",
45
- "postcss": "^8.2.14",
48
+ "postcss": "^8.4.4",
46
49
  "postcss-import": "^14.0.0",
47
50
  "postcss-merge-longhand": "^5.0.1",
48
- "posthtml": "^0.16.4",
51
+ "posthtml": "^0.16.6",
49
52
  "posthtml-attrs-parser": "^0.1.1",
53
+ "posthtml-base-url": "^1.0.1",
50
54
  "posthtml-content": "^0.0.3",
51
55
  "posthtml-expressions": "^1.8.1",
52
56
  "posthtml-extend": "^0.6.0",
53
57
  "posthtml-extra-attributes": "^1.0.0",
54
58
  "posthtml-fetch": "^2.0.0",
55
- "posthtml-markdownit": "^1.2.2",
56
- "posthtml-modules": "^0.7.4",
57
- "posthtml-mso": "^1.0.2",
59
+ "posthtml-markdownit": "^1.3.0",
60
+ "posthtml-modules": "^0.8.0",
61
+ "posthtml-mso": "^1.0.4",
58
62
  "posthtml-postcss-merge-longhand": "^1.0.2",
59
63
  "posthtml-remove-attributes": "^1.0.0",
60
64
  "posthtml-safe-class-names": "^1.0.4",
61
65
  "posthtml-url-parameters": "^1.0.4",
62
66
  "pretty": "^2.0.0",
63
67
  "prevent-widows": "^1.0.2",
64
- "query-string": "^7.0.0",
68
+ "query-string": "^7.1.0",
65
69
  "string-strip-html": "^8.2.0",
66
- "tailwindcss": "^2.2.2",
67
- "tailwindcss-box-shadow": "^1.0.0"
70
+ "tailwindcss": "^3.0.0"
68
71
  },
69
72
  "devDependencies": {
70
- "autoprefixer": "^10.0.2",
71
- "ava": "^3.13.0",
73
+ "ava": "^4.0.1",
74
+ "c8": "^7.11.0",
72
75
  "np": "*",
73
- "nyc": "^15.1.0",
74
76
  "xo": "0.39.1"
75
77
  },
76
78
  "engines": {
@@ -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,139 @@
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 (get(config, 'build.console.clear')) {
52
+ clearConsole()
53
+ }
54
+
55
+ const start = new Date()
56
+
57
+ spinner.start('Building email...')
58
+
59
+ file = file.replace(/\\/g, '/')
60
+
61
+ if (config.events && typeof config.events.beforeCreate === 'function') {
62
+ await config.events.beforeCreate(config)
63
+ }
64
+
65
+ const renderOptions = {
66
+ maizzle: config,
67
+ ...config.events
68
+ }
69
+
70
+ renderToString(
71
+ await fs.readFile(file, 'utf8'),
72
+ renderOptions
73
+ )
74
+ .then(async ({html, config}) => {
75
+ let dest = ''
76
+ let ext = ''
77
+
78
+ if (Array.isArray(config.build.templates)) {
79
+ const match = config.build.templates.find(template => template.source === path.parse(file).dir)
80
+ dest = get(match, 'destination.path', 'build_local')
81
+ ext = get(match, 'destination.ext', 'html')
82
+ } else if (isObject(config.build.templates)) {
83
+ dest = get(config, 'build.templates.destination.path', 'build_local')
84
+ ext = get(config, 'build.templates.destination.ext', 'html')
85
+ }
86
+
87
+ const finalDestination = path.join(dest, `${path.parse(file).name}.${ext}`)
88
+
89
+ await fs.outputFile(config.permalink || finalDestination, html)
90
+ })
91
+ .then(() => {
92
+ browsersync().reload()
93
+ spinner.succeed(`Compiled in ${(Date.now() - start) / 1000}s [${file}]`)
94
+ })
95
+ .catch(() => spinner.warn(`Received empty HTML, please save your file again [${file}]`))
96
+ })
97
+
98
+ // Watch for changes in all other files
99
+ browsersync()
100
+ .watch(globalPaths, {ignored: templatePaths})
101
+ .on('change', () => buildToFile(env, config).then(() => browsersync().reload()))
102
+ .on('unlink', () => buildToFile(env, config).then(() => browsersync().reload()))
103
+
104
+ // Watch for changes in config files
105
+ browsersync()
106
+ .watch('config*.js')
107
+ .on('change', async file => {
108
+ const parsedEnv = path.parse(file).name.split('.')[1] || 'local'
109
+
110
+ Config
111
+ .getMerged(parsedEnv)
112
+ .then(config => buildToFile(parsedEnv, config).then(() => browsersync().reload()))
113
+ })
114
+
115
+ // Browsersync options
116
+ const baseDir = templates.map(t => t.destination.path)
117
+
118
+ // Initialize Browsersync
119
+ browsersync()
120
+ .init({
121
+ notify: false,
122
+ open: false,
123
+ port: 3000,
124
+ server: {
125
+ baseDir,
126
+ directory: true
127
+ },
128
+ tunnel: false,
129
+ ui: {port: 3001},
130
+ logFileChanges: false,
131
+ ...get(config, 'build.browsersync', {})
132
+ }, () => {})
133
+ } catch (error) {
134
+ spinner.fail(error)
135
+ throw error
136
+ }
137
+ }
138
+
139
+ module.exports = serve
@@ -0,0 +1,5 @@
1
+ const Plaintext = require('../generators/plaintext')
2
+
3
+ const toPlaintext = async (html, config = {}) => Plaintext.generate(html, false, config)
4
+
5
+ module.exports = toPlaintext
@@ -0,0 +1,5 @@
1
+ const Output = require('../generators/output')
2
+
3
+ const render = async (html, options) => Output.toString(html, options)
4
+
5
+ module.exports = render
@@ -1,167 +1,208 @@
1
- const path = require('path')
2
- const fs = require('fs-extra')
3
- const glob = require('glob-promise')
4
- const {get, isEmpty, merge} = require('lodash')
5
- const {asyncForEach} = require('../../utils/helpers')
6
- const removePlaintextTags = require('../../transformers/plaintext')
7
-
8
- const Config = require('../config')
9
- const Tailwind = require('../tailwindcss')
10
- const Plaintext = require('../plaintext')
11
-
12
- const render = require('./to-string')
13
-
14
- module.exports = async (env, spinner, config) => {
15
- process.env.NODE_ENV = env || 'local'
16
-
17
- if (isEmpty(config)) {
18
- config = await Config.getMerged(env).catch(error => {
19
- spinner.fail('Build failed')
20
- throw error
21
- })
22
- }
23
-
24
- const buildTemplates = get(config, 'build.templates')
25
- const templatesConfig = Array.isArray(buildTemplates) ? buildTemplates : [buildTemplates]
26
-
27
- const parsed = []
28
- let files = []
29
-
30
- const css = (typeof get(config, 'tailwind.compiled') === 'string')
31
- ? config.tailwind.compiled
32
- : await Tailwind.compile('@tailwind components; @tailwind utilities;', '', {}, config)
33
-
34
- await asyncForEach(templatesConfig, async templateConfig => {
35
- const outputDir = get(templateConfig, 'destination.path', `build_${env}`)
36
-
37
- await fs.remove(outputDir)
38
-
39
- await fs
40
- .copy(templateConfig.source, outputDir)
41
- .then(async () => {
42
- const extensions = Array.isArray(templateConfig.filetypes)
43
- ? templateConfig.filetypes.join('|')
44
- : templateConfig.filetypes || get(templateConfig, 'filetypes', 'html')
45
-
46
- const templates = await glob(`${outputDir}/**/*.+(${extensions})`)
47
-
48
- if (templates.length === 0) {
49
- spinner.warn(`Error: no files with the .${extensions} extension found in ${templateConfig.source}`)
50
- return
51
- }
52
-
53
- // Store template config currently being processed
54
- config.build.currentTemplates = templateConfig
55
-
56
- if (config.events && typeof config.events.beforeCreate === 'function') {
57
- await config.events.beforeCreate(config)
58
- }
59
-
60
- await asyncForEach(templates, async file => {
61
- const html = await fs.readFile(file, 'utf8')
62
-
63
- await render(html, {
64
- maizzle: {
65
- ...config,
66
- env
67
- },
68
- tailwind: {
69
- compiled: css
70
- },
71
- ...config.events
72
- })
73
- .then(async ({html, config}) => {
74
- const destination = config.permalink || file
75
-
76
- /**
77
- * Generate plaintext
78
- *
79
- * We do this first so that we can remove the <plaintext>
80
- * tags from the markup before outputting the file.
81
- */
82
-
83
- // Make this a breaking change in 4.0, get only from `templateConfig`
84
- const plaintextConfig = get(templateConfig, 'plaintext', get(config, 'plaintext'))
85
- const plaintextDestination = get(plaintextConfig, 'destination', config.permalink || file)
86
-
87
- if ((typeof plaintextConfig === 'boolean' && plaintextConfig) || !isEmpty(plaintextConfig)) {
88
- await Plaintext
89
- .generate(html, plaintextDestination, merge(config, {filepath: file}))
90
- .then(({plaintext, destination}) => fs.outputFile(destination, plaintext))
91
- }
92
-
93
- html = removePlaintextTags(html, config)
94
-
95
- /**
96
- * Output file
97
- */
98
- const parts = path.parse(destination)
99
- const extension = get(templateConfig, 'destination.extension', 'html')
100
- const finalDestination = `${parts.dir}/${parts.name}.${extension}`
101
-
102
- await fs.outputFile(finalDestination, html)
103
- .then(async () => {
104
- /**
105
- * Remove original file if its path is different
106
- * from the final destination path.
107
- *
108
- * This ensures non-HTML files do not pollute
109
- * the build destination folder.
110
- */
111
- if (finalDestination !== file) {
112
- await fs.remove(file)
113
- }
114
-
115
- // Keep track of handled files
116
- files.push(file)
117
- parsed.push(file)
118
- })
119
- })
120
- .catch(error => {
121
- switch (config.build.fail) {
122
- case 'silent':
123
- spinner.warn(`Failed to compile template: ${path.basename(file)}`)
124
- break
125
- case 'verbose':
126
- spinner.warn(`Failed to compile template: ${path.basename(file)}`)
127
- console.error(error)
128
- break
129
- default:
130
- spinner.fail(`Failed to compile template: ${path.basename(file)}`)
131
- throw error
132
- }
133
- })
134
- })
135
-
136
- const assets = {source: '', destination: 'assets', ...get(templateConfig, 'assets')}
137
-
138
- if (Array.isArray(assets.source)) {
139
- await asyncForEach(assets.source, async source => {
140
- if (fs.existsSync(source)) {
141
- await fs.copy(source, path.join(templateConfig.destination.path, assets.destination)).catch(error => spinner.warn(error.message))
142
- }
143
- })
144
- } else {
145
- if (fs.existsSync(assets.source)) {
146
- await fs.copy(assets.source, path.join(templateConfig.destination.path, assets.destination)).catch(error => spinner.warn(error.message))
147
- }
148
- }
149
-
150
- await glob(path.join(templateConfig.destination.path, '/**/*.*'))
151
- .then(contents => {
152
- files = [...new Set([...files, ...contents])]
153
- })
154
- })
155
- .catch(error => spinner.warn(error.message))
156
- })
157
-
158
- if (config.events && typeof config.events.afterBuild === 'function') {
159
- await config.events.afterBuild(files)
160
- }
161
-
162
- return {
163
- files,
164
- parsed,
165
- css
166
- }
167
- }
1
+ const path = require('path')
2
+ const fs = require('fs-extra')
3
+ const glob = require('glob-promise')
4
+ const {get, isEmpty, merge} = require('lodash')
5
+ const {asyncForEach} = require('../../utils/helpers')
6
+ const removePlaintextTags = require('../../transformers/plaintext')
7
+
8
+ const Config = require('../config')
9
+ const Tailwind = require('../tailwindcss')
10
+ const Plaintext = require('../plaintext')
11
+
12
+ const render = require('./to-string')
13
+
14
+ module.exports = async (env, spinner, config) => {
15
+ process.env.NODE_ENV = env || 'local'
16
+
17
+ if (isEmpty(config)) {
18
+ config = await Config.getMerged(env).catch(error => {
19
+ spinner.fail('Build failed')
20
+ throw error
21
+ })
22
+ }
23
+
24
+ const buildTemplates = get(config, 'build.templates')
25
+ const templatesConfig = Array.isArray(buildTemplates) ? buildTemplates : [buildTemplates]
26
+
27
+ const parsed = []
28
+ let files = []
29
+
30
+ const css = (typeof get(config, 'tailwind.compiled') === 'string')
31
+ ? config.tailwind.compiled
32
+ : await Tailwind.compile('@tailwind components; @tailwind utilities;', '', {}, config, spinner)
33
+
34
+ // Parse each template config object
35
+ await asyncForEach(templatesConfig, async templateConfig => {
36
+ const outputDir = get(templateConfig, 'destination.path', `build_${env}`)
37
+
38
+ await fs.remove(outputDir)
39
+
40
+ /**
41
+ * Get all files in the template config's source directory
42
+ * Supports `source` defined as:
43
+ * - string
44
+ * - array of strings
45
+ * - function that returns either of the above
46
+ *
47
+ * */
48
+ const templateSource = []
49
+ const templateTypeErrorMessage = 'Invalid template source: expected string or array of strings, got '
50
+
51
+ if (typeof templateConfig.source === 'function') {
52
+ const sources = templateConfig.source(config)
53
+
54
+ if (Array.isArray(sources)) {
55
+ templateSource.push(...sources)
56
+ } else if (typeof sources === 'string') {
57
+ templateSource.push(sources)
58
+ } else {
59
+ throw new TypeError(templateTypeErrorMessage + typeof sources)
60
+ }
61
+ } else {
62
+ if (Array.isArray(templateConfig.source)) {
63
+ templateSource.push(...templateConfig.source)
64
+ } else if (typeof templateConfig.source === 'string') {
65
+ templateSource.push(templateConfig.source)
66
+ } else {
67
+ throw new TypeError(templateTypeErrorMessage + typeof templateConfig.source)
68
+ }
69
+ }
70
+
71
+ // Parse each template source
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
+
80
+ await fs
81
+ .copy(source, out)
82
+ .then(async () => {
83
+ const extensions = Array.isArray(templateConfig.filetypes)
84
+ ? templateConfig.filetypes.join('|')
85
+ : templateConfig.filetypes || get(templateConfig, 'filetypes', 'html')
86
+
87
+ const templates = await glob(`${outputDir}/**/*.+(${extensions})`)
88
+
89
+ if (templates.length === 0) {
90
+ spinner.warn(`Error: no files with the .${extensions} extension found in ${templateConfig.source}`)
91
+ return
92
+ }
93
+
94
+ if (config.events && typeof config.events.beforeCreate === 'function') {
95
+ await config.events.beforeCreate(config)
96
+ }
97
+
98
+ await asyncForEach(templates, async file => {
99
+ const html = await fs.readFile(file, 'utf8')
100
+
101
+ try {
102
+ const compiled = await render(html, {
103
+ maizzle: {
104
+ ...config,
105
+ env
106
+ },
107
+ tailwind: {
108
+ compiled: css
109
+ },
110
+ ...config.events
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
+ }
174
+ })
175
+
176
+ const assets = {source: '', destination: 'assets', ...get(templateConfig, 'assets')}
177
+
178
+ if (Array.isArray(assets.source)) {
179
+ await asyncForEach(assets.source, async source => {
180
+ if (fs.existsSync(source)) {
181
+ await fs.copy(source, path.join(templateConfig.destination.path, assets.destination)).catch(error => spinner.warn(error.message))
182
+ }
183
+ })
184
+ } else {
185
+ if (fs.existsSync(assets.source)) {
186
+ await fs.copy(assets.source, path.join(templateConfig.destination.path, assets.destination)).catch(error => spinner.warn(error.message))
187
+ }
188
+ }
189
+
190
+ await glob(path.join(templateConfig.destination.path, '/**/*.*'))
191
+ .then(contents => {
192
+ files = [...new Set([...files, ...contents])]
193
+ })
194
+ })
195
+ .catch(error => spinner.warn(error.message))
196
+ })
197
+ })
198
+
199
+ if (config.events && typeof config.events.afterBuild === 'function') {
200
+ await config.events.afterBuild(files)
201
+ }
202
+
203
+ return {
204
+ files,
205
+ parsed,
206
+ css
207
+ }
208
+ }
@@ -3,7 +3,8 @@ const {get, merge} = require('lodash')
3
3
  const posthtml = require('../posthtml')
4
4
  const Tailwind = require('../tailwindcss')
5
5
  const Transformers = require('../../transformers')
6
- const posthtmlMSO = require('../../transformers/posthtml-mso')
6
+ const posthtmlMSO = require('../../transformers/posthtmlMso')
7
+ const Config = require('../config')
7
8
 
8
9
  module.exports = async (html, options) => {
9
10
  process.env.NODE_ENV = get(options, 'maizzle.env', 'local')
@@ -16,7 +17,9 @@ module.exports = async (html, options) => {
16
17
  throw new RangeError('received empty string')
17
18
  }
18
19
 
19
- let config = get(options, 'maizzle', {})
20
+ const fileConfig = await Config.getMerged(process.env.NODE_ENV)
21
+
22
+ let config = merge(fileConfig, get(options, 'maizzle', {}))
20
23
 
21
24
  const tailwindConfig = get(options, 'tailwind.config', {})
22
25
  const cssString = get(options, 'tailwind.css', '@tailwind components; @tailwind utilities;')