Skip to content

Commit

Permalink
feat: allow $app/paths to be used without an app (#8838)
Browse files Browse the repository at this point in the history
* feat: allow $app/paths to be used without an app

* format

* try to support SVELTE_KIT_ASSETS

* revert a couple lines

* simplify

* fix hydration case

* revert unnecessary change

* remove old docs

* a bit more cleanup

* type checking

* fix

---------

Co-authored-by: Rich Harris <hello@rich-harris.dev>
  • Loading branch information
benmccann and Rich-Harris committed Feb 2, 2023
1 parent 27e2854 commit fafe7d5
Show file tree
Hide file tree
Showing 26 changed files with 88 additions and 80 deletions.
5 changes: 5 additions & 0 deletions .changeset/cyan-ants-float.md
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': minor
---

feat: allow $app/paths to be used without an app
2 changes: 1 addition & 1 deletion packages/kit/package.json
Expand Up @@ -60,7 +60,7 @@
"lint": "prettier --check . --config ../../.prettierrc --ignore-path .gitignore && eslint src/**",
"check": "tsc",
"check:all": "tsc && pnpm -r --filter=\"./**\" check",
"format": "pnpm lint --write",
"format": "prettier --write . --config ../../.prettierrc --ignore-path .gitignore",
"test": "pnpm test:unit && pnpm test:integration",
"test:integration": "pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test",
"test:cross-platform:dev": "pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test:cross-platform:dev",
Expand Down
6 changes: 4 additions & 2 deletions packages/kit/src/constants.js
@@ -1,5 +1,7 @@
// in `vite dev` and `vite preview`, we use a fake asset path so that we can
// serve local assets while verifying that requests are correctly prefixed
/**
* A fake asset path used in `vite dev` and `vite preview`, so that we can
* serve local assets while verifying that requests are correctly prefixed
*/
export const SVELTE_KIT_ASSETS = '/_svelte_kit_assets';

export const GENERATED_COMMENT = '// this file is generated — do not edit it\n';
2 changes: 1 addition & 1 deletion packages/kit/src/core/postbuild/analyse.js
@@ -1,6 +1,6 @@
import { join } from 'node:path';
import { pathToFileURL } from 'node:url';
import { get_option } from '../../runtime/server/utils.js';
import { get_option } from '../../utils/options.js';
import {
validate_common_exports,
validate_page_server_exports,
Expand Down
5 changes: 1 addition & 4 deletions packages/kit/src/core/postbuild/fallback.js
Expand Up @@ -15,9 +15,7 @@ installPolyfills();
const server_root = join(config.outDir, 'output');

/** @type {import('types').ServerInternalModule} */
const { set_building, set_paths } = await import(
pathToFileURL(`${server_root}/server/internal.js`).href
);
const { set_building } = await import(pathToFileURL(`${server_root}/server/internal.js`).href);

/** @type {import('types').ServerModule} */
const { Server } = await import(pathToFileURL(`${server_root}/server/index.js`).href);
Expand All @@ -26,7 +24,6 @@ const { Server } = await import(pathToFileURL(`${server_root}/server/index.js`).
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;

set_building(true);
set_paths(config.paths);

const server = new Server(manifest);
await server.init({ env: JSON.parse(env) });
Expand Down
2 changes: 0 additions & 2 deletions packages/kit/src/core/postbuild/prerender.js
Expand Up @@ -100,8 +100,6 @@ async function prerender({ out, manifest_path, metadata, verbose, env }) {
/** @type {Map<string, string>} */
const saved = new Map();

internal.set_paths(config.paths);

const server = new Server(manifest);
await server.init({ env });

Expand Down
5 changes: 2 additions & 3 deletions packages/kit/src/core/sync/write_server.js
Expand Up @@ -25,9 +25,8 @@ const server_template = ({
error_page
}) => `
import root from '../root.svelte';
import { set_building, set_paths, set_private_env, set_public_env, set_version } from '${runtime_directory}/shared.js';
import { set_assets, set_building, set_private_env, set_public_env, set_version } from '${runtime_directory}/shared.js';
set_paths(${s(config.kit.paths)});
set_version(${s(config.kit.version.name)});
export const options = {
Expand Down Expand Up @@ -58,7 +57,7 @@ export function get_hooks() {
return ${hooks ? `import(${s(hooks)})` : '{}'};
}
export { set_building, set_paths, set_private_env, set_public_env };
export { set_assets, set_building, set_private_env, set_public_env };
`;

// TODO need to re-run this whenever src/app.html or src/error.html are
Expand Down
9 changes: 3 additions & 6 deletions packages/kit/src/exports/vite/dev/index.js
Expand Up @@ -438,20 +438,17 @@ export async function dev(vite, vite_config, svelte_config) {
return;
}

// we have to import `Server` before calling `set_paths`
// we have to import `Server` before calling `set_assets`
const { Server } = /** @type {import('types').ServerModule} */ (
await vite.ssrLoadModule(`${runtime_base}/server/index.js`)
);

const { set_paths, set_version, set_fix_stack_trace } =
const { set_assets, set_version, set_fix_stack_trace } =
/** @type {import('types').ServerInternalModule} */ (
await vite.ssrLoadModule(`${runtime_base}/shared.js`)
);

set_paths({
base: svelte_config.kit.paths.base,
assets
});
set_assets(assets);

set_version(svelte_config.kit.version.name);

Expand Down
26 changes: 19 additions & 7 deletions packages/kit/src/exports/vite/index.js
Expand Up @@ -22,6 +22,7 @@ import { get_config_aliases, get_env } from './utils.js';
import { write_client_manifest } from '../../core/sync/write_client_manifest.js';
import prerender from '../../core/postbuild/prerender.js';
import analyse from '../../core/postbuild/analyse.js';
import { s } from '../../utils/misc.js';

export { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

Expand Down Expand Up @@ -253,9 +254,9 @@ function kit({ svelte_config }) {
new_config.build.ssr = !secondary_build_started;

new_config.define = {
__SVELTEKIT_ADAPTER_NAME__: JSON.stringify(kit.adapter?.name),
__SVELTEKIT_APP_VERSION_FILE__: JSON.stringify(`${kit.appDir}/version.json`),
__SVELTEKIT_APP_VERSION_POLL_INTERVAL__: JSON.stringify(kit.version.pollInterval),
__SVELTEKIT_ADAPTER_NAME__: s(kit.adapter?.name),
__SVELTEKIT_APP_VERSION_FILE__: s(`${kit.appDir}/version.json`),
__SVELTEKIT_APP_VERSION_POLL_INTERVAL__: s(kit.version.pollInterval),
__SVELTEKIT_DEV__: 'false',
__SVELTEKIT_EMBEDDED__: kit.embedded ? 'true' : 'false'
};
Expand Down Expand Up @@ -315,7 +316,9 @@ function kit({ svelte_config }) {

async resolveId(id) {
// treat $env/static/[public|private] as virtual
if (id.startsWith('$env/') || id === '$service-worker') return `\0${id}`;
if (id.startsWith('$env/') || id === '$internal/paths' || id === '$service-worker') {
return `\0${id}`;
}
},

async load(id, options) {
Expand Down Expand Up @@ -351,6 +354,15 @@ function kit({ svelte_config }) {
);
case '\0$service-worker':
return create_service_worker_module(svelte_config);
case '\0$internal/paths':
const { assets, base } = svelte_config.kit.paths;
return `export const base = ${s(base)};
export let assets = ${s(assets)};
/** @param {string} path */
export function set_assets(path) {
assets = path;
}`;
}
}
};
Expand Down Expand Up @@ -552,7 +564,7 @@ function kit({ svelte_config }) {
this.emitFile({
type: 'asset',
fileName: `${kit.appDir}/version.json`,
source: JSON.stringify({ version: kit.version.name })
source: s({ version: kit.version.name })
});
},

Expand Down Expand Up @@ -788,9 +800,9 @@ export const build = [];
export const files = [
${create_assets(config)
.filter((asset) => config.kit.serviceWorker.files(asset.file))
.map((asset) => `${JSON.stringify(`${config.kit.paths.base}/${asset.file}`)}`)
.map((asset) => `${s(`${config.kit.paths.base}/${asset.file}`)}`)
.join(',\n\t\t\t\t')}
];
export const prerendered = [];
export const version = ${JSON.stringify(config.kit.version.name)};
export const version = ${s(config.kit.version.name)};
`;
4 changes: 2 additions & 2 deletions packages/kit/src/exports/vite/preview/index.js
Expand Up @@ -37,14 +37,14 @@ export async function preview(vite, vite_config, svelte_config) {
const dir = join(svelte_config.kit.outDir, 'output/server');

/** @type {import('types').ServerInternalModule} */
const { set_paths } = await import(pathToFileURL(join(dir, 'internal.js')).href);
const { set_assets } = await import(pathToFileURL(join(dir, 'internal.js')).href);

/** @type {import('types').ServerModule} */
const { Server } = await import(pathToFileURL(join(dir, 'index.js')).href);

const { manifest } = await import(pathToFileURL(join(dir, 'manifest.js')).href);

set_paths({ base, assets });
set_assets(assets);

const server = new Server(manifest);
await server.init({
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/src/runtime/app/paths.js
@@ -1 +1 @@
export { base, assets } from '../shared.js';
export { base, assets } from '$internal/paths';
4 changes: 2 additions & 2 deletions packages/kit/src/runtime/client/client.js
Expand Up @@ -26,6 +26,7 @@ import { parse } from './parse.js';

import Root from '__GENERATED__/root.svelte';
import { nodes, server_loads, dictionary, matchers, hooks } from '__CLIENT__/manifest.js';
import { base } from '$internal/paths';
import { HttpError, Redirect } from '../control.js';
import { stores } from './singletons.js';
import { unwrap_promises } from '../../utils/promises.js';
Expand Down Expand Up @@ -66,11 +67,10 @@ function update_scroll_positions(index) {
/**
* @param {{
* target: HTMLElement;
* base: string;
* }} opts
* @returns {import('./types').Client}
*/
export function create_client({ target, base }) {
export function create_client({ target }) {
const container = __SVELTEKIT_EMBEDDED__ ? target : document.documentElement;
/** @type {Array<((url: URL) => boolean)>} */
const invalidated = [];
Expand Down
14 changes: 5 additions & 9 deletions packages/kit/src/runtime/client/start.js
@@ -1,23 +1,20 @@
import { DEV } from 'esm-env';
import { create_client } from './client.js';
import { init } from './singletons.js';
import { set_paths, set_version, set_public_env } from '../shared.js';
import { set_assets, set_version, set_public_env } from '../shared.js';

/**
* @param {{
* assets: string;
* env: Record<string, string>;
* hydrate: Parameters<import('./types').Client['_hydrate']>[0];
* paths: {
* assets: string;
* base: string;
* },
* target: HTMLElement;
* version: string;
* }} opts
*/
export async function start({ env, hydrate, paths, target, version }) {
export async function start({ assets, env, hydrate, target, version }) {
set_public_env(env);
set_paths(paths);
set_assets(assets);
set_version(version);

if (DEV && target === document.body) {
Expand All @@ -27,8 +24,7 @@ export async function start({ env, hydrate, paths, target, version }) {
}

const client = create_client({
target,
base: paths.base
target
});

init({ client });
Expand Down
3 changes: 2 additions & 1 deletion packages/kit/src/runtime/client/utils.js
@@ -1,6 +1,7 @@
import { BROWSER, DEV } from 'esm-env';
import { writable } from 'svelte/store';
import { assets, version } from '../shared.js';
import { assets } from '$internal/paths';
import { version } from '../shared.js';
import { PRELOAD_PRIORITIES } from './constants.js';

/* global __SVELTEKIT_APP_VERSION_FILE__, __SVELTEKIT_APP_VERSION_POLL_INTERVAL__ */
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/src/runtime/server/fetch.js
@@ -1,6 +1,6 @@
import * as set_cookie_parser from 'set-cookie-parser';
import { respond } from './respond.js';
import * as paths from '../shared.js';
import * as paths from '$internal/paths';

/**
* @param {{
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/src/runtime/server/page/index.js
Expand Up @@ -4,7 +4,6 @@ import { normalize_error } from '../../../utils/error.js';
import { add_data_suffix } from '../../../utils/url.js';
import { HttpError, Redirect } from '../../control.js';
import {
get_option,
redirect_response,
static_error_page,
handle_error_and_jsonify,
Expand All @@ -19,6 +18,7 @@ import {
import { load_data, load_server_data } from './load_data.js';
import { render_response } from './render.js';
import { respond_with_error } from './respond_with_error.js';
import { get_option } from '../../../utils/options.js';

/**
* @param {import('types').RequestEvent} event
Expand Down
5 changes: 3 additions & 2 deletions packages/kit/src/runtime/server/page/render.js
@@ -1,13 +1,14 @@
import * as devalue from 'devalue';
import { readable, writable } from 'svelte/store';
import { DEV } from 'esm-env';
import { assets, base } from '$internal/paths';
import { hash } from '../../hash.js';
import { serialize_data } from './serialize_data.js';
import { s } from '../../../utils/misc.js';
import { Csp } from './csp.js';
import { uneval_action_response } from './actions.js';
import { clarify_devalue_error } from '../utils.js';
import { assets, base, version, public_env } from '../../shared.js';
import { version, public_env } from '../../shared.js';
import { text } from '../../../exports/index.js';

// TODO rename this function/module
Expand Down Expand Up @@ -265,8 +266,8 @@ export async function render_response({

if (page_config.csr) {
const opts = [
`assets: ${s(assets)}`,
`env: ${s(public_env)}`,
`paths: ${s({ assets, base })}`,
`target: document.querySelector('[data-sveltekit-hydrate="${target}"]').parentNode`,
`version: ${s(version)}`
];
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/src/runtime/server/page/respond_with_error.js
Expand Up @@ -2,11 +2,11 @@ import { render_response } from './render.js';
import { load_data, load_server_data } from './load_data.js';
import {
handle_error_and_jsonify,
get_option,
static_error_page,
redirect_response,
GENERIC_ERROR
} from '../utils.js';
import { get_option } from '../../../utils/options.js';
import { HttpError, Redirect } from '../../control.js';

/**
Expand Down
11 changes: 6 additions & 5 deletions packages/kit/src/runtime/server/respond.js
@@ -1,10 +1,11 @@
import { DEV } from 'esm-env';
import { base } from '$internal/paths';
import { is_endpoint_request, render_endpoint } from './endpoint.js';
import { render_page } from './page/index.js';
import { render_response } from './page/render.js';
import { respond_with_error } from './page/respond_with_error.js';
import { is_form_content_type } from '../../utils/http.js';
import { GENERIC_ERROR, get_option, handle_fatal_error, redirect_response } from './utils.js';
import { GENERIC_ERROR, handle_fatal_error, redirect_response } from './utils.js';
import {
decode_pathname,
decode_params,
Expand All @@ -23,8 +24,8 @@ import {
validate_page_server_exports,
validate_server_exports
} from '../../utils/exports.js';
import { get_option } from '../../utils/options.js';
import { error, json, text } from '../../exports/index.js';
import * as paths from '../shared.js';

/* global __SVELTEKIT_ADAPTER_NAME__ */

Expand Down Expand Up @@ -70,11 +71,11 @@ export async function respond(request, options, manifest, state) {
/** @type {Record<string, string>} */
let params = {};

if (paths.base && !state.prerendering?.fallback) {
if (!decoded.startsWith(paths.base)) {
if (base && !state.prerendering?.fallback) {
if (!decoded.startsWith(base)) {
return text('Not found', { status: 404 });
}
decoded = decoded.slice(paths.base.length) || '/';
decoded = decoded.slice(base.length) || '/';
}

const is_data_request = has_data_suffix(decoded);
Expand Down
17 changes: 0 additions & 17 deletions packages/kit/src/runtime/server/utils.js
Expand Up @@ -51,23 +51,6 @@ export function allowed_methods(mod) {
return allowed;
}

/**
* @template {'prerender' | 'ssr' | 'csr' | 'trailingSlash'} Option
* @template {Option extends 'prerender' ? import('types').PrerenderOption : Option extends 'trailingSlash' ? import('types').TrailingSlash : boolean} Value
*
* @param {Array<import('types').SSRNode | undefined>} nodes
* @param {Option} option
*
* @returns {Value | undefined}
*/
export function get_option(nodes, option) {
return nodes.reduce((value, node) => {
return /** @type {any} TypeScript's too dumb to understand this */ (
node?.universal?.[option] ?? node?.server?.[option] ?? value
);
}, /** @type {Value | undefined} */ (undefined));
}

/**
* Return as a response that renders the error.html
*
Expand Down

0 comments on commit fafe7d5

Please sign in to comment.