Skip to content

Commit

Permalink
[fix] allow missing routes folder (#6944)
Browse files Browse the repository at this point in the history
* [fix] allow missing routes folder

Fixes #6921

* oops

* explanatory comment
  • Loading branch information
dummdidumm committed Sep 21, 2022
1 parent 2af2a9d commit afba48c
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 68 deletions.
5 changes: 5 additions & 0 deletions .changeset/dirty-candles-peel.md
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

[fix] allow missing routes folder
150 changes: 84 additions & 66 deletions packages/kit/src/core/sync/create_manifest_data/index.js
Expand Up @@ -225,97 +225,115 @@ function create_routes_and_nodes(cwd, config, fallback) {
walk(0, '', '', null);

const root = /** @type {import('types').RouteData} */ (route_map.get(''));

// TODO remove for 1.0
if (route_map.size === 1) {
if (!root.leaf && !root.error && !root.layout && !root.endpoint) {
throw new Error(
// TODO adjust this error message for 1.0
// 'No routes found. If you are using a custom src/routes directory, make sure it is specified in svelte.config.js'
'The filesystem router API has changed, see https://github.com/sveltejs/kit/discussions/5774 for details'
);
}
}
} else {
// If there's no routes directory, we'll just create a single empty route. This ensures the root layout and
// error components are included in the manifest, which is needed for subsequent build/dev commands to work
route_map.set('', {
id: '',
segment: '',
pattern: /^$/,
names: [],
types: [],
parent: null,
layout: null,
error: null,
leaf: null,
page: null,
endpoint: null
});
}

if (!root.layout?.component) {
if (!root.layout) root.layout = { depth: 0, child_pages: [] };
root.layout.component = posixify(path.relative(cwd, `${fallback}/layout.svelte`));
}
const root = /** @type {import('types').RouteData} */ (route_map.get(''));

if (!root.error?.component) {
if (!root.error) root.error = { depth: 0 };
root.error.component = posixify(path.relative(cwd, `${fallback}/error.svelte`));
}
if (!root.layout?.component) {
if (!root.layout) root.layout = { depth: 0, child_pages: [] };
root.layout.component = posixify(path.relative(cwd, `${fallback}/layout.svelte`));
}

// we do layouts/errors first as they are more likely to be reused,
// and smaller indexes take fewer bytes. also, this guarantees that
// the default error/layout are 0/1
route_map.forEach((route) => {
if (route.layout) nodes.push(route.layout);
if (route.error) nodes.push(route.error);
});
if (!root.error?.component) {
if (!root.error) root.error = { depth: 0 };
root.error.component = posixify(path.relative(cwd, `${fallback}/error.svelte`));
}

/** @type {Map<string, string>} */
const conflicts = new Map();
// we do layouts/errors first as they are more likely to be reused,
// and smaller indexes take fewer bytes. also, this guarantees that
// the default error/layout are 0/1
route_map.forEach((route) => {
if (route.layout) nodes.push(route.layout);
if (route.error) nodes.push(route.error);
});

route_map.forEach((route) => {
if (!route.leaf) return;
/** @type {Map<string, string>} */
const conflicts = new Map();

nodes.push(route.leaf);
route_map.forEach((route) => {
if (!route.leaf) return;

const normalized = route.id.split('/').filter(affects_path).join('/');
nodes.push(route.leaf);

if (conflicts.has(normalized)) {
throw new Error(`${conflicts.get(normalized)} and ${route.id} occupy the same route`);
}
const normalized = route.id.split('/').filter(affects_path).join('/');

conflicts.set(normalized, route.id);
});
if (conflicts.has(normalized)) {
throw new Error(`${conflicts.get(normalized)} and ${route.id} occupy the same route`);
}

const indexes = new Map(nodes.map((node, i) => [node, i]));
conflicts.set(normalized, route.id);
});

route_map.forEach((route) => {
if (!route.leaf) return;
const indexes = new Map(nodes.map((node, i) => [node, i]));

route.page = {
layouts: [],
errors: [],
leaf: /** @type {number} */ (indexes.get(route.leaf))
};
route_map.forEach((route) => {
if (!route.leaf) return;

/** @type {import('types').RouteData | null} */
let current_route = route;
let current_node = route.leaf;
let parent_id = route.leaf.parent_id;

while (current_route) {
if (parent_id === undefined || current_route.segment === parent_id) {
if (current_route.layout || current_route.error) {
route.page.layouts.unshift(
current_route.layout ? indexes.get(current_route.layout) : undefined
);
route.page.errors.unshift(
current_route.error ? indexes.get(current_route.error) : undefined
);
}
route.page = {
layouts: [],
errors: [],
leaf: /** @type {number} */ (indexes.get(route.leaf))
};

if (current_route.layout) {
/** @type {import('types').PageNode[]} */ (current_route.layout.child_pages).push(
route.leaf
);
current_node.parent = current_node = current_route.layout;
parent_id = current_node.parent_id;
} else {
parent_id = undefined;
}
/** @type {import('types').RouteData | null} */
let current_route = route;
let current_node = route.leaf;
let parent_id = route.leaf.parent_id;

while (current_route) {
if (parent_id === undefined || current_route.segment === parent_id) {
if (current_route.layout || current_route.error) {
route.page.layouts.unshift(
current_route.layout ? indexes.get(current_route.layout) : undefined
);
route.page.errors.unshift(
current_route.error ? indexes.get(current_route.error) : undefined
);
}

current_route = current_route.parent;
if (current_route.layout) {
/** @type {import('types').PageNode[]} */ (current_route.layout.child_pages).push(
route.leaf
);
current_node.parent = current_node = current_route.layout;
parent_id = current_node.parent_id;
} else {
parent_id = undefined;
}
}

if (parent_id !== undefined) {
throw new Error(`${current_node.component} references missing segment "${parent_id}"`);
}
});
}
current_route = current_route.parent;
}

if (parent_id !== undefined) {
throw new Error(`${current_node.component} references missing segment "${parent_id}"`);
}
});

const routes = Array.from(route_map.values()).sort((a, b) => compare(a, b, segment_map));

Expand Down
12 changes: 10 additions & 2 deletions packages/kit/src/core/sync/create_manifest_data/index.spec.js
Expand Up @@ -173,8 +173,16 @@ test('creates routes with layout', () => {

test('succeeds when routes does not exist', () => {
const { nodes, routes } = create('samples/basic/routes');
assert.equal(nodes, []);
assert.equal(routes, []);
assert.equal(nodes.map(simplify_node), [
{ component: 'layout.svelte' },
{ component: 'error.svelte' }
]);
assert.equal(routes.map(simplify_route), [
{
id: '',
pattern: '/^$/'
}
]);
});

// TODO some characters will need to be URL-encoded in the filename
Expand Down

0 comments on commit afba48c

Please sign in to comment.