@maizzle/framework 5.0.0-beta.17 → 5.0.0-beta.19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maizzle/framework",
3
- "version": "5.0.0-beta.17",
3
+ "version": "5.0.0-beta.19",
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",
@@ -60,8 +60,6 @@ export async function render(html = '', config = {}) {
60
60
  * @param {string} options.html - The HTML to be transformed
61
61
  * @param {Object} options.matter - The front matter data
62
62
  * @param {Object} options.config - The current template config
63
- * @param {function} options.posthtml - The PostHTML compiler
64
- * @param {Object} options.transform - The transformers object
65
63
  * @returns {string} - The transformed HTML, or the original one if nothing was returned
66
64
  */
67
65
  if (typeof templateConfig.beforeRender === 'function') {
@@ -69,7 +67,6 @@ export async function render(html = '', config = {}) {
69
67
  html: content,
70
68
  matter: matterData,
71
69
  config: templateConfig,
72
- posthtml: compilePostHTML,
73
70
  })) ?? content
74
71
  }
75
72
 
@@ -83,8 +80,6 @@ export async function render(html = '', config = {}) {
83
80
  * @param {string} options.html - The HTML to be transformed
84
81
  * @param {Object} options.matter - The front matter data
85
82
  * @param {Object} options.config - The current template config
86
- * @param {function} options.posthtml - The PostHTML compiler
87
- * @param {Object} options.transform - The transformers object
88
83
  * @returns {string} - The transformed HTML, or the original one if nothing was returned
89
84
  */
90
85
  if (typeof templateConfig.afterRender === 'function') {
@@ -92,7 +87,6 @@ export async function render(html = '', config = {}) {
92
87
  html: compiled.html,
93
88
  matter: matterData,
94
89
  config: templateConfig,
95
- posthtml: compilePostHTML,
96
90
  })) ?? compiled.html
97
91
  }
98
92
 
@@ -118,8 +112,6 @@ export async function render(html = '', config = {}) {
118
112
  * @param {string} options.html - The HTML to be transformed
119
113
  * @param {Object} options.matter - The front matter data
120
114
  * @param {Object} options.config - The current template config
121
- * @param {function} options.posthtml - The PostHTML compiler
122
- * @param {Object} options.transform - The transformers object
123
115
  * @returns {string} - The transformed HTML, or the original one if nothing was returned
124
116
  */
125
117
  if (typeof templateConfig.afterTransformers === 'function') {
@@ -127,7 +119,6 @@ export async function render(html = '', config = {}) {
127
119
  html: compiled.html,
128
120
  matter: matterData,
129
121
  config: templateConfig,
130
- posthtml: compilePostHTML,
131
122
  })) ?? compiled.html
132
123
  }
133
124
 
@@ -55,7 +55,7 @@ export async function process(html = '', config = {}) {
55
55
  merge(
56
56
  {
57
57
  expressions: merge(
58
- locals,
58
+ { locals },
59
59
  expressionsOptions,
60
60
  {
61
61
  missingLocal: '{local}',
@@ -77,9 +77,10 @@ export async function process(html = '', config = {}) {
77
77
  components(
78
78
  merge(
79
79
  {
80
- expressions: {
81
- locals,
82
- }
80
+ expressions: merge(
81
+ { locals },
82
+ expressionsOptions,
83
+ )
83
84
  },
84
85
  componentsUserOptions,
85
86
  defaultComponentsConfig
@@ -112,10 +112,12 @@ export default async (config = {}) => {
112
112
 
113
113
  /**
114
114
  * Dev server settings
115
- */
115
+ */
116
+ spinner.spinner = get(config, 'server.spinner', 'circleHalves')
117
+ spinner.start('Starting server...')
118
+
116
119
  const shouldScroll = get(config, 'server.scrollSync', false)
117
120
  const useHmr = get(config, 'server.hmr', true)
118
- spinner.spinner = get(config, 'server.spinner', 'circleHalves')
119
121
 
120
122
  // Add static assets root prefix so user doesn't have to
121
123
  if (!config.baseURL) {
@@ -193,20 +195,6 @@ export default async (config = {}) => {
193
195
  })
194
196
  })
195
197
 
196
- // Error-handling middleware
197
- app.use(async (error, req, res, next) => {
198
- console.error(error)
199
-
200
- const view = await fs.readFile(path.join(__dirname, 'views', 'error.html'), 'utf8')
201
- const { html } = await render(view, {
202
- method: req.method,
203
- url: req.url,
204
- error
205
- })
206
-
207
- res.status(500).send(html)
208
- })
209
-
210
198
  /**
211
199
  * Components watcher
212
200
  *
@@ -214,7 +202,19 @@ export default async (config = {}) => {
214
202
  */
215
203
  let isWatcherReady = false
216
204
  chokidar
217
- .watch([...templatePaths, ...get(config, 'components.folders', defaultComponentsConfig.folders)])
205
+ .watch(
206
+ [
207
+ ...templatePaths,
208
+ ...get(config, 'components.folders', defaultComponentsConfig.folders)
209
+ ],
210
+ {
211
+ ignoreInitial: true,
212
+ awaitWriteFinish: {
213
+ stabilityThreshold: 150,
214
+ pollInterval: 25,
215
+ },
216
+ }
217
+ )
218
218
  .on('change', async () => {
219
219
  if (viewing) {
220
220
  await renderUpdatedFile(viewing, config)
@@ -244,20 +244,33 @@ export default async (config = {}) => {
244
244
  /**
245
245
  * Global watcher
246
246
  *
247
- * Watch for changes in the config file, Tailwind CSS config, and CSS files
247
+ * Watch for changes in the config files, Tailwind CSS config, CSS files,
248
+ * configured static assets, and user-defined watch paths.
248
249
  */
249
250
  const globalWatchedPaths = new Set([
250
- 'config*.js',
251
- 'maizzle.config*.js',
252
- 'tailwind*.config.js',
251
+ 'config*.{js,cjs,ts}',
252
+ 'maizzle.config*.{js,cjs,ts}',
253
+ 'tailwind*.config.{js,ts}',
253
254
  '**/*.css',
254
- ...get(config, 'server.watch', [])
255
+ ...get(config, 'build.static.source', []),
256
+ ...get(config, 'server.watch', []),
255
257
  ])
256
258
 
257
259
  async function globalPathsHandler(file, eventType) {
260
+ // Update express.static to serve new files
261
+ if (eventType === 'add') {
262
+ app.use(express.static(path.dirname(file)))
263
+ }
264
+
265
+ // Stop serving deleted files
266
+ if (eventType === 'unlink') {
267
+ app._router.stack = app._router.stack.filter(
268
+ layer => layer.regexp.source !== path.dirname(file).replace(/\\/g, '/')
269
+ )
270
+ }
271
+
258
272
  // Not viewing a component in the browser, no need to rebuild
259
273
  if (!viewing) {
260
- spinner.info(`file ${eventType}: ${file}`)
261
274
  return
262
275
  }
263
276
 
@@ -314,7 +327,7 @@ export default async (config = {}) => {
314
327
  }
315
328
  })
316
329
  } catch (error) {
317
- spinner.fail('Failed to render template.')
330
+ spinner.fail(`Failed to render template: ${file}`)
318
331
  throw error
319
332
  }
320
333
  }
@@ -326,6 +339,10 @@ export default async (config = {}) => {
326
339
  get(config, 'build.output.path', 'build_production'),
327
340
  ],
328
341
  ignoreInitial: true,
342
+ awaitWriteFinish: {
343
+ stabilityThreshold: 150,
344
+ pollInterval: 25,
345
+ },
329
346
  })
330
347
  .on('change', async file => await globalPathsHandler(file, 'change'))
331
348
  .on('add', async file => await globalPathsHandler(file, 'add'))
@@ -333,8 +350,6 @@ export default async (config = {}) => {
333
350
 
334
351
  /**
335
352
  * Serve all folders in the cwd as static files
336
- *
337
- * TODO: change to include build.assets or build.static, which may be outside cwd
338
353
  */
339
354
  const srcFoldersList = await fg.glob(
340
355
  [
@@ -352,6 +367,16 @@ export default async (config = {}) => {
352
367
  app.use(express.static(path.join(config.cwd, folder)))
353
368
  })
354
369
 
370
+ // Error-handling middleware
371
+ app.use(async (req, res) => {
372
+ const view = await fs.readFile(path.join(__dirname, 'views', '404.html'), 'utf8')
373
+ const { html } = await render(view, {
374
+ url: req.url,
375
+ })
376
+
377
+ res.status(404).send(html)
378
+ })
379
+
355
380
  /**
356
381
  * Start the server
357
382
  */
@@ -361,8 +386,6 @@ export default async (config = {}) => {
361
386
 
362
387
  function startServer(port) {
363
388
  const serverStartTime = Date.now()
364
- spinner.start('Starting server...')
365
-
366
389
  const server = createServer(app)
367
390
 
368
391
  /**
@@ -0,0 +1,59 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>404 - Template not found</title>
7
+ <style>
8
+ html, body {
9
+ font-family: Helvetica, Arial, sans-serif;
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ height: 100%;
14
+ }
15
+
16
+ .container {
17
+ box-sizing: border-box;
18
+ height: 100vh;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ position: relative;
23
+ z-index: 1;
24
+ padding: 24px;
25
+ }
26
+
27
+ .error-code {
28
+ font-size: 25rem;
29
+ font-weight: 700;
30
+ color: #f1f5f9;
31
+ position: fixed;
32
+ top: -1.5rem;
33
+ left: -3rem;
34
+ user-select: none;
35
+ }
36
+ </style>
37
+ </head>
38
+ <body>
39
+ <span class="error-code">404</span>
40
+
41
+ <div class="container">
42
+ <div style="text-align: center;">
43
+ <h1 style="font-size: 3rem; color: #0F172A; margin: 2.25rem 0">
44
+ Template Not Found
45
+ </h1>
46
+ <p style="margin: 0 0 2.25rem; font-size: 1.25rem; line-height: 1.5; color: #64748B;">
47
+ The Template you are looking for was not found:
48
+ </p>
49
+ <p style="margin: 1rem 0 0; font-size: 1rem; line-height: 1.5; font-weight: 600; color: #334155;">
50
+ {{ page.url }}
51
+ </p>
52
+ </div>
53
+ </div>
54
+
55
+ <div style="position: fixed; bottom: 0; right: 0; pointer-events: none; user-select: none;">
56
+ <svg width="883" height="536" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="a" style="mask-type:alpha" maskUnits="userSpaceOnUse" x="0" y="0" width="1100" height="536"><path fill="#D9D9D9" d="M0 .955h1100V536H0z"/></mask><g mask="url(#a)" stroke="#94A3B8" stroke-miterlimit="10"><path d="M1056.93 92.587c0-50.03-43.95-90.587-98.168-90.587-54.22 0-98.174 40.557-98.174 90.587v483.125c0 50.029 43.954 90.586 98.174 90.586 54.218 0 98.168-40.557 98.168-90.586V92.587ZM646.241 92.587C646.241 42.556 602.287 2 548.067 2c-54.219 0-98.173 40.557-98.173 90.587v483.125c0 50.029 43.954 90.586 98.173 90.586 54.22 0 98.174-40.557 98.174-90.586V92.587Z"/><path d="M1036.18 148.383c33.41-39.402 25.88-96.336-16.82-127.164C976.657-9.61 914.955-2.66 881.544 36.742L471.586 520.215c-33.411 39.402-25.879 96.336 16.824 127.164 42.702 30.829 104.404 23.879 137.815-15.523l409.955-483.473ZM625.093 148.396c33.411-39.403 25.878-96.336-16.824-127.164C565.567-9.597 503.865-2.647 470.454 36.755L60.495 520.228c-33.41 39.402-25.878 96.336 16.825 127.164 42.702 30.829 104.404 23.879 137.815-15.523l409.958-483.473Z"/></g></svg>
57
+ </div>
58
+ </body>
59
+ </html>
@@ -178,21 +178,6 @@ export async function run(html = '', config = {}) {
178
178
  posthtmlPlugins.push(
179
179
  baseUrl(get(config, 'baseURL', get(config, 'baseUrl', {})))
180
180
  )
181
- } else {
182
- /**
183
- * Set baseURL to `build.static.destination` if it's not already set.
184
- */
185
- const destination = get(config, 'build.static.destination', '')
186
- if (destination && !config._dev) {
187
- posthtmlPlugins.push(
188
- baseUrl({
189
- url: destination,
190
- allTags: true,
191
- styleTag: true,
192
- inlineCss: true,
193
- })
194
- )
195
- }
196
181
  }
197
182
 
198
183
  /**
@@ -15,9 +15,11 @@ const posthtmlPlugin = (replacements = {}) => tree => {
15
15
  render(tree).replace(patterns, matched => {
16
16
  for (const [regex, replacement] of regexes) {
17
17
  if (regex.test(matched)) {
18
- return replacement
18
+ return matched.replace(regex, replacement)
19
19
  }
20
20
  }
21
+
22
+ return matched
21
23
  }),
22
24
  defaultPostHTMLConfig
23
25
  )
package/types/build.d.ts CHANGED
@@ -116,4 +116,31 @@ export default interface BuildConfig {
116
116
  * ```
117
117
  */
118
118
  summary?: boolean;
119
+
120
+ /**
121
+ * Information about the Template currently being compiled.
122
+ *
123
+ * @example
124
+ *
125
+ * ```
126
+ * {
127
+ path: {
128
+ root: 'build_production',
129
+ dir: 'build_production',
130
+ base: 'transactional.html',
131
+ ext: '.html',
132
+ name: 'transactional'
133
+ }
134
+ }
135
+ * ```
136
+ */
137
+ current?: {
138
+ path?: {
139
+ root: string;
140
+ dir: string;
141
+ base: string;
142
+ ext: string;
143
+ name: string;
144
+ };
145
+ };
119
146
  }
package/types/events.d.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  import type Config from "./config";
2
2
 
3
- type PostHTMLType = (html: string, config: Config) => { html: string; config: Config };
4
-
5
3
  export default interface Events {
6
4
  /**
7
5
  * Runs after the Environment config has been computed, but before Templates are processed.
@@ -57,13 +55,6 @@ export default interface Events {
57
55
  * This is the Environment config merged with the Template's Front Matter.
58
56
  */
59
57
  config: Config;
60
- /**
61
- * A function to process an HTML string with PostHTML.
62
- *
63
- * @param {string} html The HTML string to process.
64
- * @param {Config} config The Maizzle config object.
65
- */
66
- posthtml: PostHTMLType;
67
58
  }) => string | Promise<string>;
68
59
 
69
60
  /**
@@ -98,13 +89,6 @@ export default interface Events {
98
89
  * This is the Environment config merged with the Template's Front Matter.
99
90
  */
100
91
  config: Config;
101
- /**
102
- * A function to process an HTML string with PostHTML.
103
- *
104
- * @param {string} html The HTML string to process.
105
- * @param {Config} config The Maizzle config object.
106
- */
107
- posthtml: PostHTMLType;
108
92
  }) => string | Promise<string>;
109
93
 
110
94
  /**
@@ -139,13 +123,6 @@ export default interface Events {
139
123
  * This is the Environment config merged with the Template's Front Matter.
140
124
  */
141
125
  config: Config;
142
- /**
143
- * A function to process an HTML string with PostHTML.
144
- *
145
- * @param {string} html The HTML string to process.
146
- * @param {Config} config The Maizzle config object.
147
- */
148
- posthtml: PostHTMLType;
149
126
  }) => string | Promise<string>;
150
127
 
151
128
  /**