mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
* Updates the diffing algorithm to use an HTMLFragment node as an abstraction rather than keeping track of startNode and endNode all throughout the diffing algorithm.
* Uses the HTMLFragment for the <${dynamic}> tag and <include> tags to preserve server-rendered content for which the renderBody is not available in the browser.
* Component ids are based on the resulting parent tree (not the owner tree). This means we cannot rely on the ids in the global lookup, so component key/refs are now also stored on the component instance.
* Static node trees are now only auto assigned a key for the top-level node (instead of all nodes).
* Server comment starting markers now have the component's key serialized so the component can be attached to its owner
* Server comment markers no longer have the id on the closing marker, it is stack based.
* Normalize differences between hydration and client-rendering, so post mount the DOM looks the same regardless of whether a component was server or client rendered.
* fix matching up fragments when hydrating by taking components and normalized text nodes into account
* remove wrapping divs in test, should no longer be needed. address hydration issue with alternate fragment matching approach.
* add fragment to dom if there's a parentNode even if no startNode
* add test for mismatched hydration
* don't detach components before moving
* use fragments to preserve renderBody content
* use ___finishFragment as the incomplete fragment marker
* ensure fragments get destroyed properly and dom node key sequences don't continue from previous renders
* use parent/owner terminology in more places, component ids are now parent scoped, key/ref components are attached to their owner for both client + server render, server comment boundaries include the owner and the key in addition to the fully scoped component id, autokeyed dom nodes are attached to their parent, hydration now uses a stack: ids in ending comment nodes not needed, hydration checks to see if a component has been initialized and will attach keys directly to the owner if so
* add mutation guards for text/comment nodes, add mutation guard for input value
* make component-pages test better represent streaming hydration, fix html/head/body hydration in a better/more generic way
* add test for async rendered keyrefs
* add test for repeated mult-level transclusion
* Autokeyed elements are now stored on the parent rather than the owner. User assigned key/refs are still stored on the owner component. Because of this, user assigned keys are now prefixed (with @) to differentiate them from autokeys. This also has the benefit that assigning numeric keys can no longer conflict with the autokeys.
* add re-rendering the intermediate container to one of the new tests
121 lines
4.2 KiB
JavaScript
121 lines
4.2 KiB
JavaScript
"use strict";
|
|
require("../__util__/test-init");
|
|
|
|
var autotest = require("../autotest");
|
|
var createBrowserWithMarko = require("../__util__/create-marko-jsdom-module");
|
|
var ssrTemplate = require("./template.marko");
|
|
var hydrateComponentPath = require.resolve("./template.component-browser.js");
|
|
var browserHelpersPath = require.resolve("../__util__/BrowserHelpers");
|
|
var testTargetHTML = '<div id="testsTarget"></div><div></div>';
|
|
var browser = createBrowserWithMarko(__dirname, testTargetHTML);
|
|
var BrowserHelpers = browser.require(browserHelpersPath);
|
|
|
|
autotest("fixtures", {
|
|
client: runClientTest,
|
|
hydrate: runHydrateTest
|
|
});
|
|
|
|
autotest("fixtures-deprecated", {
|
|
client: runClientTest,
|
|
hydrate: runHydrateTest
|
|
});
|
|
|
|
function runClientTest(fixture) {
|
|
let test = fixture.test;
|
|
let resolve = fixture.resolve;
|
|
let context = fixture.context;
|
|
test(done => {
|
|
let helpers = new BrowserHelpers();
|
|
let testFile = resolve("test.js");
|
|
let testFunc = browser.require(testFile);
|
|
let isAsync = testFunc.length > 1;
|
|
|
|
if (isAsync) {
|
|
testFunc(helpers, cleanupAndFinish);
|
|
} else {
|
|
let err;
|
|
try {
|
|
testFunc(helpers);
|
|
} catch (e) {
|
|
err = e;
|
|
}
|
|
cleanupAndFinish(err);
|
|
}
|
|
|
|
function cleanupAndFinish(err) {
|
|
// Cache components for use in hydrate run.
|
|
if (!err) context.rendered = helpers.rendered;
|
|
helpers.instances.forEach(instance => instance.destroy());
|
|
helpers.targetEl.innerHTML = "";
|
|
done(err);
|
|
}
|
|
});
|
|
}
|
|
|
|
function runHydrateTest(fixture) {
|
|
let test = fixture.test;
|
|
let resolve = fixture.resolve;
|
|
let context = fixture.context;
|
|
test(done => {
|
|
var components = context.rendered;
|
|
if (!components)
|
|
throw new Error("No components rendered by client version of test");
|
|
var $global = components.reduce(
|
|
($g, c) => Object.assign($g, c.$global),
|
|
{}
|
|
);
|
|
ssrTemplate
|
|
.render({ components: components, $global: $global })
|
|
.then(function(html) {
|
|
var browser = createBrowserWithMarko(__dirname, String(html), {
|
|
beforeParse(window, browser) {
|
|
var marko = browser.require("marko/components");
|
|
var legacy = browser.require("marko/legacy-components");
|
|
legacy.load = type =>
|
|
legacy.defineWidget(
|
|
browser.require(
|
|
type.replace(
|
|
/^.*\/components-browser/,
|
|
__dirname
|
|
)
|
|
)
|
|
);
|
|
var rootComponent = browser.require(
|
|
hydrateComponentPath
|
|
);
|
|
marko.register(ssrTemplate.meta.id, rootComponent);
|
|
components.forEach(function(def) {
|
|
Object.keys(def.components).forEach(type => {
|
|
marko.register(
|
|
type,
|
|
browser.require(def.components[type])
|
|
);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
var testFile = resolve("test.js");
|
|
var testFunc = browser.require(testFile);
|
|
var BrowserHelpers = browser.require(browserHelpersPath);
|
|
var helpers = new BrowserHelpers();
|
|
var isAsync = testFunc.length > 1;
|
|
var curInstance = 0;
|
|
|
|
browser.window.$initComponents();
|
|
helpers.isHydrate = true;
|
|
|
|
helpers.mount = function() {
|
|
return browser.window.components[curInstance++];
|
|
};
|
|
|
|
if (isAsync) {
|
|
testFunc(helpers, done);
|
|
} else {
|
|
testFunc(helpers);
|
|
done();
|
|
}
|
|
})
|
|
.catch(done);
|
|
});
|
|
}
|