Skip to content

[breaking] add embedded option, turned off by default #7969

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Dec 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/popular-crabs-shop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

[breaking] add embedded option, turned off by default
1 change: 1 addition & 0 deletions packages/kit/src/core/config/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const get_defaults = (prefix = '') => ({
checkOrigin: true
},
endpointExtensions: undefined,
embedded: false,
env: {
dir: process.cwd(),
publicPrefix: 'PUBLIC_'
Expand Down
2 changes: 2 additions & 0 deletions packages/kit/src/core/config/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ const options = object(
checkOrigin: boolean(true)
}),

embedded: boolean(false),

// TODO: remove this for the 1.0 release
endpointExtensions: error(
(keypath) => `${keypath} has been renamed to config.kit.moduleExtensions`
Expand Down
1 change: 1 addition & 0 deletions packages/kit/src/exports/vite/build/build_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class Server {
check_origin: ${s(config.kit.csrf.checkOrigin)},
},
dev: false,
embedded: ${config.kit.embedded},
handle_error: (error, event) => {
return this.options.hooks.handleError({
error,
Expand Down
3 changes: 2 additions & 1 deletion packages/kit/src/exports/vite/build/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ export function get_default_build_config({ config, input, ssr, outDir }) {
__SVELTEKIT_APP_VERSION_FILE__: JSON.stringify(`${config.kit.appDir}/version.json`),
__SVELTEKIT_APP_VERSION_POLL_INTERVAL__: JSON.stringify(config.kit.version.pollInterval),
__SVELTEKIT_BROWSER__: ssr ? 'false' : 'true',
__SVELTEKIT_DEV__: 'false'
__SVELTEKIT_DEV__: 'false',
__SVELTEKIT_EMBEDDED__: config.kit.embedded ? 'true' : 'false'
},
publicDir: ssr ? false : config.kit.files.assets,
resolve: {
Expand Down
1 change: 1 addition & 0 deletions packages/kit/src/exports/vite/dev/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ export async function dev(vite, vite_config, svelte_config) {
check_origin: svelte_config.kit.csrf.checkOrigin
},
dev: true,
embedded: svelte_config.kit.embedded,
handle_error: async (error, event) => {
const error_object = await hooks.handleError({
error: new Proxy(error, {
Expand Down
3 changes: 2 additions & 1 deletion packages/kit/src/exports/vite/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,8 @@ function kit() {
define: {
__SVELTEKIT_APP_VERSION_POLL_INTERVAL__: '0',
__SVELTEKIT_BROWSER__: config_env.ssrBuild ? 'false' : 'true',
__SVELTEKIT_DEV__: 'true'
__SVELTEKIT_DEV__: 'true',
__SVELTEKIT_EMBEDDED__: svelte_config.kit.embedded ? 'true' : 'false'
},
publicDir: svelte_config.kit.files.assets,
resolve: {
Expand Down
33 changes: 24 additions & 9 deletions packages/kit/src/runtime/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ function check_for_removed_attributes() {
* @returns {import('./types').Client}
*/
export function create_client({ target, base }) {
const container = __SVELTEKIT_EMBEDDED__ ? target : document.documentElement;
/** @type {Array<((url: URL) => boolean)>} */
const invalidated = [];

Expand Down Expand Up @@ -1194,7 +1195,7 @@ export function create_client({ target, base }) {
/** @type {NodeJS.Timeout} */
let mousemove_timeout;

target.addEventListener('mousemove', (event) => {
container.addEventListener('mousemove', (event) => {
const target = /** @type {Element} */ (event.target);

clearTimeout(mousemove_timeout);
Expand All @@ -1208,8 +1209,8 @@ export function create_client({ target, base }) {
preload(/** @type {Element} */ (event.composedPath()[0]), 1);
}

target.addEventListener('mousedown', tap);
target.addEventListener('touchstart', tap, { passive: true });
container.addEventListener('mousedown', tap);
container.addEventListener('touchstart', tap, { passive: true });

const observer = new IntersectionObserver(
(entries) => {
Expand All @@ -1228,7 +1229,7 @@ export function create_client({ target, base }) {
* @param {number} priority
*/
function preload(element, priority) {
const a = find_anchor(element, target);
const a = find_anchor(element, container);
if (!a) return;

const { url, external } = get_link_info(a, base);
Expand All @@ -1248,7 +1249,7 @@ export function create_client({ target, base }) {
function after_navigate() {
observer.disconnect();

for (const a of target.querySelectorAll('a')) {
for (const a of container.querySelectorAll('a')) {
const { url, external } = get_link_info(a, base);
if (external) continue;

Expand Down Expand Up @@ -1452,14 +1453,14 @@ export function create_client({ target, base }) {
}

/** @param {MouseEvent} event */
target.addEventListener('click', (event) => {
container.addEventListener('click', (event) => {
// Adapted from https://github.com/visionmedia/page.js
// MIT license https://github.com/visionmedia/page.js#license
if (event.button || event.which !== 1) return;
if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
if (event.defaultPrevented) return;

const a = find_anchor(/** @type {Element} */ (event.composedPath()[0]), target);
const a = find_anchor(/** @type {Element} */ (event.composedPath()[0]), container);
if (!a) return;

const { url, external, has } = get_link_info(a, base);
Expand Down Expand Up @@ -1529,7 +1530,7 @@ export function create_client({ target, base }) {
});
});

target.addEventListener('submit', (event) => {
container.addEventListener('submit', (event) => {
if (event.defaultPrevented) return;

const form = /** @type {HTMLFormElement} */ (
Expand Down Expand Up @@ -1634,11 +1635,25 @@ export function create_client({ target, base }) {
});
},

_hydrate: async ({ status, error, node_ids, params, route, data: server_data_nodes, form }) => {
_hydrate: async ({
status = 200,
error,
node_ids,
params,
route,
data: server_data_nodes,
form
}) => {
hydrated = true;

const url = new URL(location.href);

if (!__SVELTEKIT_EMBEDDED__) {
// See https://github.com/sveltejs/kit/pull/4935#issuecomment-1328093358 for one motivation
// of determining the params on the client side.
({ params = {}, route = { id: null } } = get_navigation_intent(url, false) || {});
}

/** @type {import('./types').NavigationFinished | undefined} */
let result;

Expand Down
43 changes: 30 additions & 13 deletions packages/kit/src/runtime/server/page/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,24 +266,41 @@ export async function render_response({
}

if (page_config.csr) {
const opts = [
`env: ${s(options.public_env)}`,
`paths: ${s(options.paths)}`,
`target: document.querySelector('[data-sveltekit-hydrate="${target}"]').parentNode`,
`version: ${s(options.version)}`
];

if (page_config.ssr) {
const hydrate = [
`node_ids: [${branch.map(({ node }) => node.index).join(', ')}]`,
`data: ${serialized.data}`,
`form: ${serialized.form}`
];

if (status !== 200) {
hydrate.push(`status: ${status}`);
}

if (error) {
hydrate.push(`error: ${devalue.uneval(error)}`);
}

if (options.embedded) {
hydrate.push(`params: ${devalue.uneval(event.params)}`, `route: ${s(event.route)}`);
}

opts.push(`hydrate: {\n\t\t\t\t\t${hydrate.join(',\n\t\t\t\t\t')}\n\t\t\t\t}`);
}

// prettier-ignore
const init_app = `
import { start } from ${s(prefixed(entry.file))};

start({
env: ${s(options.public_env)},
hydrate: ${page_config.ssr ? `{
status: ${status},
error: ${devalue.uneval(error)},
node_ids: [${branch.map(({ node }) => node.index).join(', ')}],
params: ${devalue.uneval(event.params)},
route: ${s(event.route)},
data: ${serialized.data},
form: ${serialized.form}
}` : 'null'},
paths: ${s(options.paths)},
target: document.querySelector('[data-sveltekit-hydrate="${target}"]').parentNode,
version: ${s(options.version)}
${opts.join(',\n\t\t\t\t')}
});
`;

Expand Down
4 changes: 2 additions & 2 deletions packages/kit/test/apps/basics/test/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -809,11 +809,11 @@ test.describe('Routing', () => {
expect(await page.textContent('h1')).toBe('hello');
});

test('ignores clicks outside the app target', async ({ page }) => {
test('recognizes clicks outside the app target', async ({ page }) => {
await page.goto('/routing/link-outside-app-target/source');

await page.click('[href="/routing/link-outside-app-target/target"]');
expect(await page.textContent('h1')).toBe('target: 0');
await expect(page.locator('h1')).toHaveText('target: 1');
});

test('responds to <form method="GET"> submission without reload', async ({ page }) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
import { onMount } from 'svelte';
import { increment, count } from '../state.js';

onMount(increment);
</script>

<h2>source: {count}</h2>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export let count = 0;

export function increment() {
count += 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script>
import { count } from '../state.js';
</script>

<h2>target: {count}</h2>
1 change: 1 addition & 0 deletions packages/kit/test/apps/options/source/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
<body>
<h1>I am in the template</h1>
<div>%sveltekit.body%</div>
<a href="/path-base/routing/link-outside-app-target/target">outside app target</a>
</body>
</html>
1 change: 1 addition & 0 deletions packages/kit/test/apps/options/svelte.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
const config = {
extensions: ['.jesuslivesineveryone', '.whokilledthemuffinman', '.svelte.md', '.svelte'],
kit: {
embedded: true,
csp: {
directives: {
'script-src': ['self']
Expand Down
9 changes: 9 additions & 0 deletions packages/kit/test/apps/options/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,12 @@ test.describe('Vite options', () => {
expect(await page.textContent('h2')).toBe(`${mode} === ${mode} === ${mode}`);
});
});

test.describe('Routing', () => {
test('ignores clicks outside the app target', async ({ page }) => {
await page.goto('/path-base/routing/link-outside-app-target/source');

await page.click('[href="/path-base/routing/link-outside-app-target/target"]');
await expect(page.locator('h2')).toHaveText('target: 0');
});
});
5 changes: 5 additions & 0 deletions packages/kit/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ export interface KitConfig {
*/
checkOrigin?: boolean;
};
/**
* Whether or not the app is embedded inside a larger app. If `true`, SvelteKit will add its event listeners related to navigation etc on the parent of `%sveltekit.body%` instead of `window`, and will pass `params` from the server rather than inferring them from `location.pathname`.
* @default false
*/
embedded?: boolean;
/**
* Environment variable configuration
*/
Expand Down
2 changes: 2 additions & 0 deletions packages/kit/types/internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ export interface SSROptions {
check_origin: boolean;
};
dev: boolean;
embedded: boolean;
handle_error(error: Error & { frame?: string }, event: RequestEvent): MaybePromise<App.Error>;
hooks: ServerHooks;
manifest: SSRManifest;
Expand Down Expand Up @@ -385,4 +386,5 @@ declare global {
const __SVELTEKIT_APP_VERSION_POLL_INTERVAL__: number;
const __SVELTEKIT_BROWSER__: boolean;
const __SVELTEKIT_DEV__: boolean;
const __SVELTEKIT_EMBEDDED__: boolean;
}