-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Expand file tree
/
Copy pathutils.js
More file actions
165 lines (141 loc) · 5.33 KB
/
utils.js
File metadata and controls
165 lines (141 loc) · 5.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import process from 'node:process';
/**
* @param {import('wrangler').Unstable_Config} wrangler_config
* @returns {boolean}
*/
export function is_building_for_cloudflare_pages(wrangler_config) {
if (process.env.CF_PAGES || wrangler_config.pages_build_output_dir) {
return true;
}
if (wrangler_config.main || wrangler_config.assets) {
return false;
}
return true;
}
/**
* @param {import('wrangler').Unstable_Config} wrangler_config
*/
export function validate_worker_settings(wrangler_config) {
const config_path = wrangler_config.configPath || 'your wrangler.jsonc file';
// we don't support workers sites
if (wrangler_config.site) {
throw new Error(
`You must remove all \`site\` keys in ${config_path}. Consult https://svelte.dev/docs/kit/adapter-cloudflare#Migrating-from-Workers-Sites`
);
}
// we need the `assets.directory` key so that the static assets are deployed
if ((wrangler_config.main || wrangler_config.assets) && !wrangler_config.assets?.directory) {
throw new Error(
`You must specify the \`assets.directory\` key in ${config_path}. Consult https://developers.cloudflare.com/workers/static-assets/binding/#directory`
);
}
// we need the `assets.binding` key so that the Worker can access the static assets
if (wrangler_config.main && !wrangler_config.assets?.binding) {
throw new Error(
`You must specify the \`assets.binding\` key in ${config_path} before deploying your Worker. Consult https://developers.cloudflare.com/workers/static-assets/binding/#binding`
);
}
// the user might have forgot the `main` key or should remove the `assets.binding`
// key to deploy static assets without a Worker
if (!wrangler_config.main && wrangler_config.assets?.binding) {
throw new Error(
`You must specify the \`main\` key in ${config_path} if you want to deploy a Worker alongside your static assets. Otherwise, remove the \`assets.binding\` key if you only want to deploy static assets.`
);
}
}
/**
* Extracts the redirect source from each line of a [_redirects](https://developers.cloudflare.com/pages/configuration/redirects/)
* file so we can exclude them in [_routes.json](https://developers.cloudflare.com/pages/functions/routing/#create-a-_routesjson-file)
* to ensure the redirect is invoked instead of the Cloudflare Worker.
* @param {string} file_contents
* @returns {string[]}
*/
export function parse_redirects(file_contents) {
/** @type {string[]} */
const redirects = [];
for (const line of file_contents.split('\n')) {
const content = line.trim();
if (!content || content.startsWith('#')) continue;
const [pathname] = line.split(' ');
// pathnames with placeholders are not supported
if (!pathname || pathname.includes('/:')) {
throw new Error(`The following _redirects rule cannot be excluded by _routes.json: ${line}`);
}
redirects.push(pathname);
}
return redirects;
}
/**
* Generates the [_routes.json](https://developers.cloudflare.com/pages/functions/routing/#create-a-_routesjson-file)
* file that dictates which routes invoke the Cloudflare Worker.
* @param {Builder2_0_0} builder
* @param {string[]} client_assets
* @param {string[]} redirects
* @param {import('./index.js').AdapterOptions['routes']} routes
* @returns {import('./index.js').RoutesJSONSpec}
*/
export function get_routes_json(builder, client_assets, redirects, routes) {
const include = routes?.include ?? ['/*'];
let exclude = routes?.exclude ?? ['<all>'];
if (!Array.isArray(include) || !Array.isArray(exclude)) {
throw new Error('routes.include and routes.exclude must be arrays');
}
if (include?.length === 0) {
throw new Error('routes.include must contain at least one route');
}
if (include?.length > 100) {
throw new Error('routes.include must contain 100 or fewer routes');
}
/** @type {Set<string>} */
const transformed_rules = new Set();
for (const rule of exclude) {
if (rule === '<all>') {
transformed_rules.add('<build>');
transformed_rules.add('<files>');
transformed_rules.add('<prerendered>');
transformed_rules.add('<redirects>');
} else {
transformed_rules.add(rule);
}
}
/** @type {Set<string>} */
const excluded_routes = new Set();
for (const rule of transformed_rules) {
if (rule === '<build>') {
const app_path = builder.getAppPath();
excluded_routes.add(`/${app_path}/version.json`);
excluded_routes.add(`/${app_path}/immutable/*`);
continue;
}
if (rule === '<files>') {
for (const file of client_assets) {
if (file.startsWith(`${builder.config.kit.appDir}/`)) continue;
excluded_routes.add(`${builder.config.kit.paths.base}/${file}`);
}
continue;
}
if (rule === '<prerendered>') {
builder.prerendered.paths.forEach((path) => excluded_routes.add(path));
continue;
}
if (rule === '<redirects>') {
redirects.forEach((path) => excluded_routes.add(path));
continue;
}
excluded_routes.add(rule);
}
exclude = Array.from(excluded_routes);
const excess = include.length + exclude.length - 100;
if (excess > 0) {
builder.log.warn(
`Cloudflare Pages Functions' includes/excludes exceeds _routes.json limits (see https://developers.cloudflare.com/pages/platform/functions/routing/#limits). Dropping ${excess} exclude rules — this will cause unnecessary function invocations.`
);
exclude.length -= excess;
}
return {
version: 1,
description: 'Generated by @sveltejs/adapter-cloudflare',
include,
exclude
};
}