Skip to content

Commit

Permalink
only attach SSR <head> markers when hydratable: true (#4260)
Browse files Browse the repository at this point in the history
  • Loading branch information
Conduitry authored Jan 14, 2020
1 parent c97e8f8 commit 7494509
Show file tree
Hide file tree
Showing 11 changed files with 48 additions and 24 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Svelte changelog

## Unreleased

* Only attach SSR mode markers to a component's `<head>` elements when compiling with `hydratable: true` ([#4258](https://github.com/sveltejs/svelte/issues/4258))

## 3.17.0

* Remove old `<head>` elements during hydration so they aren't duplicated ([#1607](https://github.com/sveltejs/svelte/issues/1607))
Expand Down
2 changes: 1 addition & 1 deletion site/content/docs/03-run-time.md
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,7 @@ Existing children of `target` are left where they are.

---

The `hydrate` option instructs Svelte to upgrade existing DOM (usually from server-side rendering) rather than creating new elements. It will only work if the component was compiled with the [`hydratable: true` option](docs#svelte_compile).
The `hydrate` option instructs Svelte to upgrade existing DOM (usually from server-side rendering) rather than creating new elements. It will only work if the component was compiled with the [`hydratable: true` option](docs#svelte_compile). Hydration of `<head>` elements only works properly if the server-side rendering code was also compiled with `hydratable: true`, which adds a marker to each element in the `<head>` so that the component knows which elements it's responsible for removing during hydration.

Whereas children of `target` are normally left alone, `hydrate: true` will cause any children to be removed. For that reason, the `anchor` option cannot be used alongside `hydrate: true`.

Expand Down
2 changes: 1 addition & 1 deletion site/content/docs/04-compile-time.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ The following options can be passed to the compiler. None are required:
| `generate` | `"dom"` | If `"dom"`, Svelte emits a JavaScript class for mounting to the DOM. If `"ssr"`, Svelte emits an object with a `render` method suitable for server-side rendering. If `false`, no JavaScript or CSS is returned; just metadata.
| `dev` | `false` | If `true`, causes extra code to be added to components that will perform runtime checks and provide debugging information during development.
| `immutable` | `false` | If `true`, tells the compiler that you promise not to mutate any objects. This allows it to be less conservative about checking whether values have changed.
| `hydratable` | `false` | If `true`, enables the `hydrate: true` runtime option, which allows a component to upgrade existing DOM rather than creating new DOM from scratch.
| `hydratable` | `false` | If `true` when generating DOM code, enables the `hydrate: true` runtime option, which allows a component to upgrade existing DOM rather than creating new DOM from scratch. When generating SSR code, this adds markers to `<head>` elements so that hydration knows which to replace.
| `legacy` | `false` | If `true`, generates code that will work in IE9 and IE10, which don't support things like `element.dataset`.
| `accessors` | `false` | If `true`, getters and setters will be created for the component's props. If `false`, they will only be created for readonly exported values (i.e. those declared with `const`, `class` and `function`). If compiling with `customElement: true` this option defaults to `true`.
| `customElement` | `false` | If `true`, tells the compiler to generate a custom element constructor instead of a regular Svelte component.
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/compile/render_ssr/handlers/Element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export default function(node: Element, renderer: Renderer, options: RenderOption
}
});

if (options.head_id) {
if (options.hydratable && options.head_id) {
renderer.add_string(` data-svelte="${options.head_id}"`);
}

Expand Down
6 changes: 5 additions & 1 deletion src/compiler/compile/render_ssr/handlers/Title.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ import { x } from 'code-red';
export default function(node: Title, renderer: Renderer, options: RenderOptions) {
renderer.push();

renderer.add_string(`<title data-svelte="${options.head_id}">`);
renderer.add_string('<title');
if (options.hydratable && options.head_id) {
renderer.add_string(` data-svelte="${options.head_id}"`);
}
renderer.add_string('>');

renderer.render(node.children, options);

Expand Down
6 changes: 6 additions & 0 deletions test/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ export function tryToReadFile(file) {
}
}

export function cleanRequireCache() {
Object.keys(require.cache)
.filter(x => x.endsWith('.svelte'))
.forEach(file => delete require.cache[file]);
}

const virtualConsole = new jsdom.VirtualConsole();
virtualConsole.sendTo(console);

Expand Down
7 changes: 2 additions & 5 deletions test/runtime/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
showOutput,
loadConfig,
loadSvelte,
cleanRequireCache,
env,
setupHtmlEqual,
mkdirp
Expand Down Expand Up @@ -79,11 +80,7 @@ describe("runtime", () => {
compileOptions.immutable = config.immutable;
compileOptions.accessors = 'accessors' in config ? config.accessors : true;

Object.keys(require.cache)
.filter(x => x.endsWith('.svelte'))
.forEach(file => {
delete require.cache[file];
});
cleanRequireCache();

let mod;
let SvelteComponent;
Expand Down
34 changes: 21 additions & 13 deletions test/server-side-rendering/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
loadSvelte,
setupHtmlEqual,
tryToLoadJson,
cleanRequireCache,
shouldUpdateExpected,
mkdirp
} from "../helpers.js";
Expand All @@ -27,11 +28,6 @@ let compile = null;

describe("ssr", () => {
before(() => {
require("../../register")({
extensions: ['.svelte', '.html'],
sveltePath
});

compile = loadSvelte(true).compile;

return setupHtmlEqual();
Expand All @@ -40,9 +36,11 @@ describe("ssr", () => {
fs.readdirSync(`${__dirname}/samples`).forEach(dir => {
if (dir[0] === ".") return;

const config = loadConfig(`${__dirname}/samples/${dir}/_config.js`);

// add .solo to a sample directory name to only run that test, or
// .show to always show the output. or both
const solo = /\.solo/.test(dir);
const solo = config.solo || /\.solo/.test(dir);
const show = /\.show/.test(dir);

if (solo && process.env.CI) {
Expand All @@ -51,6 +49,18 @@ describe("ssr", () => {

(solo ? it.only : it)(dir, () => {
dir = path.resolve(`${__dirname}/samples`, dir);

cleanRequireCache();

const compileOptions = {
sveltePath,
...config.compileOptions,
generate: 'ssr',
format: 'cjs'
};

require("../../register")(compileOptions);

try {
const Component = require(`${dir}/main.svelte`).default;

Expand Down Expand Up @@ -133,18 +143,16 @@ describe("ssr", () => {
(config.skip ? it.skip : solo ? it.only : it)(dir, () => {
const cwd = path.resolve("test/runtime/samples", dir);

Object.keys(require.cache)
.filter(x => x.endsWith('.svelte'))
.forEach(file => {
delete require.cache[file];
});
cleanRequireCache();

delete global.window;

const compileOptions = Object.assign({ sveltePath }, config.compileOptions, {
const compileOptions = {
sveltePath,
...config.compileOptions,
generate: 'ssr',
format: 'cjs'
});
};

require("../../register")(compileOptions);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default {
compileOptions: {
hydratable: true
}
};
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<title data-svelte="svelte-1csszk6">B</title>
<title>B</title>
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<title data-svelte="svelte-135agoq">a custom title</title>
<title>a custom title</title>

0 comments on commit 7494509

Please sign in to comment.