From 9e3dadc54ead06753814d631632e1d252394877e Mon Sep 17 00:00:00 2001 From: jycouet Date: Sun, 3 Aug 2025 12:56:54 +0200 Subject: [PATCH 1/2] feat: remote files can now be in your kit.alias locations --- .changeset/deep-tools-stand.md | 5 +++++ .../docs/20-core-concepts/60-remote-functions.md | 2 +- .../src/core/sync/create_manifest_data/index.js | 15 ++++++++++++++- .../core/sync/create_manifest_data/index.spec.js | 16 ++++++++++++++++ .../src/modules/remotes/hello.remote.js | 3 +++ .../samples/remotes-with-alias/svelte.config.js | 13 +++++++++++++ .../kit/src/exports/vite/graph_analysis/index.js | 5 +++++ .../basics/src/modules/remotes/hello.remote.js | 3 +++ .../apps/basics/src/routes/remote/+page.svelte | 4 ++++ packages/kit/test/apps/basics/svelte.config.js | 4 ++++ packages/kit/test/apps/basics/test/test.js | 5 +++++ 11 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 .changeset/deep-tools-stand.md create mode 100644 packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/src/modules/remotes/hello.remote.js create mode 100644 packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/svelte.config.js create mode 100644 packages/kit/test/apps/basics/src/modules/remotes/hello.remote.js diff --git a/.changeset/deep-tools-stand.md b/.changeset/deep-tools-stand.md new file mode 100644 index 000000000000..e655f463452f --- /dev/null +++ b/.changeset/deep-tools-stand.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +feat: remote files can now be in your kit.alias locations diff --git a/documentation/docs/20-core-concepts/60-remote-functions.md b/documentation/docs/20-core-concepts/60-remote-functions.md index b62e6585fcb5..0513415030ba 100644 --- a/documentation/docs/20-core-concepts/60-remote-functions.md +++ b/documentation/docs/20-core-concepts/60-remote-functions.md @@ -25,7 +25,7 @@ export default { ## Overview -Remote functions are exported from a `.remote.js` or `.remote.ts` file, and come in four flavours: `query`, `form`, `command` and `prerender`. On the client, the exported functions are transformed to `fetch` wrappers that invoke their counterparts on the server via a generated HTTP endpoint. +Remote functions are exported from a `.remote.js` or `.remote.ts` file, and come in four flavours: `query`, `form`, `command` and `prerender`. On the client, the exported functions are transformed to `fetch` wrappers that invoke their counterparts on the server via a generated HTTP endpoint. You can put these remote files in `lib` or `routes` directory, or any directory that is aliased with the `kit.alias` option. ## query diff --git a/packages/kit/src/core/sync/create_manifest_data/index.js b/packages/kit/src/core/sync/create_manifest_data/index.js index a121ac189be0..0814bceb507b 100644 --- a/packages/kit/src/core/sync/create_manifest_data/index.js +++ b/packages/kit/src/core/sync/create_manifest_data/index.js @@ -481,7 +481,20 @@ function create_remotes(config, cwd) { const remotes = []; // TODO could files live in other directories, including node_modules? - for (const dir of [config.kit.files.lib, config.kit.files.routes]) { + const directories = [ + config.kit.files.lib, + config.kit.files.routes + ]; + + // Add alias directories + for (const [, alias_path] of Object.entries(config.kit.alias)) { + const resolved_path = path.resolve(cwd, alias_path); + if (fs.existsSync(resolved_path)) { + directories.push(resolved_path); + } + } + + for (const dir of directories) { if (!fs.existsSync(dir)) continue; for (const file of walk(dir)) { diff --git a/packages/kit/src/core/sync/create_manifest_data/index.spec.js b/packages/kit/src/core/sync/create_manifest_data/index.spec.js index 2642e0c3cce0..84a203463897 100644 --- a/packages/kit/src/core/sync/create_manifest_data/index.spec.js +++ b/packages/kit/src/core/sync/create_manifest_data/index.spec.js @@ -820,3 +820,19 @@ test('errors with both ts and js handlers for the same route', () => { /^Multiple endpoint files found in samples\/conflicting-ts-js-handlers-server\/ : \+server\.js and \+server\.ts/ ); }); + +test('finds remote functions in alias directories', () => { + const { remotes } = create('samples/remotes-with-alias', { + kit: { + experimental: { + remoteFunctions: true + }, + alias: { + $modules: './src/modules' + } + } + }); + + expect(remotes).toHaveLength(1); + expect(remotes[0].file).toBe('samples/remotes-with-alias/src/modules/remotes/hello.remote.js'); +}); diff --git a/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/src/modules/remotes/hello.remote.js b/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/src/modules/remotes/hello.remote.js new file mode 100644 index 000000000000..99a2afbca0c9 --- /dev/null +++ b/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/src/modules/remotes/hello.remote.js @@ -0,0 +1,3 @@ +import { query } from '$app/server'; + +export const get_hello = query(() => 'hello world'); \ No newline at end of file diff --git a/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/svelte.config.js b/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/svelte.config.js new file mode 100644 index 000000000000..58ea5ddeadaa --- /dev/null +++ b/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/svelte.config.js @@ -0,0 +1,13 @@ +/** @type {import('@sveltejs/kit').Config} */ +const config = { + kit: { + experimental: { + remoteFunctions: true + }, + alias: { + $modules: './src/modules' + } + } +}; + +export default config; \ No newline at end of file diff --git a/packages/kit/src/exports/vite/graph_analysis/index.js b/packages/kit/src/exports/vite/graph_analysis/index.js index ecf7ee146769..fa29fa24be12 100644 --- a/packages/kit/src/exports/vite/graph_analysis/index.js +++ b/packages/kit/src/exports/vite/graph_analysis/index.js @@ -5,6 +5,7 @@ import { app_server, env_dynamic_private, env_static_private } from '../module_i const ILLEGAL_IMPORTS = new Set([env_dynamic_private, env_static_private, app_server]); const ILLEGAL_MODULE_NAME_PATTERN = /.*\.server\..+/; +const REMOTE_FILE_PATTERN = /.*\.remote\..+/; /** * Checks if given id imports a module that is not allowed to be imported into client-side code. @@ -18,6 +19,10 @@ const ILLEGAL_MODULE_NAME_PATTERN = /.*\.server\..+/; export function is_illegal(id, dirs) { if (ILLEGAL_IMPORTS.has(id)) return true; if (!id.startsWith(dirs.cwd) || id.startsWith(dirs.node_modules)) return false; + + // Allow remote functions to be imported on the client side (they get transformed) + if (REMOTE_FILE_PATTERN.test(path.basename(id))) return false; + return ILLEGAL_MODULE_NAME_PATTERN.test(path.basename(id)) || id.startsWith(dirs.server); } diff --git a/packages/kit/test/apps/basics/src/modules/remotes/hello.remote.js b/packages/kit/test/apps/basics/src/modules/remotes/hello.remote.js new file mode 100644 index 000000000000..b4014de66429 --- /dev/null +++ b/packages/kit/test/apps/basics/src/modules/remotes/hello.remote.js @@ -0,0 +1,3 @@ +import { query } from '$app/server'; + +export const get_hello_from_modules = query(() => 'hello from $modules'); \ No newline at end of file diff --git a/packages/kit/test/apps/basics/src/routes/remote/+page.svelte b/packages/kit/test/apps/basics/src/routes/remote/+page.svelte index a05f83efb528..85681d259966 100644 --- a/packages/kit/test/apps/basics/src/routes/remote/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/remote/+page.svelte @@ -2,6 +2,7 @@ import { browser } from '$app/environment'; import { refreshAll } from '$app/navigation'; import { add, get_count, set_count, set_count_server } from './query-command.remote.js'; + import { get_hello_from_modules } from '$modules/remotes/hello.remote.js'; let { data } = $props(); @@ -11,6 +12,9 @@ const count = browser ? get_count() : null; // so that we get a remote request in the browser +{#if browser} +

{#await get_hello_from_modules() then result}{result}{/await}

+{/if}

{data.echo_result}

{#if browser} diff --git a/packages/kit/test/apps/basics/svelte.config.js b/packages/kit/test/apps/basics/svelte.config.js index 2410ff83d57f..64026af3aa43 100644 --- a/packages/kit/test/apps/basics/svelte.config.js +++ b/packages/kit/test/apps/basics/svelte.config.js @@ -22,6 +22,10 @@ const config = { remoteFunctions: true }, + alias: { + $modules: './src/modules' + }, + prerender: { entries: [ '*', diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js index 0cdce83605ee..feb43db3e590 100644 --- a/packages/kit/test/apps/basics/test/test.js +++ b/packages/kit/test/apps/basics/test/test.js @@ -1622,6 +1622,11 @@ test.describe('remote functions', () => { await clicknav('[href="/remote/prerender/functions-only"]'); await expect(page.locator('#prerendered-data')).toHaveText('a c 中文 yes'); }); + + test('query returns correct data from modules', async ({ page }) => { + await page.goto('/remote'); + await expect(page.locator('#hello-from-modules')).toHaveText('hello from $modules'); + }); }); test.describe('params prop', () => { From f614425764e23a272afdf8177e93b5deb2d8179a Mon Sep 17 00:00:00 2001 From: jycouet Date: Sun, 3 Aug 2025 13:03:10 +0200 Subject: [PATCH 2/2] format --- packages/kit/src/core/sync/create_manifest_data/index.js | 5 +---- .../remotes-with-alias/src/modules/remotes/hello.remote.js | 2 +- .../test/samples/remotes-with-alias/svelte.config.js | 2 +- packages/kit/src/exports/vite/graph_analysis/index.js | 4 ++-- .../kit/test/apps/basics/src/modules/remotes/hello.remote.js | 2 +- packages/kit/test/apps/basics/svelte.config.js | 2 +- 6 files changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/kit/src/core/sync/create_manifest_data/index.js b/packages/kit/src/core/sync/create_manifest_data/index.js index 0814bceb507b..71803434ed1a 100644 --- a/packages/kit/src/core/sync/create_manifest_data/index.js +++ b/packages/kit/src/core/sync/create_manifest_data/index.js @@ -481,10 +481,7 @@ function create_remotes(config, cwd) { const remotes = []; // TODO could files live in other directories, including node_modules? - const directories = [ - config.kit.files.lib, - config.kit.files.routes - ]; + const directories = [config.kit.files.lib, config.kit.files.routes]; // Add alias directories for (const [, alias_path] of Object.entries(config.kit.alias)) { diff --git a/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/src/modules/remotes/hello.remote.js b/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/src/modules/remotes/hello.remote.js index 99a2afbca0c9..7a927ee4a277 100644 --- a/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/src/modules/remotes/hello.remote.js +++ b/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/src/modules/remotes/hello.remote.js @@ -1,3 +1,3 @@ import { query } from '$app/server'; -export const get_hello = query(() => 'hello world'); \ No newline at end of file +export const get_hello = query(() => 'hello world'); diff --git a/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/svelte.config.js b/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/svelte.config.js index 58ea5ddeadaa..7fb31361c918 100644 --- a/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/svelte.config.js +++ b/packages/kit/src/core/sync/create_manifest_data/test/samples/remotes-with-alias/svelte.config.js @@ -10,4 +10,4 @@ const config = { } }; -export default config; \ No newline at end of file +export default config; diff --git a/packages/kit/src/exports/vite/graph_analysis/index.js b/packages/kit/src/exports/vite/graph_analysis/index.js index fa29fa24be12..4979b07150b4 100644 --- a/packages/kit/src/exports/vite/graph_analysis/index.js +++ b/packages/kit/src/exports/vite/graph_analysis/index.js @@ -19,10 +19,10 @@ const REMOTE_FILE_PATTERN = /.*\.remote\..+/; export function is_illegal(id, dirs) { if (ILLEGAL_IMPORTS.has(id)) return true; if (!id.startsWith(dirs.cwd) || id.startsWith(dirs.node_modules)) return false; - + // Allow remote functions to be imported on the client side (they get transformed) if (REMOTE_FILE_PATTERN.test(path.basename(id))) return false; - + return ILLEGAL_MODULE_NAME_PATTERN.test(path.basename(id)) || id.startsWith(dirs.server); } diff --git a/packages/kit/test/apps/basics/src/modules/remotes/hello.remote.js b/packages/kit/test/apps/basics/src/modules/remotes/hello.remote.js index b4014de66429..a522b36b5957 100644 --- a/packages/kit/test/apps/basics/src/modules/remotes/hello.remote.js +++ b/packages/kit/test/apps/basics/src/modules/remotes/hello.remote.js @@ -1,3 +1,3 @@ import { query } from '$app/server'; -export const get_hello_from_modules = query(() => 'hello from $modules'); \ No newline at end of file +export const get_hello_from_modules = query(() => 'hello from $modules'); diff --git a/packages/kit/test/apps/basics/svelte.config.js b/packages/kit/test/apps/basics/svelte.config.js index 64026af3aa43..9fc0e8daffd9 100644 --- a/packages/kit/test/apps/basics/svelte.config.js +++ b/packages/kit/test/apps/basics/svelte.config.js @@ -24,7 +24,7 @@ const config = { alias: { $modules: './src/modules' - }, + }, prerender: { entries: [