@travetto/email-compiler 3.3.7 → 3.4.0-rc.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/email-compiler",
3
- "version": "3.3.7",
3
+ "version": "3.4.0-rc.0",
4
4
  "description": "Email compiling module",
5
5
  "keywords": [
6
6
  "email",
@@ -26,19 +26,20 @@
26
26
  "directory": "module/email-compiler"
27
27
  },
28
28
  "dependencies": {
29
- "@travetto/base": "^3.3.3",
30
- "@travetto/config": "^3.3.4",
31
- "@travetto/di": "^3.3.3",
32
- "@travetto/email": "^3.3.4",
33
- "@travetto/image": "^3.3.3",
34
- "@types/inline-css": "^3.0.1",
29
+ "@travetto/base": "^3.4.0-rc.0",
30
+ "@travetto/config": "^3.4.0-rc.0",
31
+ "@travetto/di": "^3.4.0-rc.0",
32
+ "@travetto/email": "^3.4.0-rc.0",
33
+ "@travetto/image": "^3.4.0-rc.0",
34
+ "@travetto/worker": "^3.4.0-rc.0",
35
+ "@types/inline-css": "^3.0.2",
35
36
  "html-entities": "^2.4.0",
36
37
  "inline-css": "^4.0.2",
37
38
  "purgecss": "^5.0.0",
38
- "sass": "^1.68.0"
39
+ "sass": "^1.69.5"
39
40
  },
40
41
  "peerDependencies": {
41
- "@travetto/cli": "^3.3.5"
42
+ "@travetto/cli": "^3.4.0-rc.0"
42
43
  },
43
44
  "peerDependenciesMeta": {
44
45
  "@travetto/cli": {
package/src/compiler.ts CHANGED
@@ -4,16 +4,34 @@ import { FileQueryProvider, TypedObject } from '@travetto/base';
4
4
  import { EmailCompileSource, EmailCompiled, EmailCompileContext, MailUtil } from '@travetto/email';
5
5
  import { RootIndex, path } from '@travetto/manifest';
6
6
  import { DynamicFileLoader } from '@travetto/base/src/internal/file-loader';
7
+ import { ManualAsyncIterator as Queue } from '@travetto/worker';
7
8
 
8
9
  import { EmailCompileUtil } from './util';
9
10
 
10
11
  const VALID_FILE = (file: string): boolean => /[.](scss|css|png|jpe?g|gif|ya?ml)$/.test(file) && !/[.]compiled[.]/.test(file);
11
12
 
13
+ type WatchEvent = { action: 'create' | 'update' | 'delete', file: string, folder: string };
14
+
12
15
  /**
13
16
  * Email compilation support
14
17
  */
15
18
  export class EmailCompiler {
16
19
 
20
+ /**
21
+ * Watch folders as needed
22
+ */
23
+ static async #watchFolders(folders: string[], handler: (ev: WatchEvent) => void, signal: AbortSignal): Promise<void> {
24
+ const lib = await import('@parcel/watcher');
25
+ for (const src of folders) {
26
+ const cleanup = await lib.subscribe(src, async (err, events) => {
27
+ for (const ev of events) {
28
+ handler({ action: ev.type, file: path.toPosix(ev.path), folder: src });
29
+ }
30
+ });
31
+ signal.addEventListener('abort', () => cleanup.unsubscribe());
32
+ }
33
+ }
34
+
17
35
  /** Load Template */
18
36
  static async loadTemplate(file: string): Promise<EmailCompileContext> {
19
37
  const entry = RootIndex.getEntry(file);
@@ -22,25 +40,13 @@ export class EmailCompiler {
22
40
  }
23
41
  const root = (await import(entry.outputFile)).default;
24
42
  const og: EmailCompileSource = await root.wrap();
25
- const res = {
43
+ const res: EmailCompileContext = {
26
44
  file: entry.sourceFile,
27
45
  module: entry.module,
46
+ images: {},
47
+ styles: {},
28
48
  ...og
29
49
  };
30
-
31
- const mod = RootIndex.getModule(entry.module)!;
32
-
33
- const resourcePaths = [
34
- path.resolve(mod.sourcePath, 'resources'),
35
- path.resolve(RootIndex.manifest.workspacePath, 'resources')
36
- ];
37
-
38
- const styles = res.styles ??= {};
39
- (styles.search ??= []).push(...resourcePaths);
40
-
41
- const images = res.images ??= {};
42
- (images.search ??= []).push(...resourcePaths);
43
-
44
50
  return res;
45
51
  }
46
52
 
@@ -106,7 +112,6 @@ export class EmailCompiler {
106
112
  return keys;
107
113
  }
108
114
 
109
-
110
115
  /**
111
116
  * Watch compilation
112
117
  */
@@ -118,14 +123,20 @@ export class EmailCompiler {
118
123
  )].map(x => path.resolve(RootIndex.getModule(x)!.sourcePath, 'resources'))
119
124
  );
120
125
 
121
- const stream = all.watchFiles();
126
+ const ctrl = new AbortController();
127
+ const stream = new Queue<WatchEvent>([], ctrl.signal);
122
128
 
129
+ // watch resources
130
+ this.#watchFolders(all.paths, ev => stream.add(ev), ctrl.signal);
131
+
132
+ // Watch template files
123
133
  DynamicFileLoader.onLoadEvent((ev) => {
124
134
  const src = RootIndex.getEntry(ev.file);
125
135
  if (src && EmailCompileUtil.isTemplateFile(src.sourceFile)) {
126
136
  stream.add({ ...ev, file: src.sourceFile });
127
137
  }
128
138
  });
139
+
129
140
  for await (const { file, action } of stream) {
130
141
  if (action === 'delete') {
131
142
  continue;
package/src/util.ts CHANGED
@@ -137,11 +137,11 @@ export class EmailCompileUtil {
137
137
  static async inlineImages(html: string, opts: EmailTemplateImageConfig): Promise<string> {
138
138
  const { tokens, finalize } = await this.tokenizeResources(html, this.#HTML_CSS_IMAGE_URLS);
139
139
  const pendingImages: [token: string, ext: string, stream: Readable | Promise<Readable>][] = [];
140
- const resources = new FileResourceProvider(opts.search ?? []);
140
+ const resource = new FileResourceProvider({ includeCommon: true, paths: opts.search ?? [] });
141
141
 
142
142
  for (const [token, src] of tokens) {
143
143
  const ext = path.extname(src);
144
- const stream = await resources.readStream(src);
144
+ const stream = await resource.readStream(src);
145
145
  pendingImages.push([token, ext, /^[.](jpe?g|png)$/.test(ext) ?
146
146
  ImageConverter.optimize(ext === '.png' ? 'png' : 'jpeg', stream) : stream]);
147
147
  }
@@ -183,7 +183,7 @@ export class EmailCompileUtil {
183
183
  styles.push(opts.global);
184
184
  }
185
185
 
186
- const resource = new FileResourceProvider(opts.search ?? []);
186
+ const resource = new FileResourceProvider({ includeCommon: true, paths: opts.search ?? [] });
187
187
  const main = await resource.read('/email/main.scss').then(d => d, () => '');
188
188
 
189
189
  if (main) {
@@ -191,9 +191,7 @@ export class EmailCompileUtil {
191
191
  }
192
192
 
193
193
  if (styles.length) {
194
- const compiled = await this.compileSass(
195
- { data: styles.join('\n') },
196
- [...opts.search ?? []]);
194
+ const compiled = await this.compileSass({ data: styles.join('\n') }, resource.paths);
197
195
 
198
196
  // Remove all unused styles
199
197
  const finalStyles = await this.pruneCss(html, compiled);
@@ -1,5 +1,5 @@
1
1
  import { GlobalEnvConfig } from '@travetto/base';
2
- import { CliCommand } from '@travetto/cli';
2
+ import { CliCommand, CliUtil } from '@travetto/cli';
3
3
  import { RootRegistry } from '@travetto/registry';
4
4
 
5
5
  import { EditorState } from './bin/editor';
@@ -18,6 +18,9 @@ export class EmailEditorCommand {
18
18
  }
19
19
 
20
20
  async main(): Promise<void> {
21
+ if (await CliUtil.runWithRestart(this)) {
22
+ return;
23
+ }
21
24
  await RootRegistry.init();
22
25
  await new EditorState(await EmailCompilationManager.createInstance()).init();
23
26
  }