Skip to content

Commit

Permalink
fix: strip /@fs prefix correctly on Windows when invoking read()
Browse files Browse the repository at this point in the history
…in dev mode

Windows absolute paths look like `/@fs/C:/..` - when stripping the fs prefix, we need to remove the additional slash after the fs
  • Loading branch information
dummdidumm committed Jan 24, 2024
1 parent a93e19b commit 36dc773
Show file tree
Hide file tree
Showing 8 changed files with 49 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .changeset/fresh-points-smoke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: strip `/@fs` prefix correctly on Windows when invoking `read()` in dev mode
10 changes: 5 additions & 5 deletions packages/kit/src/exports/vite/dev/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { isCSSRequest, loadEnv, buildErrorMessage } from 'vite';
import { createReadableStream, getRequest, setResponse } from '../../../exports/node/index.js';
import { installPolyfills } from '../../../exports/node/polyfills.js';
import { coalesce_to_error } from '../../../utils/error.js';
import { posixify, resolve_entry, to_fs } from '../../../utils/filesystem.js';
import { from_fs, posixify, resolve_entry, to_fs } from '../../../utils/filesystem.js';
import { load_error_page } from '../../../core/config/index.js';
import { SVELTE_KIT_ASSETS } from '../../../constants.js';
import * as sync from '../../../core/sync/sync.js';
Expand Down Expand Up @@ -87,7 +87,7 @@ export async function dev(vite, vite_config, svelte_config) {

/** @param {string} id */
async function resolve(id) {
const url = id.startsWith('..') ? `/@fs${path.posix.resolve(id)}` : `/${id}`;
const url = id.startsWith('..') ? to_fs(path.posix.resolve(id)) : `/${id}`;

const module = await loud_ssr_load_module(url);

Expand Down Expand Up @@ -137,8 +137,8 @@ export async function dev(vite, vite_config, svelte_config) {
server_assets: new Proxy(
{},
{
has: (_, /** @type {string} */ file) => fs.existsSync(file.replace(/^\/@fs/, '')),
get: (_, /** @type {string} */ file) => fs.statSync(file.replace(/^\/@fs/, '')).size
has: (_, /** @type {string} */ file) => fs.existsSync(from_fs(file)),
get: (_, /** @type {string} */ file) => fs.statSync(from_fs(file)).size
}
),
nodes: manifest_data.nodes.map((node, index) => {
Expand Down Expand Up @@ -490,7 +490,7 @@ export async function dev(vite, vite_config, svelte_config) {

await server.init({
env,
read: (file) => createReadableStream(file.replace(/^\/@fs/, ''))
read: (file) => createReadableStream(from_fs(file))
});

const request = await getRequest({
Expand Down
13 changes: 13 additions & 0 deletions packages/kit/src/utils/filesystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,19 @@ export function to_fs(str) {
}${str}`;
}

/**
* Removes `/@fs` prefix from given path and posixifies it
* @param {string} str
*/
export function from_fs(str) {
str = posixify(str);
if (!str.startsWith('/@fs')) return str;

str = str.slice(4);
// Windows/Linux separation - Windows starts with a drive letter, we need to strip the additional / here
return str[2] === ':' && /[A-Z]/.test(str[1]) ? str.slice(1) : str;
}

/**
* Given an entry point like [cwd]/src/hooks, returns a filename like [cwd]/src/hooks.js or [cwd]/src/hooks/index.js
* @param {string} entry
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ import { read } from '$app/server';
import auto from './auto.txt';
import url from './url.txt?url';

const glob = import.meta.glob('../../../../read-file-test.txt', {
as: 'url',
eager: true
});

export async function load() {
if (!dev && !auto.startsWith('data:')) {
throw new Error('expected auto.txt to be inlined');
}

return {
auto: await read(auto).text(),
url: await read(url).text()
url: await read(url).text(),
glob: await read(Object.values(glob)[0]).text()
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

<p data-testid="auto">{data.auto}</p>
<p data-testid="url">{data.url}</p>
<p data-testid="glob">{data.glob}</p>
17 changes: 17 additions & 0 deletions packages/kit/test/apps/basics/test/cross-platform/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1033,3 +1033,20 @@ test.describe('XSS', () => {
);
});
});

test.describe('$app/server', () => {
test('can read a file', async ({ page }) => {
await page.goto('/read-file');

const auto = await page.textContent('[data-testid="auto"]');
const url = await page.textContent('[data-testid="url"]');
const glob = await page.textContent('[data-testid="glob"]');

// the emoji is there to check that base64 decoding works correctly
expect(auto.trim()).toBe('Imported without ?url 😎');
expect(url.trim()).toBe('Imported with ?url 😎');
expect(glob.trim()).toBe(
'Imported with url glob from the read-file test in basics. Placed here outside the app folder to force a /@fs prefix 😎'
);
});
});
13 changes: 0 additions & 13 deletions packages/kit/test/apps/basics/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -706,19 +706,6 @@ test.describe('$app/paths', () => {
});
});

test.describe('$app/server', () => {
test('can read a file', async ({ page }) => {
await page.goto('/read-file');

const auto = await page.textContent('[data-testid="auto"]');
const url = await page.textContent('[data-testid="url"]');

// the emoji is there to check that base64 decoding works correctly
expect(auto.trim()).toBe('Imported without ?url 😎');
expect(url.trim()).toBe('Imported with ?url 😎');
});
});

test.describe('$app/stores', () => {
test('can access page.url', async ({ baseURL, page }) => {
await page.goto('/origin');
Expand Down
1 change: 1 addition & 0 deletions packages/kit/test/apps/read-file-test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Imported with url glob from the read-file test in basics. Placed here outside the app folder to force a /@fs prefix 😎

0 comments on commit 36dc773

Please sign in to comment.