marko 5.39.2 → 5.39.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 (85) hide show
  1. package/dist/node_modules/@internal/components-registry/index-browser.js +6 -1
  2. package/dist/node_modules/@internal/components-registry/index.js +1 -1
  3. package/dist/node_modules/@internal/components-util/index-browser.js +11 -11
  4. package/dist/node_modules/@internal/components-util/index.js +4 -4
  5. package/dist/node_modules/@internal/create-readable/index-browser.js +1 -1
  6. package/dist/node_modules/@internal/create-readable/index.js +9 -9
  7. package/dist/node_modules/@internal/preserve-tag/index-browser.js +5 -5
  8. package/dist/node_modules/@internal/preserve-tag/index.js +1 -1
  9. package/dist/node_modules/@internal/set-immediate/index-worker.js +1 -1
  10. package/dist/node_modules/@internal/set-immediate/index.js +1 -1
  11. package/dist/runtime/RenderResult.js +3 -3
  12. package/dist/runtime/components/Component.js +66 -66
  13. package/dist/runtime/components/ComponentDef.js +12 -12
  14. package/dist/runtime/components/ComponentsContext.js +3 -3
  15. package/dist/runtime/components/GlobalComponentsContext.js +3 -3
  16. package/dist/runtime/components/KeySequence.js +3 -3
  17. package/dist/runtime/components/ServerComponent.js +1 -1
  18. package/dist/runtime/components/State.js +18 -18
  19. package/dist/runtime/components/attach-detach.js +7 -7
  20. package/dist/runtime/components/dom-data.js +2 -2
  21. package/dist/runtime/components/event-delegation.js +5 -5
  22. package/dist/runtime/components/legacy/defineRenderer-legacy.js +8 -8
  23. package/dist/runtime/components/legacy/dependencies/index.js +7 -7
  24. package/dist/runtime/components/legacy/renderer-legacy.js +21 -21
  25. package/dist/runtime/components/renderer.js +20 -20
  26. package/dist/runtime/components/update-manager.js +3 -3
  27. package/dist/runtime/createOut.js +1 -1
  28. package/dist/runtime/dom-insert.js +5 -5
  29. package/dist/runtime/helpers/_change-case.js +2 -2
  30. package/dist/runtime/helpers/dynamic-tag.js +9 -9
  31. package/dist/runtime/helpers/load-tag-browser.js +59 -0
  32. package/dist/runtime/helpers/load-tag-event-trigger.js +25 -0
  33. package/dist/runtime/helpers/load-tag-idle-trigger.js +15 -0
  34. package/dist/runtime/helpers/load-tag-media-trigger.js +17 -0
  35. package/dist/runtime/helpers/load-tag-race-trigger.js +22 -0
  36. package/dist/runtime/helpers/load-tag-visible-trigger.js +35 -0
  37. package/dist/runtime/helpers/load-tag.js +168 -0
  38. package/dist/runtime/helpers/render-tag.js +1 -1
  39. package/dist/runtime/helpers/serialize-noop.js +1 -1
  40. package/dist/runtime/helpers/style-value.js +1 -1
  41. package/dist/runtime/helpers/tags-compat/runtime-dom.js +16 -16
  42. package/dist/runtime/helpers/tags-compat/runtime-html.js +2 -2
  43. package/dist/runtime/html/AsyncStream.js +20 -20
  44. package/dist/runtime/html/BufferedWriter.js +1 -1
  45. package/dist/runtime/html/helpers/_dynamic-attr.js +2 -2
  46. package/dist/runtime/html/helpers/attr.js +2 -2
  47. package/dist/runtime/html/helpers/data-marko.js +1 -1
  48. package/dist/runtime/html/helpers/escape-xml.js +1 -1
  49. package/dist/runtime/html/index.js +1 -1
  50. package/dist/runtime/renderable.js +2 -2
  51. package/dist/runtime/vdom/AsyncVDOMBuilder.js +83 -83
  52. package/dist/runtime/vdom/VComment.js +7 -7
  53. package/dist/runtime/vdom/VComponent.js +4 -4
  54. package/dist/runtime/vdom/VDocumentFragment.js +6 -6
  55. package/dist/runtime/vdom/VElement.js +35 -35
  56. package/dist/runtime/vdom/VFragment.js +7 -7
  57. package/dist/runtime/vdom/VNode.js +33 -33
  58. package/dist/runtime/vdom/VText.js +8 -8
  59. package/dist/runtime/vdom/helpers/const-element.js +3 -3
  60. package/dist/runtime/vdom/hot-reload.js +8 -8
  61. package/dist/runtime/vdom/index.js +1 -1
  62. package/dist/runtime/vdom/morphdom/fragment.js +4 -4
  63. package/dist/runtime/vdom/morphdom/helpers.js +5 -5
  64. package/dist/runtime/vdom/morphdom/index.js +57 -57
  65. package/dist/runtime/vdom/vdom.js +15 -15
  66. package/dist/translator/index.js +51 -2
  67. package/dist/translator/tag/custom-tag.js +4 -2
  68. package/dist/translator/tag/native-tag[html]/index.js +37 -11
  69. package/dist/translator/util/get-component-files.js +1 -1
  70. package/dist/translator/util/load-import.js +288 -0
  71. package/package.json +3 -3
  72. package/src/node_modules/@internal/components-registry/index-browser.js +5 -0
  73. package/src/runtime/helpers/load-tag-browser.js +59 -0
  74. package/src/runtime/helpers/load-tag-event-trigger.js +25 -0
  75. package/src/runtime/helpers/load-tag-idle-trigger.js +15 -0
  76. package/src/runtime/helpers/load-tag-media-trigger.js +17 -0
  77. package/src/runtime/helpers/load-tag-race-trigger.js +22 -0
  78. package/src/runtime/helpers/load-tag-visible-trigger.js +35 -0
  79. package/src/runtime/helpers/load-tag.js +168 -0
  80. package/src/runtime/helpers/tags-compat/runtime-dom.js +2 -2
  81. package/src/runtime/helpers/tags-compat/runtime-html.js +1 -1
  82. package/src/translator/index.js +50 -1
  83. package/src/translator/tag/custom-tag.js +4 -2
  84. package/src/translator/tag/native-tag[html]/index.js +42 -16
  85. package/src/translator/util/load-import.js +288 -0
@@ -230,7 +230,7 @@ exports.p = function (htmlCompat) {
230
230
  };
231
231
  });
232
232
 
233
- return htmlCompat.registerRenderer;
233
+ return htmlCompat.register;
234
234
  };
235
235
 
236
236
  function concatScripts(a, b) {
@@ -28,9 +28,11 @@ import MarkoTag from "./tag";
28
28
  import MarkoText from "./text";
29
29
  import addDependencies from "./util/add-dependencies";
30
30
  import getComponentFiles from "./util/get-component-files";
31
+ import { analyzeLoadImport } from "./util/load-import";
31
32
  import { optimizeHTMLWrites } from "./util/optimize-html-writes";
32
33
  import { analyzeStaticVDOM } from "./util/optimize-vdom-create";
33
34
 
35
+ export { version } from "../../package.json";
34
36
  export const tagDiscoveryDirs = ["components"];
35
37
  export { optionalTaglibs, default as taglibs } from "./taglib";
36
38
  export { entryBuilder as internalEntryBuilder } from "./util/add-dependencies";
@@ -127,6 +129,9 @@ export const analyze = {
127
129
  relativePath = resolveTagImport(tag, importSource) || importSource;
128
130
  tag.node.extra = tag.node.extra || {};
129
131
  tag.node.extra.tagNameImported = relativePath;
132
+ if (binding.path.parentPath?.node.extra?.loadImport !== undefined) {
133
+ tag.node.extra.tagNameLoad = true;
134
+ }
130
135
  }
131
136
  }
132
137
 
@@ -196,6 +201,7 @@ export const analyze = {
196
201
  exit(path) {
197
202
  const source = path.get("source");
198
203
  const tagEntry = resolveTagImport(source, source.node.value);
204
+ analyzeLoadImport(path, tagEntry);
199
205
 
200
206
  if (tagEntry) {
201
207
  const meta = path.hub.file.metadata.marko;
@@ -230,7 +236,50 @@ export const translate = {
230
236
  hub: { file },
231
237
  } = path;
232
238
 
233
- if (file.markoOpts.output === "hydrate") {
239
+ if (file.markoOpts.entry && !file.markoOpts.linkAssets) {
240
+ throw path.buildCodeFrameError(
241
+ 'The "entry" option requires the `linkAssets` compiler option to be configured.',
242
+ );
243
+ }
244
+
245
+ if (file.markoOpts.output === "html" && file.markoOpts.entry === "page") {
246
+ const { linkAssets } = file.markoOpts;
247
+ const templateId = file.metadata.marko.id;
248
+ const relPath = resolveRelativePath(file, file.opts.filename);
249
+ linkAssets.onAsset("page", file.opts.filename, templateId);
250
+ path.node.body = [
251
+ t.importDeclaration(
252
+ [t.importSpecifier(t.identifier("flush"), t.identifier("flush"))],
253
+ t.stringLiteral(linkAssets.runtime),
254
+ ),
255
+ t.importDeclaration(
256
+ [t.importDefaultSpecifier(t.identifier("template"))],
257
+ t.stringLiteral(relPath),
258
+ ),
259
+ t.importDeclaration(
260
+ [
261
+ t.importSpecifier(
262
+ t.identifier("withPageAssets"),
263
+ t.identifier("withPageAssets"),
264
+ ),
265
+ ],
266
+ t.stringLiteral("marko/src/runtime/helpers/load-tag.js"),
267
+ ),
268
+ t.exportAllDeclaration(t.stringLiteral(relPath)),
269
+ t.exportDefaultDeclaration(
270
+ t.callExpression(t.identifier("withPageAssets"), [
271
+ t.stringLiteral(templateId),
272
+ t.identifier("template"),
273
+ t.identifier("flush"),
274
+ ]),
275
+ ),
276
+ ];
277
+ path.skip();
278
+ return;
279
+ } else if (
280
+ (file.markoOpts.output === "dom" && file.markoOpts.entry) ||
281
+ file.markoOpts.output === "hydrate"
282
+ ) {
234
283
  addDependencies(file, true);
235
284
  return;
236
285
  } else if (
@@ -3,11 +3,11 @@ import {
3
3
  assertNoArgs,
4
4
  getTagDef,
5
5
  importDefault,
6
- loadFileForTag,
7
6
  resolveRelativePath,
8
7
  resolveTagImport,
9
8
  } from "@marko/compiler/babel-utils";
10
9
 
10
+ import { translateLoadTag } from "../util/load-import";
11
11
  import withPreviousLocation from "../util/with-previous-location";
12
12
  import dynamicTag from "./dynamic-tag";
13
13
  import nativeTag from "./native-tag";
@@ -53,7 +53,9 @@ export default function (path, isNullable) {
53
53
  if (binding && !binding.identifier.loc) binding = null;
54
54
 
55
55
  if (relativePath) {
56
- tagIdentifier = importDefault(file, relativePath, tagName);
56
+ tagIdentifier = node.extra?.tagNameLoad
57
+ ? translateLoadTag(path, tagName, relativePath)
58
+ : importDefault(file, relativePath, tagName);
57
59
  } else if (binding) {
58
60
  path.set("name", t.identifier(tagName));
59
61
  return dynamicTag(path);
@@ -2,6 +2,7 @@ import { types as t } from "@marko/compiler";
2
2
  import {
3
3
  getTagDef,
4
4
  importDefault,
5
+ importNamed,
5
6
  normalizeTemplateString,
6
7
  } from "@marko/compiler/babel-utils";
7
8
  import { resolve } from "path";
@@ -205,22 +206,47 @@ export default function (path, isNullable) {
205
206
  );
206
207
  }
207
208
 
208
- path.replaceWithMultiple(
209
- [writeStartNode]
210
- .concat(
211
- needsIIFE
212
- ? t.expressionStatement(
213
- t.callExpression(
214
- t.arrowFunctionExpression([], t.blockStatement(body)),
215
- [],
216
- ),
217
- )
218
- : needsBlock
219
- ? t.blockStatement(body)
220
- : body,
221
- )
222
- .concat(writeEndNode),
223
- );
209
+ const nodes = [writeStartNode];
210
+
211
+ if (needsIIFE) {
212
+ nodes.push(
213
+ t.expressionStatement(
214
+ t.callExpression(
215
+ t.arrowFunctionExpression([], t.blockStatement(body)),
216
+ [],
217
+ ),
218
+ ),
219
+ );
220
+ } else if (needsBlock) {
221
+ nodes.push(t.blockStatement(body));
222
+ } else {
223
+ for (const node of body) {
224
+ nodes.push(node);
225
+ }
226
+ }
227
+
228
+ if (
229
+ t.isStringLiteral(name) &&
230
+ name.value === "head" &&
231
+ file.markoOpts.linkAssets
232
+ ) {
233
+ nodes.push(
234
+ t.expressionStatement(
235
+ t.callExpression(
236
+ importNamed(
237
+ file,
238
+ "marko/src/runtime/helpers/load-tag.js",
239
+ "flushHead",
240
+ "marko_flush_head",
241
+ ),
242
+ [t.identifier("out")],
243
+ ),
244
+ ),
245
+ );
246
+ }
247
+
248
+ nodes.push(writeEndNode);
249
+ path.replaceWithMultiple(nodes);
224
250
  }
225
251
 
226
252
  function isPreserved(path) {
@@ -0,0 +1,288 @@
1
+ import { types as t } from "@marko/compiler";
2
+ import {
3
+ importDefault,
4
+ importNamed,
5
+ loadFileForTag,
6
+ } from "@marko/compiler/babel-utils";
7
+
8
+ const triggerRegExp = /\s*([\w-]+)\s*([^?|]+?)?\s*(?:\?([^|]*?))?\s*(?:\||$)/g;
9
+ const loadTagsByFile = new WeakMap();
10
+
11
+ export function analyzeLoadImport(importDecl, tagEntry) {
12
+ const loadAttrValuePath = importDecl
13
+ .get("attributes")
14
+ .find(
15
+ (p) =>
16
+ (p.node.key.type === "Identifier"
17
+ ? p.node.key.name
18
+ : p.node.key.value) === "load",
19
+ )
20
+ ?.get("value");
21
+
22
+ if (!loadAttrValuePath) return;
23
+
24
+ if (!tagEntry) {
25
+ throw importDecl.buildCodeFrameError(
26
+ "Unable to resolve marko file for load import.",
27
+ );
28
+ }
29
+
30
+ if ((importDecl.node.importKind || "value") !== "value") {
31
+ throw importDecl.buildCodeFrameError("Invalid load import.");
32
+ }
33
+
34
+ for (const specifier of importDecl.get("specifiers")) {
35
+ if (!t.isImportDefaultSpecifier(specifier.node)) {
36
+ throw specifier.buildCodeFrameError(
37
+ "Invalid load import, only a default specifier is allowed.",
38
+ );
39
+ }
40
+ }
41
+
42
+ const { markoOpts } = importDecl.hub.file;
43
+ if (!markoOpts.linkAssets) {
44
+ throw importDecl.buildCodeFrameError(
45
+ "The `load` import attribute requires the `linkAssets` compiler option to be configured.",
46
+ );
47
+ }
48
+
49
+ (importDecl.node.extra ??= {}).loadImport =
50
+ getLoadImportConfig(loadAttrValuePath);
51
+ }
52
+
53
+ export function translateLoadTag(path, tagName, relativePath) {
54
+ const { file } = path.hub;
55
+ const { markoOpts } = file;
56
+
57
+ const loadTagFn =
58
+ markoOpts.output === "dom"
59
+ ? importDefault(
60
+ file,
61
+ "marko/src/runtime/helpers/load-tag-browser.js",
62
+ "marko_load_tag",
63
+ )
64
+ : importNamed(
65
+ file,
66
+ "marko/src/runtime/helpers/load-tag.js",
67
+ "withLoadAssets",
68
+ "marko_load_tag",
69
+ );
70
+
71
+ const importBinding = path.scope.getBinding(tagName);
72
+ const importDecl = importBinding?.path?.parentPath?.isImportDeclaration()
73
+ ? importBinding.path.parentPath
74
+ : null;
75
+ const loadImport = importDecl?.node?.extra?.loadImport;
76
+ const triggers =
77
+ loadImport && !loadImport.render && loadImport.triggers.length
78
+ ? loadImport.triggers
79
+ : null;
80
+
81
+ let loadTags = loadTagsByFile.get(file);
82
+ if (!loadTags) loadTagsByFile.set(file, (loadTags = new Map()));
83
+ if (loadTags.has(relativePath)) {
84
+ return loadTags.get(relativePath);
85
+ }
86
+
87
+ const loadId = file.path.scope.generateUidIdentifier(`marko_load_${tagName}`);
88
+ loadTags.set(relativePath, loadId);
89
+
90
+ let loadArgs;
91
+ if (markoOpts.output === "dom") {
92
+ if (importDecl) {
93
+ // The lazy wrapper pretends to be the template, so every reference
94
+ // not already translated as a tag uses it.
95
+ for (const ref of importBinding.referencePaths) {
96
+ if (!(t.isMarkoTag(ref.parent) && ref.parent.extra?.tagNameLoad)) {
97
+ ref.replaceWith(t.cloneNode(loadId));
98
+ }
99
+ }
100
+ importDecl.remove();
101
+ }
102
+ const childFile = loadFileForTag(path);
103
+ loadArgs = [
104
+ t.stringLiteral(childFile.metadata.marko.id),
105
+ t.arrowFunctionExpression(
106
+ [],
107
+ t.callExpression(t.import(), [t.stringLiteral(relativePath)]),
108
+ ),
109
+ ];
110
+ if (triggers) loadArgs.push(buildDomTrigger(file, triggers));
111
+ } else {
112
+ const { linkAssets } = markoOpts;
113
+ const childFile = loadFileForTag(path);
114
+ linkAssets.onAsset(
115
+ "load",
116
+ childFile.opts.filename,
117
+ childFile.metadata.marko.id,
118
+ );
119
+ loadArgs = [
120
+ t.stringLiteral(childFile.metadata.marko.id),
121
+ t.identifier(tagName),
122
+ ];
123
+ if (triggers) loadArgs.push(t.valueToNode(triggers));
124
+ }
125
+
126
+ file.path.unshiftContainer("body", [
127
+ t.variableDeclaration("const", [
128
+ t.variableDeclarator(loadId, t.callExpression(loadTagFn, loadArgs)),
129
+ ]),
130
+ ]);
131
+
132
+ return loadId;
133
+ }
134
+
135
+ function getLoadImportConfig(attrValue) {
136
+ const raw = attrValue.node.value;
137
+
138
+ if (raw === "render") return { render: true };
139
+
140
+ const triggers = [];
141
+ for (const match of raw.matchAll(triggerRegExp)) {
142
+ const type = parseTriggerType(match[1]);
143
+ const selector = match[2];
144
+ const query = match[3];
145
+
146
+ if (!type) {
147
+ throw attrValue.buildCodeFrameError(
148
+ `Unknown trigger type "${match[1]}". Supported triggers are "visible", "idle", "media", and "on*".`,
149
+ );
150
+ }
151
+ if (type === "render") {
152
+ throw attrValue.buildCodeFrameError(
153
+ 'The "render" trigger must be used alone.',
154
+ );
155
+ }
156
+ if (type === "idle") {
157
+ if (selector) {
158
+ throw attrValue.buildCodeFrameError(
159
+ `Selector is not supported for the "idle" trigger.`,
160
+ );
161
+ }
162
+ } else if (!selector) {
163
+ throw attrValue.buildCodeFrameError(
164
+ type === "media"
165
+ ? `A media query is required for the "media" trigger. (e.g. "media(max-width:768px)")`
166
+ : `A selector is required for the "${type}" trigger. (e.g. "${type}.my-element")`,
167
+ );
168
+ }
169
+
170
+ const trigger = selector ? { type, selector } : { type };
171
+
172
+ if (query) {
173
+ const params = new URLSearchParams(query);
174
+ switch (type) {
175
+ case "visible": {
176
+ let rootMargin;
177
+ for (const [key, value] of params) {
178
+ if (key !== "rootMargin") {
179
+ throw attrValue.buildCodeFrameError(
180
+ `Unknown param "${key}" for the "visible" trigger. Supported params: "rootMargin".`,
181
+ );
182
+ }
183
+ rootMargin = value;
184
+ }
185
+ if (rootMargin) trigger.options = { rootMargin };
186
+ break;
187
+ }
188
+ case "idle": {
189
+ let timeout;
190
+ for (const [key, value] of params) {
191
+ if (key !== "timeout") {
192
+ throw attrValue.buildCodeFrameError(
193
+ `Unknown param "${key}" for the "idle" trigger. Supported params: "timeout".`,
194
+ );
195
+ }
196
+ timeout = Number(value);
197
+ }
198
+ if (timeout) trigger.options = { timeout };
199
+ break;
200
+ }
201
+ default:
202
+ throw attrValue.buildCodeFrameError(
203
+ `Params are not supported for the "${type}" trigger.`,
204
+ );
205
+ }
206
+ }
207
+
208
+ triggers.push(trigger);
209
+ }
210
+
211
+ if (!triggers.length) {
212
+ throw attrValue.buildCodeFrameError(
213
+ 'The "load" attribute requires "render" or at least one trigger (e.g. "visible.my-element").',
214
+ );
215
+ }
216
+
217
+ return { render: false, triggers };
218
+ }
219
+
220
+ function buildDomTrigger(file, triggers) {
221
+ const triggerExprs = triggers.map((trigger) => {
222
+ switch (trigger.type) {
223
+ case "visible": {
224
+ const fn = importDefault(
225
+ file,
226
+ "marko/src/runtime/helpers/load-tag-visible-trigger.js",
227
+ "marko_visible_trigger",
228
+ );
229
+ const args = [t.stringLiteral(trigger.selector)];
230
+ if (trigger.options) args.push(t.valueToNode(trigger.options));
231
+ return t.callExpression(fn, args);
232
+ }
233
+ case "idle": {
234
+ const fn = importDefault(
235
+ file,
236
+ "marko/src/runtime/helpers/load-tag-idle-trigger.js",
237
+ "marko_idle_trigger",
238
+ );
239
+ return t.callExpression(
240
+ fn,
241
+ trigger.options ? [t.valueToNode(trigger.options)] : [],
242
+ );
243
+ }
244
+ case "media": {
245
+ const fn = importDefault(
246
+ file,
247
+ "marko/src/runtime/helpers/load-tag-media-trigger.js",
248
+ "marko_media_trigger",
249
+ );
250
+ return t.callExpression(fn, [t.stringLiteral(trigger.selector)]);
251
+ }
252
+ default: {
253
+ const fn = importDefault(
254
+ file,
255
+ "marko/src/runtime/helpers/load-tag-event-trigger.js",
256
+ "marko_event_trigger",
257
+ );
258
+ return t.callExpression(fn, [
259
+ t.stringLiteral(trigger.type.slice("on-".length)),
260
+ t.stringLiteral(trigger.selector),
261
+ ]);
262
+ }
263
+ }
264
+ });
265
+
266
+ if (triggerExprs.length === 1) return triggerExprs[0];
267
+
268
+ const raceFn = importDefault(
269
+ file,
270
+ "marko/src/runtime/helpers/load-tag-race-trigger.js",
271
+ "marko_race_trigger",
272
+ );
273
+ return t.callExpression(raceFn, triggerExprs);
274
+ }
275
+
276
+ function parseTriggerType(type) {
277
+ switch (type) {
278
+ case "idle":
279
+ case "media":
280
+ case "render":
281
+ case "visible":
282
+ return type;
283
+ default:
284
+ return /^on[A-Z-]/.test(type)
285
+ ? `on-${type[2] === "-" ? type.slice(3) : type.slice(2).toLowerCase()}`
286
+ : undefined;
287
+ }
288
+ }