@nxgt/mail-config 0.1.0

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.
@@ -0,0 +1,168 @@
1
+ # Production
2
+
3
+ This page is for adding a production build next to the everyday one: the same
4
+ project config, with the HTML minified, written somewhere else, with whatever
5
+ else only production needs.
6
+
7
+ ```ts
8
+ // maizzle.config.production.ts
9
+ import { productionConfig } from '@nxgt/mail-config';
10
+ import config from './maizzle.config';
11
+
12
+ export default productionConfig(config, { output: { path: 'dist-production' } });
13
+ ```
14
+
15
+ ```json
16
+ {
17
+ "scripts": {
18
+ "dev": "maizzle serve",
19
+ "build": "maizzle build -c maizzle.config.production.ts"
20
+ }
21
+ }
22
+ ```
23
+
24
+ Maizzle 6 has no environments. `maizzle build -c <file>` loads that file and
25
+ no other — not `maizzle.config.ts` beside it — so the production file imports
26
+ the project config and builds on it.
27
+
28
+ ## The signature
29
+
30
+ ```ts
31
+ import type { MaizzleConfig } from '@maizzle/framework';
32
+
33
+ function productionConfig(
34
+ config: MaizzleConfig & { readonly plugins?: never },
35
+ overrides?: MaizzleConfig & { readonly plugins?: never },
36
+ ): MaizzleConfig;
37
+ ```
38
+
39
+ Neither argument may carry `plugins`: every plugin is listed in the project
40
+ config, and `plugins` in either one is a type error as well as a `TypeError`
41
+ at load time.
42
+
43
+ | Parameter | Type | Default | Effect |
44
+ | --- | --- | --- | --- |
45
+ | `config` | `MaizzleConfig` | — | The project config: what `maizzle.config.ts` exports, that is **what `defineMailConfig` answered** |
46
+ | `overrides` | `MaizzleConfig` | `{}` | Layered last: wins over the project and over the minification |
47
+
48
+ It answers three layers, lowest first — `config`, then
49
+ `{ html: { minify: true } }` (left out when the project already set minify
50
+ options, [below](#what-it-changes)), then `overrides` — merged by the same
51
+ rules as `defineMailConfig`, the overrides as a plugin is: objects merge,
52
+ arrays replace, their `components.source`, `vite.plugins` and `vue.plugins`
53
+ are added to the project's, their build events run after the project's. See
54
+ [The project config](config.md#how-two-layers-merge). Neither argument is
55
+ changed.
56
+
57
+ ## What it changes
58
+
59
+ Only `html.minify`. Everything else is the project's:
60
+
61
+ ```ts
62
+ import { defineMailConfig, productionConfig } from '@nxgt/mail-config';
63
+
64
+ const config = defineMailConfig({ output: { path: 'dist' } });
65
+
66
+ productionConfig(config);
67
+ // { plaintext: true, output: { path: 'dist' }, html: { minify: true } }
68
+ ```
69
+
70
+ When the project config already sets `html.minify` to an object of options,
71
+ they are kept: `minify: true` would replace them.
72
+
73
+ ```ts
74
+ const config = defineMailConfig({
75
+ html: { minify: { lineLengthLimit: 1000 }, decodeEntities: false },
76
+ });
77
+ productionConfig(config).html;
78
+ // { minify: { lineLengthLimit: 1000 }, decodeEntities: false }
79
+ ```
80
+
81
+ Minifying with no output path of its own writes over the everyday build in
82
+ `dist/`. Give production its own folder, as above, when both are kept.
83
+
84
+ ## Overrides
85
+
86
+ Anything a Maizzle config holds. The minifier's options, for one:
87
+
88
+ ```ts
89
+ productionConfig(config, {
90
+ output: { path: 'dist-production' },
91
+ html: { minify: { lineLengthLimit: 1000 } },
92
+ });
93
+ // { plaintext: true, output: { path: 'dist-production' }, html: { minify: { lineLengthLimit: 1000 } } }
94
+ ```
95
+
96
+ A list in `overrides` is added to the project's, never replaces it — a Vite
97
+ plugin only production needs, say:
98
+
99
+ ```ts
100
+ const report = { name: 'report' }; // a Vite plugin of yours
101
+
102
+ productionConfig(config, { vite: { plugins: [report] } });
103
+ // vite.plugins: the project's (and its plugins'), then report
104
+ ```
105
+
106
+ A build event in `overrides` runs **after** the project's — and after every
107
+ plugin's, which the project config already chains:
108
+
109
+ ```ts
110
+ import { defineMailConfig, productionConfig } from '@nxgt/mail-config';
111
+
112
+ const config = defineMailConfig({ afterTransform: ({ html }) => `${html}p` });
113
+
114
+ export default productionConfig(config, {
115
+ afterTransform: ({ html }) => `${html}!`, // receives the project's output: '…p' becomes '…p!'
116
+ });
117
+ ```
118
+
119
+ A realistic one: fail the production build when an e-mail is heavier than an
120
+ inbox will show in full.
121
+
122
+ ```ts
123
+ // maizzle.config.production.ts
124
+ import { productionConfig } from '@nxgt/mail-config';
125
+ import config from './maizzle.config';
126
+
127
+ const limit = 100 * 1024; // some clients clip an e-mail past about 100 KB
128
+
129
+ export default productionConfig(config, {
130
+ output: { path: 'dist-production' },
131
+ afterTransform: ({ template, html }) => {
132
+ const size = new TextEncoder().encode(html).length;
133
+ if (size > limit) {
134
+ throw new Error(`${template.path.name}: ${size} bytes, over the ${limit}-byte limit`);
135
+ }
136
+ },
137
+ });
138
+ ```
139
+
140
+ Returning nothing keeps the HTML as it was; throwing fails the build.
141
+
142
+ ## Errors
143
+
144
+ A bare `TypeError`, when `maizzle.config.production.ts` loads:
145
+
146
+ | Message | Cause |
147
+ | --- | --- |
148
+ | `productionConfig: config must be the project config, as productionConfig(config, overrides)` | `config` is missing, `null`, an array, or not an object |
149
+ | `productionConfig: config lists plugins — pass what defineMailConfig answered, not its argument` | `config` still has `plugins`: it is the object given to `defineMailConfig`, not what it answered |
150
+ | `productionConfig: overrides must be an object` | `overrides` is `null`, an array, or not an object |
151
+ | `productionConfig: overrides list plugins — list every plugin in the project config` | `overrides` sets `plugins`. Plugins are layered once, in the project config; what only production needs goes in the overrides as plain config keys, which merge as a plugin's would |
152
+ | `productionConfig: afterBuild must be a function` | `overrides` sets a build event to something other than a function |
153
+
154
+ The second one comes from exporting the argument instead of the result:
155
+
156
+ ```ts
157
+ // maizzle.config.ts — wrong: exports the input, not a Maizzle config
158
+ const input = { plugins: [brand] };
159
+ export default input;
160
+
161
+ // right
162
+ export default defineMailConfig({ plugins: [brand] });
163
+ ```
164
+
165
+ ## See also
166
+
167
+ - [The project config](config.md) — the merge rules and the chained events.
168
+ - [Writing a plugin](plugins.md) — what a plugin can add, in both builds.
@@ -0,0 +1,76 @@
1
+ # Roadmap
2
+
3
+ Where `@nxgt/mail-config` is heading. A direction, not a commitment: there are
4
+ no dates here, and the version something shipped in is the only number.
5
+
6
+ ## Now
7
+
8
+ Nothing between releases.
9
+
10
+ ## Next
11
+
12
+ Nothing yet.
13
+
14
+ ## Later
15
+
16
+ Nothing yet. A request is welcome as an
17
+ [issue](https://github.com/softistx/nxgt-mail/issues).
18
+
19
+ ## Not planned
20
+
21
+ - **A preview server or a CLI of our own** — `maizzle serve` is the preview
22
+ and `maizzle build` the build. This package writes the config those commands
23
+ read; it never replaces them.
24
+ - **Environments beyond Maizzle's `-c` config files** — Maizzle has no
25
+ environments: `maizzle build -c <file>` loads that one file. A second config
26
+ file that imports the first, as `productionConfig` does, is the whole
27
+ mechanism; there is no `NODE_ENV` switch or environment map to learn.
28
+ - **A plugin that brings other plugins** — refused with an error. Every plugin
29
+ is listed in your project, so their order, and which one's key wins, is read
30
+ in one place.
31
+ - **Joining every array** — only `components.source`, `vite.plugins` and
32
+ `vue.plugins` are joined. Every other array replaces the one under it, as in
33
+ Maizzle, so a list your project sets is the list you get.
34
+ - **Last handler wins** — Maizzle's own merge keeps only the last
35
+ `beforeRender` (or any other event); here every layer's handler runs, in
36
+ order. A plugin silently disabling another's hook is the bug this package
37
+ exists to remove.
38
+ - **`moduleResolution: "nodenext"` as a contract** — bundler resolution
39
+ (`"moduleResolution": "bundler"`) is what is supported and tested, as Bun,
40
+ every bundler and Maizzle's own config loader resolve. `nodenext` may work;
41
+ it is not promised.
42
+
43
+ ## Shipped
44
+
45
+ The last ten, newest first, each with the version it came in. Everything
46
+ before is in the [CHANGELOG](../CHANGELOG.md).
47
+
48
+ - **A base Maizzle config, v0.1.0** — `defineMailConfig({ plugins, ...project })` for
49
+ the `maizzle.config.ts` of a normal Maizzle 6 project (`maizzle serve`,
50
+ `maizzle build`, unchanged). It turns plain text on (`baseConfig`), and
51
+ leaves everything else to Maizzle's defaults.
52
+ - **Plugins that do not drop each other, v0.1.0** — a plugin is a partial Maizzle
53
+ config with a `name`, layered base, then each plugin in order, then your
54
+ project, whose keys win. Every build event (`beforeCreate` to `afterBuild`)
55
+ runs each layer's handler in that order, and `components.source`,
56
+ `vite.plugins` and `vue.plugins` are joined, so two plugins that each bring
57
+ components keep both.
58
+ - **Checking a plugin where it is written, v0.1.0** — `defineMailPlugin(plugin)`: a
59
+ package that exports a plugin gets a missing name or a handler that is not a
60
+ function reported in its own code, not in the project that uses it.
61
+ - **A production config, v0.1.0** — `productionConfig(config, overrides)` for
62
+ `maizzle.config.production.ts`: your project config, the HTML minified,
63
+ then your overrides, built with `maizzle build -c
64
+ maizzle.config.production.ts`.
65
+ - **i18n as a plugin, `@nxgt/mail-i18n` v0.1.0** — `i18n({ locales,
66
+ fallbackLocale })`, listed in `plugins` — see
67
+ [its roadmap](https://github.com/softistx/nxgt-mail/blob/develop/packages/mail-i18n/docs/roadmap.md).
68
+ - **UI components as a plugin, `@nxgt/mail-ui` v0.1.0** — `ui({ brand, theme
69
+ })`, listed in `plugins`: e-mail components in the style of
70
+ `@nxgt/material-vue`, each replaceable by name in your project — see
71
+ [its roadmap](https://github.com/softistx/nxgt-mail/blob/develop/packages/mail-ui/docs/roadmap.md).
72
+ - **A starter project, with v0.1.0** — the official Maizzle starter with
73
+ `defineMailConfig`, the i18n and the UI plugins wired in as the READMEs
74
+ say, built, rendered in `en` and `fr` and served in CI, so the snippets are
75
+ known to work: [`examples/starter`](https://github.com/softistx/nxgt-mail/tree/develop/examples/starter).
76
+ In the repository; its README says how to start your own from npm.