@astrojs/cloudflare 0.0.0-cf-10-20240320162001 → 0.0.0-cf-10-solid-20240329084913
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/entrypoints/image-service.js +2 -1
- package/dist/entrypoints/server.advanced.d.ts +5 -5
- package/dist/entrypoints/server.advanced.js +7 -0
- package/dist/index.d.ts +35 -2
- package/dist/index.js +36 -37
- package/dist/utils/assets.d.ts +0 -5
- package/dist/utils/assets.js +1 -26
- package/dist/utils/generate-routes-json.d.ts +9 -0
- package/dist/utils/generate-routes-json.js +205 -0
- package/dist/utils/wasm-module-loader.d.ts +1 -2
- package/dist/utils/wasm-module-loader.js +5 -23
- package/package.json +11 -15
- package/dist/dev-toolbar-app/tabs.astro +0 -20
- package/dist/dev-toolbar-app/test.astro +0 -15
- package/dist/entrypoints/dev-toolbar-app.d.ts +0 -3
- package/dist/entrypoints/dev-toolbar-app.js +0 -36
- package/dist/utils/generate-routes.d.ts +0 -21
- package/dist/utils/generate-routes.js +0 -199
- package/dist/utils/index.d.ts +0 -2
- package/dist/utils/index.js +0 -10
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { joinPaths } from '@astrojs/internal-helpers/path';
|
|
1
2
|
import { baseService } from 'astro/assets';
|
|
2
|
-
import { isESMImportedImage, isRemoteAllowed
|
|
3
|
+
import { isESMImportedImage, isRemoteAllowed } from '../utils/assets.js';
|
|
3
4
|
const service = {
|
|
4
5
|
...baseService,
|
|
5
6
|
getURL: (options, imageConfig) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CacheStorage as
|
|
1
|
+
import type { CacheStorage as CLOUDFLARE_CACHESTORAGE, Request as CLOUDFLARE_REQUEST, ExecutionContext } from '@cloudflare/workers-types';
|
|
2
2
|
import type { SSRManifest } from 'astro';
|
|
3
3
|
type Env = {
|
|
4
4
|
ASSETS: {
|
|
@@ -6,17 +6,17 @@ type Env = {
|
|
|
6
6
|
};
|
|
7
7
|
ASTRO_STUDIO_APP_TOKEN?: string;
|
|
8
8
|
};
|
|
9
|
-
export interface
|
|
9
|
+
export interface Runtime<T extends object = object> {
|
|
10
10
|
runtime: {
|
|
11
11
|
waitUntil: (promise: Promise<any>) => void;
|
|
12
12
|
env: Env & T;
|
|
13
|
-
cf:
|
|
14
|
-
caches:
|
|
13
|
+
cf: CLOUDFLARE_REQUEST['cf'];
|
|
14
|
+
caches: CLOUDFLARE_CACHESTORAGE;
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
17
|
export declare function createExports(manifest: SSRManifest): {
|
|
18
18
|
default: {
|
|
19
|
-
fetch: (request: Request &
|
|
19
|
+
fetch: (request: Request & CLOUDFLARE_REQUEST, env: Env, context: ExecutionContext) => Promise<Response>;
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
22
|
export {};
|
|
@@ -8,6 +8,13 @@ export function createExports(manifest) {
|
|
|
8
8
|
return env.ASSETS.fetch(request.url.replace(/\.html$/, ''));
|
|
9
9
|
}
|
|
10
10
|
const routeData = app.match(request);
|
|
11
|
+
if (!routeData) {
|
|
12
|
+
// https://developers.cloudflare.com/pages/functions/api-reference/#envassetsfetch
|
|
13
|
+
const asset = await env.ASSETS.fetch(request.url.replace(/index.html$/, '').replace(/\.html$/, ''));
|
|
14
|
+
if (asset.status !== 404) {
|
|
15
|
+
return asset;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
11
18
|
Reflect.set(request, Symbol.for('astro.clientAddress'), request.headers.get('cf-connecting-ip'));
|
|
12
19
|
process.env.ASTRO_STUDIO_APP_TOKEN ??= (() => {
|
|
13
20
|
if (typeof env.ASTRO_STUDIO_APP_TOKEN === 'string') {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,48 @@
|
|
|
1
1
|
import type { AstroIntegration } from 'astro';
|
|
2
|
-
export type {
|
|
2
|
+
export type { Runtime } from './entrypoints/server.advanced.js';
|
|
3
3
|
export type Options = {
|
|
4
|
+
/** Options for handling images. */
|
|
4
5
|
imageService?: 'passthrough' | 'cloudflare' | 'compile';
|
|
5
|
-
|
|
6
|
+
/** Configuration for `_routes.json` generation. A _routes.json file controls when your Function is invoked. This file will include three different properties:
|
|
7
|
+
*
|
|
8
|
+
* - version: Defines the version of the schema. Currently there is only one version of the schema (version 1), however, we may add more in the future and aim to be backwards compatible.
|
|
9
|
+
* - include: Defines routes that will be invoked by Functions. Accepts wildcard behavior.
|
|
10
|
+
* - exclude: Defines routes that will not be invoked by Functions. Accepts wildcard behavior. `exclude` always take priority over `include`.
|
|
11
|
+
*
|
|
12
|
+
* Wildcards match any number of path segments (slashes). For example, `/users/*` will match everything after the `/users/` path.
|
|
13
|
+
*
|
|
14
|
+
*/
|
|
15
|
+
routes?: {
|
|
16
|
+
/** Extend `_routes.json` */
|
|
17
|
+
extend: {
|
|
18
|
+
/** Paths which should be routed to the SSR function */
|
|
19
|
+
include?: {
|
|
20
|
+
/** Generally this is in pathname format, but does support wildcards, e.g. `/users`, `/products/*` */
|
|
21
|
+
pattern: string;
|
|
22
|
+
}[];
|
|
23
|
+
/** Paths which should be routed as static assets */
|
|
24
|
+
exclude?: {
|
|
25
|
+
/** Generally this is in pathname format, but does support wildcards, e.g. `/static`, `/assets/*`, `/images/avatar.jpg` */
|
|
26
|
+
pattern: string;
|
|
27
|
+
}[];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Proxy configuration for the platform.
|
|
32
|
+
*/
|
|
6
33
|
platformProxy?: {
|
|
34
|
+
/** Toggle the proxy. Default `undefined`, which equals to `false`. */
|
|
7
35
|
enabled?: boolean;
|
|
36
|
+
/** Path to the configuration file. Default `wrangler.toml`. */
|
|
8
37
|
configPath?: string;
|
|
38
|
+
/** Enable experimental support for JSON configuration. Default `false`. */
|
|
9
39
|
experimentalJsonConfig?: boolean;
|
|
40
|
+
/** Configuration persistence settings. Default '.wrangler/state/v3' */
|
|
10
41
|
persist?: boolean | {
|
|
11
42
|
path: string;
|
|
12
43
|
};
|
|
13
44
|
};
|
|
45
|
+
/** Enable WebAssembly support */
|
|
46
|
+
wasmModuleImports?: boolean;
|
|
14
47
|
};
|
|
15
48
|
export default function createIntegration(args?: Options): AstroIntegration;
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { createReadStream } from 'node:fs';
|
|
2
2
|
import { appendFile, rename, stat } from 'node:fs/promises';
|
|
3
3
|
import { createInterface } from 'node:readline/promises';
|
|
4
|
-
import {
|
|
4
|
+
import { appendForwardSlash, prependForwardSlash, removeLeadingForwardSlash, } from '@astrojs/internal-helpers/path';
|
|
5
5
|
import { createRedirectsFromAstroRoutes } from '@astrojs/underscore-redirects';
|
|
6
6
|
import { AstroError } from 'astro/errors';
|
|
7
7
|
import { getPlatformProxy } from 'wrangler';
|
|
8
|
-
import {
|
|
9
|
-
import createRoutesFile, { getParts } from './utils/generate-routes.js';
|
|
8
|
+
import { createRoutesFile, getParts } from './utils/generate-routes-json.js';
|
|
10
9
|
import { setImageConfig } from './utils/image-config.js';
|
|
11
10
|
import { wasmModuleLoader } from './utils/wasm-module-loader.js';
|
|
12
11
|
export default function createIntegration(args) {
|
|
@@ -14,36 +13,24 @@ export default function createIntegration(args) {
|
|
|
14
13
|
return {
|
|
15
14
|
name: '@astrojs/cloudflare',
|
|
16
15
|
hooks: {
|
|
17
|
-
'astro:config:setup': ({ command, config, updateConfig, logger
|
|
16
|
+
'astro:config:setup': ({ command, config, updateConfig, logger }) => {
|
|
18
17
|
updateConfig({
|
|
19
18
|
build: {
|
|
20
|
-
client: new URL(`.${config.base}
|
|
19
|
+
client: new URL(`.${prependForwardSlash(appendForwardSlash(config.base))}`, config.outDir),
|
|
21
20
|
server: new URL('./_worker.js/', config.outDir),
|
|
22
21
|
serverEntry: 'index.js',
|
|
22
|
+
redirects: false,
|
|
23
23
|
},
|
|
24
24
|
vite: {
|
|
25
25
|
// load .wasm files as WebAssembly modules
|
|
26
26
|
plugins: [
|
|
27
27
|
wasmModuleLoader({
|
|
28
28
|
disabled: !args?.wasmModuleImports,
|
|
29
|
-
isHybrid: config.output === 'hybrid',
|
|
30
29
|
}),
|
|
31
30
|
],
|
|
32
31
|
},
|
|
33
32
|
image: setImageConfig(args?.imageService ?? 'DEFAULT', config.image, command, logger),
|
|
34
33
|
});
|
|
35
|
-
// MARK: Dev Toolbar App
|
|
36
|
-
if (command === 'dev') {
|
|
37
|
-
addDevToolbarApp('@astrojs/cloudflare/dev-toolbar-app');
|
|
38
|
-
injectRoute({
|
|
39
|
-
pattern: '/_dev-toolbar-app/cloudflare/tabs',
|
|
40
|
-
entrypoint: '@astrojs/cloudflare/dev-toolbar-app/tabs.astro',
|
|
41
|
-
});
|
|
42
|
-
injectRoute({
|
|
43
|
-
pattern: '/_dev-toolbar-app/cloudflare/home',
|
|
44
|
-
entrypoint: '@astrojs/cloudflare/dev-toolbar-app/test.astro',
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
34
|
},
|
|
48
35
|
'astro:config:done': ({ setAdapter, config }) => {
|
|
49
36
|
_config = config;
|
|
@@ -71,24 +58,21 @@ export default function createIntegration(args) {
|
|
|
71
58
|
},
|
|
72
59
|
});
|
|
73
60
|
},
|
|
74
|
-
'astro:server:setup': async ({ server
|
|
61
|
+
'astro:server:setup': async ({ server }) => {
|
|
75
62
|
if (args?.platformProxy?.enabled === true) {
|
|
76
|
-
const
|
|
63
|
+
const platformProxy = await getPlatformProxy({
|
|
77
64
|
configPath: args.platformProxy.configPath ?? 'wrangler.toml',
|
|
78
65
|
experimentalJsonConfig: args.platformProxy.experimentalJsonConfig ?? false,
|
|
79
66
|
persist: args.platformProxy.persist ?? true,
|
|
80
67
|
});
|
|
81
|
-
const tmpString = inspect(platform.env.D1);
|
|
82
|
-
console.log(tmpString);
|
|
83
|
-
console.log(platform.env.KV);
|
|
84
68
|
const clientLocalsSymbol = Symbol.for('astro.locals');
|
|
85
69
|
server.middlewares.use(async function middleware(req, res, next) {
|
|
86
70
|
Reflect.set(req, clientLocalsSymbol, {
|
|
87
71
|
runtime: {
|
|
88
|
-
env:
|
|
89
|
-
cf:
|
|
90
|
-
caches:
|
|
91
|
-
ctx:
|
|
72
|
+
env: platformProxy.env,
|
|
73
|
+
cf: platformProxy.cf,
|
|
74
|
+
caches: platformProxy.caches,
|
|
75
|
+
ctx: platformProxy.ctx,
|
|
92
76
|
},
|
|
93
77
|
});
|
|
94
78
|
next();
|
|
@@ -113,26 +97,41 @@ export default function createIntegration(args) {
|
|
|
113
97
|
vite.resolve.alias[alias.find] = alias.replacement;
|
|
114
98
|
}
|
|
115
99
|
}
|
|
100
|
+
vite.resolve.conditions ||= [];
|
|
101
|
+
vite.resolve.conditions.push('workerd', 'worker');
|
|
116
102
|
vite.ssr ||= {};
|
|
117
|
-
vite.ssr.noExternal = true;
|
|
118
|
-
vite.ssr.external = _config?.vite?.ssr?.external ?? [];
|
|
119
103
|
vite.ssr.target = 'webworker';
|
|
104
|
+
vite.ssr.noExternal = true;
|
|
105
|
+
vite.ssr.external = _config.vite.ssr?.external ?? [];
|
|
120
106
|
vite.build ||= {};
|
|
121
107
|
vite.build.rollupOptions ||= {};
|
|
122
108
|
vite.build.rollupOptions.output ||= {};
|
|
123
|
-
// @ts-
|
|
124
|
-
vite.build.rollupOptions.output.banner ||=
|
|
125
|
-
|
|
109
|
+
// @ts-expect-error
|
|
110
|
+
vite.build.rollupOptions.output.banner ||=
|
|
111
|
+
'globalThis.process ??= {}; globalThis.process.env ??= {};';
|
|
112
|
+
vite.build.rollupOptions.external = _config.vite.build?.rollupOptions?.external ?? [];
|
|
113
|
+
// Cloudflare env is only available per request. This isn't feasible for code that access env vars
|
|
114
|
+
// in a global way, so we shim their access as `process.env.*`. This is not the recommended way for users to access environment variables. But we'll add this for compatibility for chosen variables. Mainly to support `@astrojs/db`
|
|
115
|
+
vite.define = {
|
|
116
|
+
'process.env': 'process.env',
|
|
117
|
+
...vite.define,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
if (target === 'client') {
|
|
121
|
+
vite.resolve ||= {};
|
|
122
|
+
vite.resolve.conditions ||= [];
|
|
123
|
+
vite.resolve.conditions = vite.resolve.conditions.filter((c) => c !== 'workerd' && c !== 'worker');
|
|
126
124
|
}
|
|
127
125
|
},
|
|
128
|
-
'astro:build:done': async ({
|
|
126
|
+
'astro:build:done': async ({ pages, routes, dir, logger }) => {
|
|
127
|
+
const PLATFORM_FILES = ['_headers', '_redirects', '_routes.json'];
|
|
129
128
|
if (_config.base !== '/') {
|
|
130
|
-
for (const file of
|
|
129
|
+
for (const file of PLATFORM_FILES) {
|
|
131
130
|
try {
|
|
132
131
|
await rename(new URL(file, _config.build.client), new URL(file, _config.outDir));
|
|
133
132
|
}
|
|
134
133
|
catch (e) {
|
|
135
|
-
|
|
134
|
+
logger.error(`There was an error moving ${file} to the root of the output directory.`);
|
|
136
135
|
}
|
|
137
136
|
}
|
|
138
137
|
}
|
|
@@ -180,7 +179,7 @@ export default function createIntegration(args) {
|
|
|
180
179
|
routesExists = false;
|
|
181
180
|
}
|
|
182
181
|
if (!routesExists) {
|
|
183
|
-
await createRoutesFile(_config, routes, pages, redirects);
|
|
182
|
+
await createRoutesFile(_config, logger, routes, pages, redirects, args?.routes?.extend?.include, args?.routes?.extend?.exclude);
|
|
184
183
|
}
|
|
185
184
|
const redirectRoutes = [];
|
|
186
185
|
for (const route of routes) {
|
|
@@ -197,7 +196,7 @@ export default function createIntegration(args) {
|
|
|
197
196
|
await appendFile(new URL('./_redirects', _config.outDir), trueRedirects.print());
|
|
198
197
|
}
|
|
199
198
|
catch (error) {
|
|
200
|
-
|
|
199
|
+
logger.error('Failed to write _redirects file');
|
|
201
200
|
}
|
|
202
201
|
}
|
|
203
202
|
},
|
package/dist/utils/assets.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { AstroConfig, ImageMetadata, RemotePattern } from 'astro';
|
|
2
2
|
export declare function isESMImportedImage(src: ImageMetadata | string): src is ImageMetadata;
|
|
3
|
-
export declare function isRemotePath(src: string): boolean;
|
|
4
3
|
export declare function matchHostname(url: URL, hostname?: string, allowWildcard?: boolean): boolean;
|
|
5
4
|
export declare function matchPort(url: URL, port?: string): boolean;
|
|
6
5
|
export declare function matchProtocol(url: URL, protocol?: string): boolean;
|
|
@@ -8,7 +7,3 @@ export declare function matchPathname(url: URL, pathname?: string, allowWildcard
|
|
|
8
7
|
export declare function matchPattern(url: URL, remotePattern: RemotePattern): boolean;
|
|
9
8
|
export declare function isRemoteAllowed(src: string, { domains, remotePatterns, }: Partial<Pick<AstroConfig['image'], 'domains' | 'remotePatterns'>>): boolean;
|
|
10
9
|
export declare function isString(path: unknown): path is string;
|
|
11
|
-
export declare function removeTrailingForwardSlash(path: string): string;
|
|
12
|
-
export declare function removeLeadingForwardSlash(path: string): string;
|
|
13
|
-
export declare function trimSlashes(path: string): string;
|
|
14
|
-
export declare function joinPaths(...paths: (string | undefined)[]): string;
|
package/dist/utils/assets.js
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
|
+
import { isRemotePath } from '@astrojs/internal-helpers/path';
|
|
1
2
|
export function isESMImportedImage(src) {
|
|
2
3
|
return typeof src === 'object';
|
|
3
4
|
}
|
|
4
|
-
export function isRemotePath(src) {
|
|
5
|
-
return /^(http|ftp|https|ws):?\/\//.test(src) || src.startsWith('data:');
|
|
6
|
-
}
|
|
7
5
|
export function matchHostname(url, hostname, allowWildcard) {
|
|
8
6
|
if (!hostname) {
|
|
9
7
|
return true;
|
|
@@ -68,26 +66,3 @@ export function isRemoteAllowed(src, { domains = [], remotePatterns = [], }) {
|
|
|
68
66
|
export function isString(path) {
|
|
69
67
|
return typeof path === 'string' || path instanceof String;
|
|
70
68
|
}
|
|
71
|
-
export function removeTrailingForwardSlash(path) {
|
|
72
|
-
return path.endsWith('/') ? path.slice(0, path.length - 1) : path;
|
|
73
|
-
}
|
|
74
|
-
export function removeLeadingForwardSlash(path) {
|
|
75
|
-
return path.startsWith('/') ? path.substring(1) : path;
|
|
76
|
-
}
|
|
77
|
-
export function trimSlashes(path) {
|
|
78
|
-
return path.replace(/^\/|\/$/g, '');
|
|
79
|
-
}
|
|
80
|
-
export function joinPaths(...paths) {
|
|
81
|
-
return paths
|
|
82
|
-
.filter(isString)
|
|
83
|
-
.map((path, i) => {
|
|
84
|
-
if (i === 0) {
|
|
85
|
-
return removeTrailingForwardSlash(path);
|
|
86
|
-
}
|
|
87
|
-
if (i === paths.length - 1) {
|
|
88
|
-
return removeLeadingForwardSlash(path);
|
|
89
|
-
}
|
|
90
|
-
return trimSlashes(path);
|
|
91
|
-
})
|
|
92
|
-
.join('/');
|
|
93
|
-
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AstroConfig, AstroIntegrationLogger, RouteData, RoutePart } from 'astro';
|
|
2
|
+
export declare function getParts(part: string): RoutePart[];
|
|
3
|
+
export declare function createRoutesFile(_config: AstroConfig, logger: AstroIntegrationLogger, routes: RouteData[], pages: {
|
|
4
|
+
pathname: string;
|
|
5
|
+
}[], redirects: RouteData['segments'][], includeExtends: {
|
|
6
|
+
pattern: string;
|
|
7
|
+
}[] | undefined, excludeExtends: {
|
|
8
|
+
pattern: string;
|
|
9
|
+
}[] | undefined): Promise<void>;
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { writeFile } from 'node:fs/promises';
|
|
3
|
+
import { posix } from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { prependForwardSlash, removeLeadingForwardSlash, removeTrailingForwardSlash, } from '@astrojs/internal-helpers/path';
|
|
6
|
+
import glob from 'tiny-glob';
|
|
7
|
+
// Copied from https://github.com/withastro/astro/blob/3776ecf0aa9e08a992d3ae76e90682fd04093721/packages/astro/src/core/routing/manifest/create.ts#L45-L70
|
|
8
|
+
// We're not sure how to improve this regex yet
|
|
9
|
+
const ROUTE_DYNAMIC_SPLIT = /\[(.+?\(.+?\)|.+?)\]/;
|
|
10
|
+
const ROUTE_SPREAD = /^\.{3}.+$/;
|
|
11
|
+
export function getParts(part) {
|
|
12
|
+
const result = [];
|
|
13
|
+
part.split(ROUTE_DYNAMIC_SPLIT).map((str, i) => {
|
|
14
|
+
if (!str)
|
|
15
|
+
return;
|
|
16
|
+
const dynamic = i % 2 === 1;
|
|
17
|
+
const [, content] = dynamic ? /([^(]+)$/.exec(str) || [null, null] : [null, str];
|
|
18
|
+
if (!content || (dynamic && !/^(?:\.\.\.)?[\w$]+$/.test(content))) {
|
|
19
|
+
throw new Error('Parameter name must match /^[a-zA-Z0-9_$]+$/');
|
|
20
|
+
}
|
|
21
|
+
result.push({
|
|
22
|
+
content,
|
|
23
|
+
dynamic,
|
|
24
|
+
spread: dynamic && ROUTE_SPREAD.test(content),
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
async function writeRoutesFileToOutDir(_config, logger, include, exclude) {
|
|
30
|
+
try {
|
|
31
|
+
await writeFile(new URL('./_routes.json', _config.outDir), JSON.stringify({
|
|
32
|
+
version: 1,
|
|
33
|
+
include: include,
|
|
34
|
+
exclude: exclude,
|
|
35
|
+
}, null, 2), 'utf-8');
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
logger.error("There was an error writing the '_routes.json' file to the output directory.");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function segmentsToCfSyntax(segments, _config) {
|
|
42
|
+
const pathSegments = [];
|
|
43
|
+
if (removeLeadingForwardSlash(removeTrailingForwardSlash(_config.base)).length > 0) {
|
|
44
|
+
pathSegments.push(removeLeadingForwardSlash(removeTrailingForwardSlash(_config.base)));
|
|
45
|
+
}
|
|
46
|
+
for (const segment of segments.flat()) {
|
|
47
|
+
if (segment.dynamic)
|
|
48
|
+
pathSegments.push('*');
|
|
49
|
+
else
|
|
50
|
+
pathSegments.push(segment.content);
|
|
51
|
+
}
|
|
52
|
+
return pathSegments;
|
|
53
|
+
}
|
|
54
|
+
class TrieNode {
|
|
55
|
+
children = new Map();
|
|
56
|
+
isEndOfPath = false;
|
|
57
|
+
hasWildcardChild = false;
|
|
58
|
+
}
|
|
59
|
+
class PathTrie {
|
|
60
|
+
root;
|
|
61
|
+
constructor() {
|
|
62
|
+
this.root = new TrieNode();
|
|
63
|
+
}
|
|
64
|
+
insert(path) {
|
|
65
|
+
let node = this.root;
|
|
66
|
+
for (const segment of path) {
|
|
67
|
+
if (segment === '*') {
|
|
68
|
+
node.hasWildcardChild = true;
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
if (!node.children.has(segment)) {
|
|
72
|
+
node.children.set(segment, new TrieNode());
|
|
73
|
+
}
|
|
74
|
+
// biome-ignore lint/style/noNonNullAssertion: The `if` condition above ensures that the segment exists inside the map
|
|
75
|
+
node = node.children.get(segment);
|
|
76
|
+
}
|
|
77
|
+
node.isEndOfPath = true;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Depth-first search (dfs), traverses the "graph" segment by segment until the end or wildcard (*).
|
|
81
|
+
* It makes sure that all necessary paths are returned, but not paths with an existing wildcard prefix.
|
|
82
|
+
* e.g. if we have a path like /foo/* and /foo/bar, we only want to return /foo/*
|
|
83
|
+
*/
|
|
84
|
+
dfs(node, path, allPaths) {
|
|
85
|
+
if (node.hasWildcardChild) {
|
|
86
|
+
allPaths.push([...path, '*']);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (node.isEndOfPath) {
|
|
90
|
+
allPaths.push([...path]);
|
|
91
|
+
}
|
|
92
|
+
for (const [segment, childNode] of node.children) {
|
|
93
|
+
this.dfs(childNode, [...path, segment], allPaths);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
getAllPaths() {
|
|
97
|
+
const allPaths = [];
|
|
98
|
+
this.dfs(this.root, [], allPaths);
|
|
99
|
+
return allPaths;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export async function createRoutesFile(_config, logger, routes, pages, redirects, includeExtends, excludeExtends) {
|
|
103
|
+
const includePaths = [];
|
|
104
|
+
const excludePaths = [];
|
|
105
|
+
let hasPrerendered404 = false;
|
|
106
|
+
for (const route of routes) {
|
|
107
|
+
const convertedPath = segmentsToCfSyntax(route.segments, _config);
|
|
108
|
+
if (route.pathname === '/404' && route.prerender === true)
|
|
109
|
+
hasPrerendered404 = true;
|
|
110
|
+
switch (route.type) {
|
|
111
|
+
case 'page':
|
|
112
|
+
if (route.prerender === false)
|
|
113
|
+
includePaths.push(convertedPath);
|
|
114
|
+
break;
|
|
115
|
+
case 'endpoint':
|
|
116
|
+
if (route.prerender === false)
|
|
117
|
+
includePaths.push(convertedPath);
|
|
118
|
+
else
|
|
119
|
+
excludePaths.push(convertedPath);
|
|
120
|
+
break;
|
|
121
|
+
case 'redirect':
|
|
122
|
+
excludePaths.push(convertedPath);
|
|
123
|
+
break;
|
|
124
|
+
default:
|
|
125
|
+
/**
|
|
126
|
+
* We don't know the type, so we are conservative!
|
|
127
|
+
* Invoking the function on these is a safe-bet because
|
|
128
|
+
* the function will fallback to static asset fetching
|
|
129
|
+
*/
|
|
130
|
+
includePaths.push(convertedPath);
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
for (const page of pages) {
|
|
135
|
+
const pageSegments = removeLeadingForwardSlash(page.pathname)
|
|
136
|
+
.split(posix.sep)
|
|
137
|
+
.filter(Boolean)
|
|
138
|
+
.map((s) => {
|
|
139
|
+
return getParts(s);
|
|
140
|
+
});
|
|
141
|
+
excludePaths.push(segmentsToCfSyntax(pageSegments, _config));
|
|
142
|
+
}
|
|
143
|
+
if (existsSync(fileURLToPath(_config.publicDir))) {
|
|
144
|
+
const staticFiles = await glob(`${fileURLToPath(_config.publicDir)}/**/*`, {
|
|
145
|
+
cwd: fileURLToPath(_config.publicDir),
|
|
146
|
+
filesOnly: true,
|
|
147
|
+
dot: true,
|
|
148
|
+
});
|
|
149
|
+
for (const staticFile of staticFiles) {
|
|
150
|
+
if (['_headers', '_redirects', '_routes.json'].includes(staticFile))
|
|
151
|
+
continue;
|
|
152
|
+
const staticPath = staticFile;
|
|
153
|
+
const segments = removeLeadingForwardSlash(staticPath)
|
|
154
|
+
.split(posix.sep)
|
|
155
|
+
.filter(Boolean)
|
|
156
|
+
.map((s) => {
|
|
157
|
+
return getParts(s);
|
|
158
|
+
});
|
|
159
|
+
excludePaths.push(segmentsToCfSyntax(segments, _config));
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* All files in the `_config.build.assets` path, e.g. `_astro`
|
|
164
|
+
* are considered static assets and should not be handled by the function
|
|
165
|
+
* therefore we exclude a wildcard for that, e.g. `/_astro/*`
|
|
166
|
+
*/
|
|
167
|
+
const assetsPath = segmentsToCfSyntax([
|
|
168
|
+
[{ content: _config.build.assets, dynamic: false, spread: false }],
|
|
169
|
+
[{ content: '', dynamic: true, spread: false }],
|
|
170
|
+
], _config);
|
|
171
|
+
excludePaths.push(assetsPath);
|
|
172
|
+
for (const redirect of redirects) {
|
|
173
|
+
excludePaths.push(segmentsToCfSyntax(redirect, _config));
|
|
174
|
+
}
|
|
175
|
+
const includeTrie = new PathTrie();
|
|
176
|
+
for (const includePath of includePaths) {
|
|
177
|
+
includeTrie.insert(includePath);
|
|
178
|
+
}
|
|
179
|
+
const deduplicatedIncludePaths = includeTrie.getAllPaths();
|
|
180
|
+
const excludeTrie = new PathTrie();
|
|
181
|
+
for (const excludePath of excludePaths) {
|
|
182
|
+
excludeTrie.insert(excludePath);
|
|
183
|
+
}
|
|
184
|
+
const deduplicatedExcludePaths = excludeTrie.getAllPaths();
|
|
185
|
+
/**
|
|
186
|
+
* Cloudflare allows no more than 100 include/exclude rules combined
|
|
187
|
+
* https://developers.cloudflare.com/pages/functions/routing/#limits
|
|
188
|
+
*/
|
|
189
|
+
const CLOUDFLARE_COMBINED_LIMIT = 100;
|
|
190
|
+
if (!hasPrerendered404 ||
|
|
191
|
+
deduplicatedIncludePaths.length + (includeExtends?.length ?? 0) > CLOUDFLARE_COMBINED_LIMIT ||
|
|
192
|
+
deduplicatedExcludePaths.length + (excludeExtends?.length ?? 0) > CLOUDFLARE_COMBINED_LIMIT) {
|
|
193
|
+
await writeRoutesFileToOutDir(_config, logger, ['/*'].concat(includeExtends?.map((entry) => entry.pattern) ?? []), deduplicatedExcludePaths
|
|
194
|
+
.map((path) => `${prependForwardSlash(path.join('/'))}`)
|
|
195
|
+
.concat(excludeExtends?.map((entry) => entry.pattern) ?? [])
|
|
196
|
+
.slice(0, 99));
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
await writeRoutesFileToOutDir(_config, logger, deduplicatedIncludePaths
|
|
200
|
+
.map((path) => `${prependForwardSlash(path.join('/'))}`)
|
|
201
|
+
.concat(includeExtends?.map((entry) => entry.pattern) ?? []), deduplicatedExcludePaths
|
|
202
|
+
.map((path) => `${prependForwardSlash(path.join('/'))}`)
|
|
203
|
+
.concat(excludeExtends?.map((entry) => entry.pattern) ?? []));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -8,7 +8,6 @@ import type { AstroConfig } from 'astro';
|
|
|
8
8
|
* @param assetsDirectory - the folder name for the assets directory in the build directory. Usually '_astro'
|
|
9
9
|
* @returns Vite plugin to load WASM tagged with '?module' as a WASM modules
|
|
10
10
|
*/
|
|
11
|
-
export declare function wasmModuleLoader({ disabled,
|
|
11
|
+
export declare function wasmModuleLoader({ disabled, }: {
|
|
12
12
|
disabled: boolean;
|
|
13
|
-
isHybrid: boolean;
|
|
14
13
|
}): NonNullable<AstroConfig['vite']['plugins']>[number];
|
|
@@ -9,7 +9,7 @@ import * as path from 'node:path';
|
|
|
9
9
|
* @param assetsDirectory - the folder name for the assets directory in the build directory. Usually '_astro'
|
|
10
10
|
* @returns Vite plugin to load WASM tagged with '?module' as a WASM modules
|
|
11
11
|
*/
|
|
12
|
-
export function wasmModuleLoader({ disabled,
|
|
12
|
+
export function wasmModuleLoader({ disabled, }) {
|
|
13
13
|
const postfix = '.wasm?module';
|
|
14
14
|
let isDev = false;
|
|
15
15
|
return {
|
|
@@ -24,6 +24,7 @@ export function wasmModuleLoader({ disabled, isHybrid, }) {
|
|
|
24
24
|
assetsInclude: ['**/*.wasm?module'],
|
|
25
25
|
build: {
|
|
26
26
|
rollupOptions: {
|
|
27
|
+
// mark the wasm files as external so that they are not bundled and instead are loaded from the files
|
|
27
28
|
external: [/^__WASM_ASSET__.+\.wasm$/i, /^__WASM_ASSET__.+\.wasm.mjs$/i],
|
|
28
29
|
},
|
|
29
30
|
},
|
|
@@ -71,9 +72,10 @@ export function wasmModuleLoader({ disabled, isHybrid, }) {
|
|
|
71
72
|
return;
|
|
72
73
|
if (!/__WASM_ASSET__/g.test(code))
|
|
73
74
|
return;
|
|
75
|
+
const isPrerendered = Object.keys(chunk.modules).some((moduleId) => this.getModuleInfo(moduleId)?.meta?.astro?.pageOptions?.prerender === true);
|
|
74
76
|
let final = code;
|
|
75
77
|
// SSR
|
|
76
|
-
if (
|
|
78
|
+
if (!isPrerendered) {
|
|
77
79
|
final = code.replaceAll(/__WASM_ASSET__([A-Za-z\d]+).wasm.mjs/g, (s, assetId) => {
|
|
78
80
|
const fileName = this.getFileName(assetId).replace(/\.mjs$/, '');
|
|
79
81
|
const relativePath = path
|
|
@@ -82,28 +84,8 @@ export function wasmModuleLoader({ disabled, isHybrid, }) {
|
|
|
82
84
|
return `./${relativePath}`;
|
|
83
85
|
});
|
|
84
86
|
}
|
|
85
|
-
// SSR
|
|
86
|
-
if (!isHybrid && !chunk.exports.includes('prerender')) {
|
|
87
|
-
final = code.replaceAll(/__WASM_ASSET__([A-Za-z\d]+).wasm.mjs/g, (s, assetId) => {
|
|
88
|
-
const fileName = this.getFileName(assetId);
|
|
89
|
-
const relativePath = path
|
|
90
|
-
.relative(path.dirname(chunk.fileName), fileName)
|
|
91
|
-
.replaceAll('\\', '/'); // fix windows paths for import
|
|
92
|
-
return `./${relativePath}`;
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
// SSG
|
|
96
|
-
if (isHybrid && !chunk.exports.includes('prerender')) {
|
|
97
|
-
final = code.replaceAll(/__WASM_ASSET__([A-Za-z\d]+).wasm.mjs/g, (s, assetId) => {
|
|
98
|
-
const fileName = this.getFileName(assetId);
|
|
99
|
-
const relativePath = path
|
|
100
|
-
.relative(path.dirname(chunk.fileName), fileName)
|
|
101
|
-
.replaceAll('\\', '/'); // fix windows paths for import
|
|
102
|
-
return `./${relativePath}`;
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
87
|
// SSG
|
|
106
|
-
if (
|
|
88
|
+
if (isPrerendered) {
|
|
107
89
|
final = code.replaceAll(/__WASM_ASSET__([A-Za-z\d]+).wasm.mjs/g, (s, assetId) => {
|
|
108
90
|
const fileName = this.getFileName(assetId);
|
|
109
91
|
const relativePath = path
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/cloudflare",
|
|
3
3
|
"description": "Deploy your site to Cloudflare Workers/Pages",
|
|
4
|
-
"version": "0.0.0-cf-10-
|
|
4
|
+
"version": "0.0.0-cf-10-solid-20240329084913",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
7
|
"author": "withastro",
|
|
@@ -23,9 +23,6 @@
|
|
|
23
23
|
"./entrypoints/server.directory.js": "./dist/entrypoints/server.directory.js",
|
|
24
24
|
"./image-service": "./dist/entrypoints/image-service.js",
|
|
25
25
|
"./image-endpoint": "./dist/entrypoints/image-endpoint.js",
|
|
26
|
-
"./dev-toolbar-app": "./dist/entrypoints/dev-toolbar-app.js",
|
|
27
|
-
"./dev-toolbar-app/tabs.astro": "./dist/dev-toolbar-app/tabs.astro",
|
|
28
|
-
"./dev-toolbar-app/test.astro": "./dist/dev-toolbar-app/test.astro",
|
|
29
26
|
"./package.json": "./package.json"
|
|
30
27
|
},
|
|
31
28
|
"files": [
|
|
@@ -33,31 +30,30 @@
|
|
|
33
30
|
],
|
|
34
31
|
"dependencies": {
|
|
35
32
|
"@astrojs/underscore-redirects": "^0.3.3",
|
|
36
|
-
"@
|
|
37
|
-
"
|
|
38
|
-
"miniflare": "^3.
|
|
33
|
+
"@astrojs/internal-helpers": "0.3.0",
|
|
34
|
+
"@cloudflare/workers-types": "^4.20240320.1",
|
|
35
|
+
"miniflare": "^3.20240320.0",
|
|
36
|
+
"esbuild": "^0.19.5",
|
|
39
37
|
"tiny-glob": "^0.2.9",
|
|
40
|
-
"wrangler": "^3.
|
|
38
|
+
"wrangler": "^3.36.0"
|
|
41
39
|
},
|
|
42
40
|
"peerDependencies": {
|
|
43
41
|
"astro": "^4.2.0"
|
|
44
42
|
},
|
|
45
43
|
"devDependencies": {
|
|
46
|
-
"astro": "^4.5.7",
|
|
47
|
-
"cheerio": "1.0.0-rc.12",
|
|
48
44
|
"execa": "^8.0.1",
|
|
49
45
|
"fast-glob": "^3.3.2",
|
|
50
46
|
"strip-ansi": "^7.1.0",
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
47
|
+
"astro": "^4.5.8",
|
|
48
|
+
"cheerio": "1.0.0-rc.12",
|
|
49
|
+
"astro-scripts": "0.0.14",
|
|
50
|
+
"@astrojs/test-utils": "0.0.1"
|
|
55
51
|
},
|
|
56
52
|
"publishConfig": {
|
|
57
53
|
"provenance": true
|
|
58
54
|
},
|
|
59
55
|
"scripts": {
|
|
60
|
-
"build": "tsc
|
|
56
|
+
"build": "tsc",
|
|
61
57
|
"test": "astro-scripts test \"test/**/*.test.js\""
|
|
62
58
|
}
|
|
63
59
|
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
export const partial = true;
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
<div>
|
|
6
|
-
<button onclick="fetchHome(this)">Env</button>
|
|
7
|
-
<button>D1</button>
|
|
8
|
-
</div>
|
|
9
|
-
|
|
10
|
-
<script is:inline>
|
|
11
|
-
var fetchHome = function (element) {
|
|
12
|
-
console.log(element.getRootNode());
|
|
13
|
-
fetch('/_dev-toolbar-app/cloudflare/home')
|
|
14
|
-
.then((res) => res.text())
|
|
15
|
-
.then((html) => {
|
|
16
|
-
const el = document.createRange().createContextualFragment(html);
|
|
17
|
-
element.getRootNode().querySelector('#target').replaceChildren(el);
|
|
18
|
-
});
|
|
19
|
-
};
|
|
20
|
-
</script>
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
export const partial = true;
|
|
3
|
-
|
|
4
|
-
const { env } = Astro.locals.runtime;
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
<pre onclick="me(this)">
|
|
8
|
-
{JSON.stringify(env, null, 2)}
|
|
9
|
-
</pre>
|
|
10
|
-
|
|
11
|
-
<script is:inline>
|
|
12
|
-
var me = function (element) {
|
|
13
|
-
console.log('me');
|
|
14
|
-
};
|
|
15
|
-
</script>
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
const plugin = {
|
|
2
|
-
id: 'cloudflare-app',
|
|
3
|
-
name: 'Cloudflare DevToolbarApp',
|
|
4
|
-
icon: '<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24"><path fill="currentColor" d="M10.715 14.32H5.442l-.64-1.203L13.673 0l1.397.579-1.752 9.112h5.24l.648 1.192L10.719 24l-1.412-.54ZM4.091 5.448a.579.579 0 1 1 0-1.157.579.579 0 0 1 0 1.157m1.543 0a.579.579 0 1 1 0-1.157.579.579 0 0 1 0 1.157m1.544 0a.579.579 0 1 1 0-1.157.579.579 0 0 1 0 1.157m8.657-2.7h5.424l.772.771v16.975l-.772.772h-7.392l.374-.579h6.779l.432-.432V3.758l-.432-.432h-4.676l-.552 2.85h-.59l.529-2.877.108-.552ZM2.74 21.265l-.772-.772V3.518l.772-.771h7.677l-.386.579H2.98l-.432.432v16.496l.432.432h5.586l-.092.579zm1.157-1.93h3.28l-.116.58h-3.55l-.192-.193v-3.473l.578 1.158zm13.117 0 .579.58H14.7l.385-.58z"/></svg>',
|
|
5
|
-
init(canvas, eventTarget) {
|
|
6
|
-
const page = `
|
|
7
|
-
<script>
|
|
8
|
-
var loadTabs = function (element) {
|
|
9
|
-
console.log(this);
|
|
10
|
-
console.log(element);
|
|
11
|
-
fetch('/_dev-toolbar-app/cloudflare/tabs')
|
|
12
|
-
.then((res) => res.text())
|
|
13
|
-
.then((html) => {
|
|
14
|
-
const el = document.createRange().createContextualFragment(html);
|
|
15
|
-
element.getRootNode().querySelector('#tabs').replaceChildren(el);
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
</script>
|
|
19
|
-
<div id="tabs"></div>
|
|
20
|
-
<div id="target"></div>
|
|
21
|
-
`;
|
|
22
|
-
const pageEl = document.createRange().createContextualFragment(page);
|
|
23
|
-
const cfWindow = document.createElement('astro-dev-toolbar-window');
|
|
24
|
-
cfWindow.append(pageEl);
|
|
25
|
-
canvas.appendChild(cfWindow);
|
|
26
|
-
eventTarget.addEventListener('app-toggled', (event) => {
|
|
27
|
-
// @ts-ignore
|
|
28
|
-
if (event.detail.state === true) {
|
|
29
|
-
console.log('The app is now enabled!');
|
|
30
|
-
// @ts-ignore
|
|
31
|
-
loadTabs(cfWindow);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
export default plugin;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { AstroConfig, RouteData, RoutePart } from 'astro';
|
|
2
|
-
/**
|
|
3
|
-
* create _routes.json automatically
|
|
4
|
-
* two approaches:
|
|
5
|
-
* include everything and exclude static
|
|
6
|
-
* if 404 is not prerendered, we need to include everything
|
|
7
|
-
* include only ssr paths
|
|
8
|
-
* we want to use as much wildcards as possible
|
|
9
|
-
* assetsURL should be excluded via wildcard
|
|
10
|
-
* _workers.js dir should not be in the routes anyway (cause it is the server bundle)
|
|
11
|
-
* we would work based on routes (endpoint / page)
|
|
12
|
-
* static files should be based on src rather than dist
|
|
13
|
-
* static files should not include cloudflare special files
|
|
14
|
-
* we need forwardslash
|
|
15
|
-
* we need to add the base path
|
|
16
|
-
* redirects from _redirects should be excluded
|
|
17
|
-
*/
|
|
18
|
-
export declare const getParts: (part: string) => RoutePart[];
|
|
19
|
-
export default function (_config: AstroConfig, routes: RouteData[], pages: {
|
|
20
|
-
pathname: string;
|
|
21
|
-
}[], redirects: RoutePart[][][]): Promise<void>;
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'node:fs';
|
|
2
|
-
import { writeFile } from 'node:fs/promises';
|
|
3
|
-
import { posix } from 'node:path';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import glob from 'tiny-glob';
|
|
6
|
-
import { removeLeadingForwardSlash, removeTrailingForwardSlash } from './assets.js';
|
|
7
|
-
/**
|
|
8
|
-
* create _routes.json automatically
|
|
9
|
-
* two approaches:
|
|
10
|
-
* include everything and exclude static
|
|
11
|
-
* if 404 is not prerendered, we need to include everything
|
|
12
|
-
* include only ssr paths
|
|
13
|
-
* we want to use as much wildcards as possible
|
|
14
|
-
* assetsURL should be excluded via wildcard
|
|
15
|
-
* _workers.js dir should not be in the routes anyway (cause it is the server bundle)
|
|
16
|
-
* we would work based on routes (endpoint / page)
|
|
17
|
-
* static files should be based on src rather than dist
|
|
18
|
-
* static files should not include cloudflare special files
|
|
19
|
-
* we need forwardslash
|
|
20
|
-
* we need to add the base path
|
|
21
|
-
* redirects from _redirects should be excluded
|
|
22
|
-
*/
|
|
23
|
-
export const getParts = (part) => {
|
|
24
|
-
const result = [];
|
|
25
|
-
part.split(/\[(.+?\(.+?\)|.+?)\]/).map((str, i) => {
|
|
26
|
-
if (!str)
|
|
27
|
-
return;
|
|
28
|
-
const dynamic = i % 2 === 1;
|
|
29
|
-
const [, content] = dynamic ? /([^(]+)$/.exec(str) || [null, null] : [null, str];
|
|
30
|
-
if (!content || (dynamic && !/^(?:\.\.\.)?[\w$]+$/.test(content))) {
|
|
31
|
-
throw new Error('Parameter name must match /^[a-zA-Z0-9_$]+$/');
|
|
32
|
-
}
|
|
33
|
-
result.push({
|
|
34
|
-
content,
|
|
35
|
-
dynamic,
|
|
36
|
-
spread: dynamic && /^\.{3}.+$/.test(content),
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
return result;
|
|
40
|
-
};
|
|
41
|
-
const segmentsToCfSyntax = (segments, _config) => {
|
|
42
|
-
if (segments.length === 0)
|
|
43
|
-
return ['', ''];
|
|
44
|
-
const pathSegments = [removeLeadingForwardSlash(removeTrailingForwardSlash(_config.base))];
|
|
45
|
-
for (const segment of segments.flat()) {
|
|
46
|
-
if (segment.dynamic)
|
|
47
|
-
pathSegments.push('*');
|
|
48
|
-
else
|
|
49
|
-
pathSegments.push(segment.content);
|
|
50
|
-
}
|
|
51
|
-
return pathSegments;
|
|
52
|
-
};
|
|
53
|
-
const deduplicateInPlace = (element, index, paths) => {
|
|
54
|
-
const regexp = new RegExp(`${element.join('/').replace(/(\*\/)*\*$/g, '[*\\w\\/]+')}$`, 'gm');
|
|
55
|
-
for (let i = index + 1; i < paths.length; i++) {
|
|
56
|
-
if (regexp.test(paths[i].join('/'))) {
|
|
57
|
-
paths.splice(i, 1);
|
|
58
|
-
i--;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
const sort = (first, second) => {
|
|
63
|
-
// more segements should be sorted first
|
|
64
|
-
if (second.length > first.length)
|
|
65
|
-
return -1;
|
|
66
|
-
if (first.length > second.length)
|
|
67
|
-
return 1;
|
|
68
|
-
// equal amount of segments, sort by specifity
|
|
69
|
-
for (let i = 0; i < first.length; i++) {
|
|
70
|
-
// if segment is equal, continue with next segment
|
|
71
|
-
if (first[i] === second[i])
|
|
72
|
-
continue;
|
|
73
|
-
// wildcard segments should be sorted last
|
|
74
|
-
if (first[i] === '*' && second[i] !== '*')
|
|
75
|
-
return -1;
|
|
76
|
-
if (first[i] !== '*' && second[i] === '*')
|
|
77
|
-
return 1;
|
|
78
|
-
}
|
|
79
|
-
return 0;
|
|
80
|
-
};
|
|
81
|
-
export default async function (_config, routes, pages, redirects) {
|
|
82
|
-
const includePaths = [];
|
|
83
|
-
const excludePaths = [];
|
|
84
|
-
let hasPrerendered404 = false;
|
|
85
|
-
for (const route of routes) {
|
|
86
|
-
const convertedPath = segmentsToCfSyntax(route.segments, _config);
|
|
87
|
-
if (route.pathname === '/404' && route.prerender === true)
|
|
88
|
-
hasPrerendered404 = true;
|
|
89
|
-
if (route.type === 'page')
|
|
90
|
-
if (route.prerender === false)
|
|
91
|
-
includePaths.push(convertedPath);
|
|
92
|
-
if (route.type === 'endpoint')
|
|
93
|
-
if (route.prerender === false)
|
|
94
|
-
includePaths.push(convertedPath);
|
|
95
|
-
else
|
|
96
|
-
excludePaths.push(convertedPath);
|
|
97
|
-
if (route.type === 'redirect')
|
|
98
|
-
excludePaths.push(convertedPath);
|
|
99
|
-
}
|
|
100
|
-
for (const page of pages) {
|
|
101
|
-
const pageSegments = removeLeadingForwardSlash(page.pathname)
|
|
102
|
-
.split(posix.sep)
|
|
103
|
-
.filter(Boolean)
|
|
104
|
-
.map((s) => {
|
|
105
|
-
return getParts(s);
|
|
106
|
-
});
|
|
107
|
-
excludePaths.push(segmentsToCfSyntax(pageSegments, _config));
|
|
108
|
-
}
|
|
109
|
-
if (existsSync(fileURLToPath(_config.publicDir))) {
|
|
110
|
-
const staticFiles = await glob(`${fileURLToPath(_config.publicDir)}/**/*`, {
|
|
111
|
-
cwd: fileURLToPath(_config.publicDir),
|
|
112
|
-
filesOnly: true,
|
|
113
|
-
dot: true,
|
|
114
|
-
});
|
|
115
|
-
for (const staticFile of staticFiles) {
|
|
116
|
-
if (['_headers', '_redirects', '_routes.json'].includes(staticFile))
|
|
117
|
-
continue;
|
|
118
|
-
const staticPath = staticFile;
|
|
119
|
-
const segments = removeLeadingForwardSlash(staticPath)
|
|
120
|
-
.split(posix.sep)
|
|
121
|
-
.filter(Boolean)
|
|
122
|
-
.map((s) => {
|
|
123
|
-
return getParts(s);
|
|
124
|
-
});
|
|
125
|
-
excludePaths.push(segmentsToCfSyntax(segments, _config));
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
const assetsPath = segmentsToCfSyntax([
|
|
129
|
-
[{ content: _config.build.assets, dynamic: false, spread: false }],
|
|
130
|
-
[{ content: '', dynamic: true, spread: false }],
|
|
131
|
-
], _config);
|
|
132
|
-
excludePaths.push(assetsPath);
|
|
133
|
-
const pagefindPath = segmentsToCfSyntax([
|
|
134
|
-
[{ content: 'pagefind', dynamic: false, spread: false }],
|
|
135
|
-
[{ content: '', dynamic: true, spread: false }],
|
|
136
|
-
], _config);
|
|
137
|
-
excludePaths.push(pagefindPath);
|
|
138
|
-
for (const redirect of redirects) {
|
|
139
|
-
excludePaths.push(segmentsToCfSyntax(redirect, _config));
|
|
140
|
-
}
|
|
141
|
-
includePaths.sort(sort);
|
|
142
|
-
excludePaths.sort(sort);
|
|
143
|
-
console.log(includePaths);
|
|
144
|
-
console.log('---');
|
|
145
|
-
console.log(excludePaths);
|
|
146
|
-
for (const [index, element] of includePaths.entries()) {
|
|
147
|
-
deduplicateInPlace(element, index, includePaths);
|
|
148
|
-
}
|
|
149
|
-
for (const [index, element] of excludePaths.entries()) {
|
|
150
|
-
console.log(element);
|
|
151
|
-
deduplicateInPlace(element, index, excludePaths);
|
|
152
|
-
}
|
|
153
|
-
console.log('------');
|
|
154
|
-
console.log(includePaths);
|
|
155
|
-
console.log('---');
|
|
156
|
-
console.log(excludePaths);
|
|
157
|
-
console.log('------');
|
|
158
|
-
console.log('INCLUDE', includePaths.length);
|
|
159
|
-
console.log('---');
|
|
160
|
-
console.log('EXCLUDE', excludePaths.length);
|
|
161
|
-
if (!hasPrerendered404 ||
|
|
162
|
-
includePaths.length > 100 ||
|
|
163
|
-
includePaths.length > excludePaths.length) {
|
|
164
|
-
try {
|
|
165
|
-
await writeFile(new URL('./_routes.json', _config.outDir), JSON.stringify({
|
|
166
|
-
version: 1,
|
|
167
|
-
include: ['/*'],
|
|
168
|
-
exclude: excludePaths.map((path) => path.join('/')).slice(0, 99),
|
|
169
|
-
}, null, 2), 'utf-8');
|
|
170
|
-
}
|
|
171
|
-
catch (error) {
|
|
172
|
-
// TODO
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
else if (includePaths.length < excludePaths.length) {
|
|
176
|
-
try {
|
|
177
|
-
await writeFile(new URL('./_routes.json', _config.outDir), JSON.stringify({
|
|
178
|
-
version: 1,
|
|
179
|
-
include: includePaths.map((path) => path.join('/')),
|
|
180
|
-
exclude: [],
|
|
181
|
-
}, null, 2), 'utf-8');
|
|
182
|
-
}
|
|
183
|
-
catch (error) {
|
|
184
|
-
// TODO
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
try {
|
|
189
|
-
await writeFile(new URL('./_routes.json', _config.outDir), JSON.stringify({
|
|
190
|
-
version: 1,
|
|
191
|
-
include: ['/*'],
|
|
192
|
-
exclude: excludePaths.map((path) => path.join('/')).slice(0, 99),
|
|
193
|
-
}, null, 2), 'utf-8');
|
|
194
|
-
}
|
|
195
|
-
catch (error) {
|
|
196
|
-
// TODO
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
package/dist/utils/index.d.ts
DELETED
package/dist/utils/index.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export const isNode = typeof process === 'object' && Object.prototype.toString.call(process) === '[object process]';
|
|
2
|
-
export function getProcessEnvProxy() {
|
|
3
|
-
return new Proxy({}, {
|
|
4
|
-
get: (target, prop) => {
|
|
5
|
-
console.warn(
|
|
6
|
-
// NOTE: \0 prevents Vite replacement
|
|
7
|
-
`Unable to access \`import.meta\0.env.${prop.toString()}\` on initialization as the Cloudflare platform only provides the environment variables per request. Please move the environment variable access inside a function that's only called after a request has been received.`);
|
|
8
|
-
},
|
|
9
|
-
});
|
|
10
|
-
}
|