marko 5.39.11 → 5.39.13

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.
@@ -40,8 +40,13 @@ existingComponentDef)
40
40
  }
41
41
 
42
42
  if (componentsContext.w_) {
43
+ var forceBoundary = componentsContext.w_;
43
44
  componentsContext.w_ = false;
44
- isSplitComponent = false;
45
+ if (forceBoundary === "preserve") {
46
+ isSplitComponent = true;
47
+ } else {
48
+ isSplitComponent = false;
49
+ }
45
50
  } else if (isImplicitComponent === true) {
46
51
  // We don't mount implicit components rendered on the server
47
52
  // unless the implicit component is nested within a UI component
@@ -137,9 +137,24 @@ exports.p = function (domCompat) {
137
137
  let host = domCompat.getStartNode(scope);
138
138
  let rootNode = host.fragment;
139
139
  if (!rootNode) {
140
+ // An inert/server only class child has no client instance in
141
+ // ___componentLookup; once it has been re-rendered once it is tracked on
142
+ // the scope instead.
140
143
  const component = scope.bt_ =
141
- _n_[scope.m5c];
142
- rootNode = component._G_;
144
+ _n_[scope.m5c] || scope.bt_;
145
+ if (component) {
146
+ rootNode = component._G_;
147
+ } else {
148
+ // First re-render of such a child: wrap its existing DOM (between the
149
+ // scope's start and end nodes) in a fragment so the new render can be
150
+ // morphed in place. The morph + ___initComponents below registers a
151
+ // component that the branch above reuses for subsequent re-renders.
152
+ rootNode = _m_(
153
+ host.nextSibling,
154
+ domCompat.getEndNode(scope),
155
+ host.parentNode
156
+ );
157
+ }
143
158
  host = rootNode.startNode;
144
159
  domCompat.setScopeNodes(host, rootNode.startNode, rootNode.endNode);
145
160
  }
@@ -8,9 +8,11 @@ const {
8
8
  const createRenderer = require("../../components/renderer");
9
9
  const defaultCreateOut = require("../../createOut");
10
10
  const dynamicTag5 = require("../dynamic-tag");
11
+ const PRESERVE_BOUNDARY = "preserve";
11
12
 
12
13
  exports.p = function (htmlCompat) {
13
14
  const writersByGlobal = new WeakMap();
15
+ const boundaryModeByRenderer = new WeakMap();
14
16
  const isMarko6 = (fn) => typeof fn !== "function" || htmlCompat.isTagsAPI(fn);
15
17
  const isMarko5 = (fn) =>
16
18
  typeof fn !== "function" || !htmlCompat.isTagsAPI(fn);
@@ -172,6 +174,7 @@ exports.p = function (htmlCompat) {
172
174
  const state = htmlCompat.ensureState($global);
173
175
  const out = defaultCreateOut($global);
174
176
  const branchId = htmlCompat.nextScopeId();
177
+ let forceBoundary = boundaryModeByRenderer.get(tag);
175
178
 
176
179
  if (renderer5) {
177
180
  const componentsContext = T_(out);
@@ -187,6 +190,7 @@ exports.p = function (htmlCompat) {
187
190
  key[2] === "-" ? key.slice(3) : key.slice(2).toLowerCase(),
188
191
  value]
189
192
  );
193
+ forceBoundary = true;
190
194
  value.toJSON = htmlCompat.toJSON(state);
191
195
  }
192
196
  } else {
@@ -194,11 +198,11 @@ exports.p = function (htmlCompat) {
194
198
  }
195
199
  }
196
200
 
197
- componentsContext.w_ = true;
201
+ componentsContext.w_ = forceBoundary;
198
202
  renderer5(input, out);
199
203
 
200
204
  const componentDef = componentsContext.b_[0];
201
- if (componentDef) {
205
+ if (componentDef && forceBoundary) {
202
206
  const rawInput = componentDef.s_.P_;
203
207
  const { toJSON: _, ...serializeInput } = rawInput;
204
208
  componentDef.s_.X_ = customEvents;
@@ -230,7 +234,10 @@ exports.p = function (htmlCompat) {
230
234
  };
231
235
  });
232
236
 
233
- return htmlCompat.register;
237
+ return function register(id, renderer, boundaryMode) {
238
+ boundaryModeByRenderer.set(renderer, boundaryMode || true);
239
+ return htmlCompat.register(id, renderer);
240
+ };
234
241
  };
235
242
 
236
243
  function concatScripts(a, b) {
@@ -33,9 +33,12 @@ var _loadImport = require("./util/load-import");
33
33
  var _optimizeHtmlWrites = require("./util/optimize-html-writes");
34
34
  var _optimizeVdomCreate = require("./util/optimize-vdom-create");
35
35
 
36
+
37
+
38
+
36
39
  var _package2 = require("../../package.json");exports.version = _package2.version;
37
40
 
38
- var _taglib = _interopRequireWildcard(require("./taglib"));exports.optionalTaglibs = _taglib.optionalTaglibs;exports.taglibs = _taglib.default;function _interopRequireWildcard(e, t) {if ("function" == typeof WeakMap) var r = new WeakMap(),n = new WeakMap();return (_interopRequireWildcard = function (e, t) {if (!t && e && e.__esModule) return e;var o,i,f = { __proto__: null, default: e };if (null === e || "object" != typeof e && "function" != typeof e) return f;if (o = t ? n : r) {if (o.has(e)) return o.get(e);o.set(e, f);}for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]);return f;})(e, t);}function _interopRequireDefault(e) {return e && e.__esModule ? e : { default: e };}const tagDiscoveryDirs = exports.tagDiscoveryDirs = ["components"];
41
+ var _taglib = _interopRequireWildcard(require("./taglib"));exports.optionalTaglibs = _taglib.optionalTaglibs;exports.taglibs = _taglib.default;function _interopRequireWildcard(e, t) {if ("function" == typeof WeakMap) var r = new WeakMap(),n = new WeakMap();return (_interopRequireWildcard = function (e, t) {if (!t && e && e.__esModule) return e;var o,i,f = { __proto__: null, default: e };if (null === e || "object" != typeof e && "function" != typeof e) return f;if (o = t ? n : r) {if (o.has(e)) return o.get(e);o.set(e, f);}for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]);return f;})(e, t);}function _interopRequireDefault(e) {return e && e.__esModule ? e : { default: e };}const CLASS_HYDRATION_SELF = "self";const CLASS_HYDRATION_DESCENDANT = "descendant";const tagDiscoveryDirs = exports.tagDiscoveryDirs = ["components"];
39
42
 
40
43
 
41
44
  const preferAPI = exports.preferAPI = "class";
@@ -90,6 +93,7 @@ const analyze = exports.analyze = {
90
93
  (0, _babelUtils.resolveRelativePath)(file, filename) :
91
94
  filename
92
95
  );
96
+ meta.classHydration = getClassHydrationMode(file);
93
97
  }
94
98
  },
95
99
  MarkoTag(tag) {
@@ -696,4 +700,32 @@ function resolveRelativeTagEntry(file, tagDef) {
696
700
  // TODO: support transform and other entries.
697
701
  const entry = tagDef.template || tagDef.renderer;
698
702
  return entry && (0, _babelUtils.resolveRelativePath)(file, entry);
703
+ }
704
+
705
+ function getClassHydrationMode(file, visited = new Set()) {
706
+ const fileName = file.opts.filename;
707
+ const meta = file.metadata.marko;
708
+
709
+ if (Object.hasOwn(meta, "classHydration")) {
710
+ return meta.classHydration;
711
+ }
712
+
713
+ if (visited.has(fileName)) {
714
+ return;
715
+ }
716
+
717
+ visited.add(fileName);
718
+
719
+ if (meta.component) {
720
+ return meta.classHydration = CLASS_HYDRATION_SELF;
721
+ }
722
+
723
+ for (const tag of meta.tags) {
724
+ if (tag.endsWith(".marko")) {
725
+ const childFile = (0, _babelUtils.loadFileForImport)(file, tag);
726
+ if (childFile && getClassHydrationMode(childFile, visited)) {
727
+ return meta.classHydration = CLASS_HYDRATION_DESCENDANT;
728
+ }
729
+ }
730
+ }
699
731
  }
@@ -165,16 +165,18 @@ const entryBuilder = exports.entryBuilder = {
165
165
  }
166
166
  }
167
167
 
168
- for (const tag of fileMeta.tags) {
169
- if (tag.endsWith(".marko")) {
170
- visitChild(tag);
171
- } else if (/^@lasso\/marko-taglib\//.test(tag)) {
172
- state.hasComponents = true;
173
- } else {
174
- const importedTemplates = tryGetTemplateImports(file, tag);
175
- if (importedTemplates) {
176
- for (const templateFile of importedTemplates) {
177
- visitChild(templateFile);
168
+ if (fileMeta.classHydration) {
169
+ for (const tag of fileMeta.tags) {
170
+ if (tag.endsWith(".marko")) {
171
+ visitChild(tag);
172
+ } else if (/^@lasso\/marko-taglib\//.test(tag)) {
173
+ state.hasComponents = true;
174
+ } else {
175
+ const importedTemplates = tryGetTemplateImports(file, tag);
176
+ if (importedTemplates) {
177
+ for (const templateFile of importedTemplates) {
178
+ visitChild(templateFile);
179
+ }
178
180
  }
179
181
  }
180
182
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "marko",
3
- "version": "5.39.11",
3
+ "version": "5.39.13",
4
4
  "private": false,
5
5
  "description": "UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.",
6
6
  "keywords": [
@@ -71,7 +71,7 @@
71
71
  },
72
72
  "dependencies": {
73
73
  "@marko/compiler": "^5.39.66",
74
- "@marko/runtime-tags": "^6.1.17",
74
+ "@marko/runtime-tags": "^6.1.19",
75
75
  "app-module-path": "^2.2.0",
76
76
  "argly": "^1.2.0",
77
77
  "browser-refresh-client": "1.1.4",
@@ -40,8 +40,13 @@ module.exports = function beginComponent(
40
40
  }
41
41
 
42
42
  if (componentsContext.___forceBoundary) {
43
+ var forceBoundary = componentsContext.___forceBoundary;
43
44
  componentsContext.___forceBoundary = false;
44
- isSplitComponent = false;
45
+ if (forceBoundary === "preserve") {
46
+ isSplitComponent = true;
47
+ } else {
48
+ isSplitComponent = false;
49
+ }
45
50
  } else if (isImplicitComponent === true) {
46
51
  // We don't mount implicit components rendered on the server
47
52
  // unless the implicit component is nested within a UI component
@@ -137,9 +137,24 @@ exports.p = function (domCompat) {
137
137
  let host = domCompat.getStartNode(scope);
138
138
  let rootNode = host.fragment;
139
139
  if (!rootNode) {
140
+ // An inert/server only class child has no client instance in
141
+ // ___componentLookup; once it has been re-rendered once it is tracked on
142
+ // the scope instead.
140
143
  const component = (scope.___marko5Component =
141
- ___componentLookup[scope.m5c]);
142
- rootNode = component.___rootNode;
144
+ ___componentLookup[scope.m5c] || scope.___marko5Component);
145
+ if (component) {
146
+ rootNode = component.___rootNode;
147
+ } else {
148
+ // First re-render of such a child: wrap its existing DOM (between the
149
+ // scope's start and end nodes) in a fragment so the new render can be
150
+ // morphed in place. The morph + ___initComponents below registers a
151
+ // component that the branch above reuses for subsequent re-renders.
152
+ rootNode = ___createFragmentNode(
153
+ host.nextSibling,
154
+ domCompat.getEndNode(scope),
155
+ host.parentNode,
156
+ );
157
+ }
143
158
  host = rootNode.startNode;
144
159
  domCompat.setScopeNodes(host, rootNode.startNode, rootNode.endNode);
145
160
  }
@@ -8,9 +8,11 @@ const {
8
8
  const createRenderer = require("../../components/renderer");
9
9
  const defaultCreateOut = require("../../createOut");
10
10
  const dynamicTag5 = require("../dynamic-tag");
11
+ const PRESERVE_BOUNDARY = "preserve";
11
12
 
12
13
  exports.p = function (htmlCompat) {
13
14
  const writersByGlobal = new WeakMap();
15
+ const boundaryModeByRenderer = new WeakMap();
14
16
  const isMarko6 = (fn) => typeof fn !== "function" || htmlCompat.isTagsAPI(fn);
15
17
  const isMarko5 = (fn) =>
16
18
  typeof fn !== "function" || !htmlCompat.isTagsAPI(fn);
@@ -172,6 +174,7 @@ exports.p = function (htmlCompat) {
172
174
  const state = htmlCompat.ensureState($global);
173
175
  const out = defaultCreateOut($global);
174
176
  const branchId = htmlCompat.nextScopeId();
177
+ let forceBoundary = boundaryModeByRenderer.get(tag);
175
178
 
176
179
  if (renderer5) {
177
180
  const componentsContext = ___getComponentsContext(out);
@@ -187,6 +190,7 @@ exports.p = function (htmlCompat) {
187
190
  key[2] === "-" ? key.slice(3) : key.slice(2).toLowerCase(),
188
191
  value,
189
192
  ]);
193
+ forceBoundary = true;
190
194
  value.toJSON = htmlCompat.toJSON(state);
191
195
  }
192
196
  } else {
@@ -194,11 +198,11 @@ exports.p = function (htmlCompat) {
194
198
  }
195
199
  }
196
200
 
197
- componentsContext.___forceBoundary = true;
201
+ componentsContext.___forceBoundary = forceBoundary;
198
202
  renderer5(input, out);
199
203
 
200
204
  const componentDef = componentsContext.___components[0];
201
- if (componentDef) {
205
+ if (componentDef && forceBoundary) {
202
206
  const rawInput = componentDef.___component.___input;
203
207
  const { toJSON: _, ...serializeInput } = rawInput;
204
208
  componentDef.___component.___customEvents = customEvents;
@@ -230,7 +234,10 @@ exports.p = function (htmlCompat) {
230
234
  };
231
235
  });
232
236
 
233
- return htmlCompat.register;
237
+ return function register(id, renderer, boundaryMode) {
238
+ boundaryModeByRenderer.set(renderer, boundaryMode || true);
239
+ return htmlCompat.register(id, renderer);
240
+ };
234
241
  };
235
242
 
236
243
  function concatScripts(a, b) {
@@ -33,6 +33,9 @@ import { analyzeLoadImport } from "./util/load-import";
33
33
  import { optimizeHTMLWrites } from "./util/optimize-html-writes";
34
34
  import { analyzeStaticVDOM } from "./util/optimize-vdom-create";
35
35
 
36
+ const CLASS_HYDRATION_SELF = "self";
37
+ const CLASS_HYDRATION_DESCENDANT = "descendant";
38
+
36
39
  export { version } from "../../package.json";
37
40
  export const tagDiscoveryDirs = ["components"];
38
41
  export { optionalTaglibs, default as taglibs } from "./taglib";
@@ -90,6 +93,7 @@ export const analyze = {
90
93
  ? resolveRelativePath(file, filename)
91
94
  : filename,
92
95
  );
96
+ meta.classHydration = getClassHydrationMode(file);
93
97
  },
94
98
  },
95
99
  MarkoTag(tag) {
@@ -697,3 +701,31 @@ function resolveRelativeTagEntry(file, tagDef) {
697
701
  const entry = tagDef.template || tagDef.renderer;
698
702
  return entry && resolveRelativePath(file, entry);
699
703
  }
704
+
705
+ function getClassHydrationMode(file, visited = new Set()) {
706
+ const fileName = file.opts.filename;
707
+ const meta = file.metadata.marko;
708
+
709
+ if (Object.hasOwn(meta, "classHydration")) {
710
+ return meta.classHydration;
711
+ }
712
+
713
+ if (visited.has(fileName)) {
714
+ return;
715
+ }
716
+
717
+ visited.add(fileName);
718
+
719
+ if (meta.component) {
720
+ return (meta.classHydration = CLASS_HYDRATION_SELF);
721
+ }
722
+
723
+ for (const tag of meta.tags) {
724
+ if (tag.endsWith(".marko")) {
725
+ const childFile = loadFileForImport(file, tag);
726
+ if (childFile && getClassHydrationMode(childFile, visited)) {
727
+ return (meta.classHydration = CLASS_HYDRATION_DESCENDANT);
728
+ }
729
+ }
730
+ }
731
+ }
@@ -165,16 +165,18 @@ export const entryBuilder = {
165
165
  }
166
166
  }
167
167
 
168
- for (const tag of fileMeta.tags) {
169
- if (tag.endsWith(".marko")) {
170
- visitChild(tag);
171
- } else if (/^@lasso\/marko-taglib\//.test(tag)) {
172
- state.hasComponents = true;
173
- } else {
174
- const importedTemplates = tryGetTemplateImports(file, tag);
175
- if (importedTemplates) {
176
- for (const templateFile of importedTemplates) {
177
- visitChild(templateFile);
168
+ if (fileMeta.classHydration) {
169
+ for (const tag of fileMeta.tags) {
170
+ if (tag.endsWith(".marko")) {
171
+ visitChild(tag);
172
+ } else if (/^@lasso\/marko-taglib\//.test(tag)) {
173
+ state.hasComponents = true;
174
+ } else {
175
+ const importedTemplates = tryGetTemplateImports(file, tag);
176
+ if (importedTemplates) {
177
+ for (const templateFile of importedTemplates) {
178
+ visitChild(templateFile);
179
+ }
178
180
  }
179
181
  }
180
182
  }