Skip to content

Commit

Permalink
this feels clunky
Browse files Browse the repository at this point in the history
  • Loading branch information
dummdidumm committed Feb 2, 2023
1 parent 5c66287 commit b3b1b6e
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 38 deletions.
59 changes: 33 additions & 26 deletions packages/adapter-vercel/index.js
Expand Up @@ -31,11 +31,11 @@ const plugin = function ({ external = [], edge, split, ...default_config } = {})

/**
* @param {string} name
* @param {string} pattern
* @param {string[]} patterns
* @param {import('.').Config | undefined} config
* @param {(options: { relativePath: string }) => string} generate_manifest
*/
async function generate_serverless_function(name, pattern, config, generate_manifest) {
async function generate_serverless_function(name, patterns, config, generate_manifest) {
const relativePath = path.posix.relative(tmp, builder.getServerDirectory());

builder.copy(`${files}/serverless.js`, `${tmp}/index.js`, {
Expand All @@ -58,16 +58,18 @@ const plugin = function ({ external = [], edge, split, ...default_config } = {})
config
);

static_config.routes.push({ src: pattern, dest: `/${name}` });
for (const pattern of patterns) {
static_config.routes.push({ src: pattern, dest: `/${name}` });
}
}

/**
* @param {string} name
* @param {string} pattern
* @param {string[]} patterns
* @param {import('.').Config | undefined} config
* @param {(options: { relativePath: string }) => string} generate_manifest
*/
async function generate_edge_function(name, pattern, config, generate_manifest) {
async function generate_edge_function(name, patterns, config, generate_manifest) {
const tmp = builder.getBuildDirectory(`vercel-tmp/${name}`);
const relativePath = path.posix.relative(tmp, builder.getServerDirectory());

Expand Down Expand Up @@ -104,7 +106,9 @@ const plugin = function ({ external = [], edge, split, ...default_config } = {})
})
);

static_config.routes.push({ src: pattern, dest: `/${name}` });
for (const pattern of patterns) {
static_config.routes.push({ src: pattern, dest: `/${name}` });
}
}

if (split || builder.hasRouteLevelConfig) {
Expand All @@ -113,31 +117,34 @@ const plugin = function ({ external = [], edge, split, ...default_config } = {})
return {
id: route.pattern.toString(), // TODO is `id` necessary?
filter: (other) =>
split
? route.pattern.toString() === other.pattern.toString()
: can_group(route_config, { ...default_config, ...other.config }),
(!split && !builder.hasRouteLevelConfig) ||
route.pattern.toString() === other.pattern.toString(),
group: (other) => can_group(route_config, { ...default_config, ...other.config }),
complete: async (entry) => {
let sliced_pattern = route.pattern
.toString()
// remove leading / and trailing $/
.slice(1, -2)
// replace escaped \/ with /
.replace(/\\\//g, '/');

// replace the root route "^/" with "^/?"
if (sliced_pattern === '^/') {
sliced_pattern = '^/?';
}

const src = `${sliced_pattern}(?:/__data.json)?$`; // TODO adding /__data.json is a temporary workaround — those endpoints should be treated as distinct routes
const patterns = entry.routes.map((route) => {
let sliced_pattern = route.pattern
.toString()
// remove leading / and trailing $/
.slice(1, -2)
// replace escaped \/ with /
.replace(/\\\//g, '/');

// replace the root route "^/" with "^/?"
if (sliced_pattern === '^/') {
sliced_pattern = '^/?';
}

return `${sliced_pattern}(?:/__data.json)?$`;
});

const generate_function =
edge && (!route_config.runtime || route_config.runtime === 'edge')
(edge && !route_config.runtime) || route_config.runtime === 'edge'
? generate_edge_function
: generate_serverless_function;

await generate_function(
route.id.slice(1) || 'index',
src,
patterns,
route_config,
entry.generateManifest
);
Expand All @@ -146,7 +153,7 @@ const plugin = function ({ external = [], edge, split, ...default_config } = {})
});
} else {
const generate_function = edge ? generate_edge_function : generate_serverless_function;
await generate_function('render', '/.*', default_config, builder.generateManifest);
await generate_function('render', ['/.*'], default_config, builder.generateManifest);
}

builder.log.minor('Copying assets...');
Expand Down Expand Up @@ -373,8 +380,8 @@ async function create_function_bundle(builder, entry, dir, runtime, config) {
write(
`${dir}/.vc-config.json`,
JSON.stringify({
runtime,
...config,
runtime: config?.runtime === 'serverless' || !config?.runtime ? runtime : config.runtime,
handler: path.relative(base + ancestor, entry),
launcherType: 'Nodejs'
})
Expand Down
33 changes: 25 additions & 8 deletions packages/kit/src/core/adapt/builder.js
Expand Up @@ -76,40 +76,57 @@ export function create_builder({ config, build_data, server_metadata, routes, pr
});

const seen = new Set();
const grouped = new Set();
let ungrouped = facades.map((f, i) => ({ r: routes[i], f }));

for (let i = 0; i < routes.length; i += 1) {
const route = routes[i];
const { id, filter, complete } = fn(facades[i]);
const { id, filter, complete, group } = fn(facades[i]);

if (seen.has(id)) continue;
if (seen.has(id) || grouped.has(route)) continue;
seen.add(id);

const group = [route];
const filtered = new Set([route]);
const route_definitions = new Set([facades[i]]);

if (group) {
ungrouped = ungrouped.filter((candidate) => {
if (group(candidate.f)) {
filtered.add(candidate.r);
route_definitions.add(candidate.f);
grouped.add(candidate.r);
return false;
}
return true;
});
}

// figure out which lower priority routes should be considered fallbacks
for (let j = i + 1; j < routes.length; j += 1) {
if (filter(facades[j])) {
group.push(routes[j]);
if (!group && filter(facades[j])) {
filtered.add(routes[j]);
route_definitions.add(facades[j]);
}
}

const filtered = new Set(group);

// heuristic: if /foo/[bar] is included, /foo/[bar].json should
// also be included, since the page likely needs the endpoint
// TODO is this still necessary, given the new way of doing things?
filtered.forEach((route) => {
if (route.page) {
const endpoint = routes.find((candidate) => candidate.id === route.id + '.json');
const idx = routes.findIndex((candidate) => candidate.id === route.id + '.json');
const endpoint = routes[idx];

if (endpoint) {
filtered.add(endpoint);
route_definitions.add(facades[idx]);
}
}
});

if (filtered.size > 0) {
await complete({
routes: Array.from(route_definitions),
generateManifest: ({ relativePath }) =>
generate_manifest({
build_data,
Expand Down
20 changes: 16 additions & 4 deletions packages/kit/types/private.d.ts
Expand Up @@ -11,20 +11,32 @@ export interface AdapterEntry {
id: string;

/**
* A function that compares the candidate route with the current route to determine
* if it should be grouped with the current route.
* A function that compares the lower candidate route with the current route to determine
* if it should be grouped with the current route. Has no effect when `group` is set.
*
* Use cases:
* - Fallback pages: `/foo/[c]` is a fallback for `/foo/a-[b]`, and `/[...catchall]` is a fallback for all routes
* - Grouping routes that share a common `config`: `/foo` should be deployed to the edge, `/bar` and `/baz` should be deployed to a serverless function
*/
filter(route: RouteDefinition): boolean;

/**
* A function that compares the candidate route with the current route to determine
* if it should be grouped with the current route. In contrast to `filter`, this
* results in the other route not being invoked by `createEntries` again, if grouped.
*
* Use cases:
* - Grouping routes that share a common `config`: `/foo` should be deployed to the edge, `/bar` and `/baz` should be deployed to a serverless function
*/
group?(route: RouteDefinition): boolean;

/**
* A function that is invoked once the entry has been created. This is where you
* should write the function to the filesystem and generate redirect manifests.
*/
complete(entry: { generateManifest(opts: { relativePath: string }): string }): MaybePromise<void>;
complete(entry: {
routes: RouteDefinition[];
generateManifest(opts: { relativePath: string }): string;
}): MaybePromise<void>;
}

// Based on https://github.com/josh-hemphill/csp-typed-directives/blob/latest/src/csp.types.ts
Expand Down

0 comments on commit b3b1b6e

Please sign in to comment.