Skip to content

Commit

Permalink
Merge branch 'master' into js-typechecking
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed Apr 15, 2022
2 parents 5c32844 + 6d67173 commit 16e4945
Show file tree
Hide file tree
Showing 20 changed files with 211 additions and 425 deletions.
5 changes: 5 additions & 0 deletions .changeset/breezy-mayflies-yawn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

Custom `load` `dependencies` in `LoadOutput`
12 changes: 12 additions & 0 deletions .changeset/few-walls-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@sveltejs/adapter-cloudflare-workers': patch
---

[Breaking] refactor implementation from "Service Worker" pattern to "Module Worker" used in adapter-cloudflare

#### add the following to your wrangler.toml
```toml
[build.upload]
format = "modules"
main = "./worker.mjs"
```
6 changes: 6 additions & 0 deletions documentation/docs/04-loading.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,9 @@ If the `load` function returns a `props` object, the props will be passed to the
This will be merged with any existing `stuff` and passed to the `load` functions of subsequent layout and page components.

The combined `stuff` is available to components using the [page store](/docs/modules#$app-stores) as `$page.stuff`, providing a mechanism for pages to pass data 'upward' to layouts.

#### dependencies

An array of strings representing URLs the page depends on, which can subsequently be used with [`invalidate`](/docs/modules#$app-navigation-invalidate) to cause `load` to rerun. You only need to add them to `dependencies` if you're using a custom API client; URLs loaded with the provided `fetch` function are added automatically.

URLs can be absolute or relative to the page being loaded, and must be [encoded](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding).
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,9 @@
"@svitejs/changesets-changelog-github-compact": "^0.1.1",
"@typescript-eslint/eslint-plugin": "^5.5.0",
"@typescript-eslint/parser": "^5.5.0",
"action-deploy-docs": "github:sveltejs/action-deploy-docs#main",
"eslint": "^8.3.0",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-svelte3": "^3.2.1",
"playwright-chromium": "^1.21.0",
"prettier": "^2.5.0",
"rollup": "^2.60.2",
"turbo": "^1.2.3",
Expand Down
8 changes: 6 additions & 2 deletions packages/adapter-cloudflare-workers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ Then configure your sites build directory and your account-details in the config
```toml
account_id = 'YOUR ACCOUNT_ID'
zone_id = 'YOUR ZONE_ID' # optional, if you don't specify this a workers.dev subdomain will be used.
site = {bucket = "./build", entry-point = "./workers-site"}

type = "javascript"

Expand All @@ -62,7 +61,12 @@ type = "javascript"
command = ""

[build.upload]
format = "service-worker"
format = "modules"
main = "./worker.mjs"

[site]
bucket = "./.cloudflare/assets"
entry-point = "./.cloudflare/worker"
```

It's recommended that you add the `build` and `workers-site` folders (or whichever other folders you specify) to your `.gitignore`.
Expand Down
8 changes: 3 additions & 5 deletions packages/adapter-cloudflare-workers/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ declare module 'MANIFEST' {
export const prerendered: Set<string>;
}

declare abstract class FetchEvent extends Event {
readonly request: Request;
respondWith(promise: Response | Promise<Response>): void;
passThroughOnException(): void;
waitUntil(promise: Promise<any>): void;
declare module '__STATIC_CONTENT_MANIFEST' {
const json: string;
export default json;
}
122 changes: 81 additions & 41 deletions packages/adapter-cloudflare-workers/files/entry.js
Original file line number Diff line number Diff line change
@@ -1,61 +1,101 @@
import { Server } from 'SERVER';
import { manifest, prerendered } from 'MANIFEST';
import { getAssetFromKV } from '@cloudflare/kv-asset-handler';
import static_asset_manifest_json from '__STATIC_CONTENT_MANIFEST';
const static_asset_manifest = JSON.parse(static_asset_manifest_json);

const server = new Server(manifest);

const prefix = `/${manifest.appDir}/`;

addEventListener('fetch', (/** @type {FetchEvent} */ event) => {
event.respondWith(handle(event));
});
export default {
/**
* @param {Request} req
* @param {any} env
* @param {any} context
*/
async fetch(req, env, context) {
const url = new URL(req.url);

/**
* @param {FetchEvent} event
* @returns {Promise<Response>}
*/
async function handle(event) {
const { request } = event;

const url = new URL(request.url);

// generated assets
if (url.pathname.startsWith(prefix)) {
const res = await getAssetFromKV(event);
return new Response(res.body, {
headers: {
'cache-control': 'public, immutable, max-age=31536000',
'content-type': res.headers.get('content-type')
// static assets
if (url.pathname.startsWith(prefix)) {
/** @type {Response} */
const res = await get_asset_from_kv(req, env, context);
if (is_error(res.status)) {
return res;
}
});
}
return new Response(res.body, {
headers: {
// include original cache headers, minus cache-control which
// is overridden, and etag which is no longer useful
'cache-control': 'public, immutable, max-age=31536000',
'content-type': res.headers.get('content-type'),
'x-robots-tag': 'noindex'
}
});
}

// prerendered pages and index.html files
const pathname = url.pathname.replace(/\/$/, '');
let file = pathname.substring(1);
// prerendered pages and index.html files
const pathname = url.pathname.replace(/\/$/, '');
let file = pathname.substring(1);

try {
file = decodeURIComponent(file);
} catch (err) {
// ignore
}
try {
file = decodeURIComponent(file);
} catch (err) {
// ignore
}

if (
manifest.assets.has(file) ||
manifest.assets.has(file + '/index.html') ||
prerendered.has(pathname || '/')
) {
return get_asset_from_kv(req, env, context);
}

if (
manifest.assets.has(file) ||
manifest.assets.has(file + '/index.html') ||
prerendered.has(pathname || '/')
) {
return await getAssetFromKV(event);
// dynamically-generated pages
try {
return await server.respond(req, {
platform: { env, context },
getClientAddress() {
return req.headers.get('cf-connecting-ip');
}
});
} catch (e) {
return new Response('Error rendering route: ' + (e.message || e.toString()), { status: 500 });
}
}
};

// dynamically-generated pages
/**
* @param {Request} req
* @param {any} env
* @param {any} context
*/
async function get_asset_from_kv(req, env, context) {
try {
return await server.respond(request, {
getClientAddress() {
return request.headers.get('cf-connecting-ip');
return await getAssetFromKV(
{
request: req,
waitUntil(promise) {
return context.waitUntil(promise);
}
},
{
ASSET_NAMESPACE: env.__STATIC_CONTENT,
ASSET_MANIFEST: static_asset_manifest
}
});
);
} catch (e) {
return new Response('Error rendering route:' + (e.message || e.toString()), { status: 500 });
const status = is_error(e.status) ? e.status : 500;
return new Response(e.message || e.toString(), { status });
}
}

/**
* @param {number} status
* @returns {boolean}
*/
function is_error(status) {
return status > 399;
}
58 changes: 52 additions & 6 deletions packages/adapter-cloudflare-workers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@ import toml from '@iarna/toml';
import { fileURLToPath } from 'url';

/** @type {import('.')} */
export default function () {
export default function (options = {}) {
return {
name: '@sveltejs/adapter-cloudflare-workers',

async adapt(builder) {
const { site } = validate_config(builder);
const { site, build } = validate_config(builder);

// @ts-ignore
const { bucket } = site;

// @ts-ignore
const entrypoint = site['entry-point'] || 'workers-site';

// @ts-ignore
const main_path = build.upload.main;

const files = fileURLToPath(new URL('./files', import.meta.url).href);
const tmp = builder.getBuildDirectory('cloudflare-workers-tmp');

Expand Down Expand Up @@ -50,14 +53,20 @@ export default function () {
);

await esbuild.build({
target: 'es2020',
platform: 'browser',
...options,
entryPoints: [`${tmp}/entry.js`],
outfile: `${entrypoint}/index.js`,
outfile: `${entrypoint}/${main_path}`,
bundle: true,
target: 'es2020',
platform: 'browser'
external: ['__STATIC_CONTENT_MANIFEST', ...(options?.external || [])],
format: 'esm'
});

writeFileSync(`${entrypoint}/package.json`, JSON.stringify({ main: 'index.js' }));
writeFileSync(
`${entrypoint}/package.json`,
JSON.stringify({ main: main_path, type: 'module' })
);

builder.log.minor('Copying assets...');
builder.writeClient(bucket);
Expand Down Expand Up @@ -86,6 +95,36 @@ function validate_config(builder) {
);
}

// @ts-ignore
if (!wrangler_config.build || !wrangler_config.build.upload) {
throw new Error(
'You must specify build.upload options in wrangler.toml. Consult https://github.com/sveltejs/kit/tree/master/packages/adapter-cloudflare-workers'
);
}

// @ts-ignore
if (wrangler_config.build.upload.format !== 'modules') {
throw new Error('build.upload.format in wrangler.toml must be "modules"');
}

// @ts-ignore
const main_file = wrangler_config.build?.upload?.main;
const main_file_ext = main_file?.split('.').slice(-1)[0];
if (main_file_ext && main_file_ext !== 'mjs') {
// @ts-ignore
const upload_rules = wrangler_config.build?.upload?.rules;
// @ts-ignore
const matching_rule = upload_rules?.find(({ globs }) =>
// @ts-ignore
globs.find((glob) => glob.endsWith(`*.${main_file_ext}`))
);
if (!matching_rule) {
throw new Error(
'To support a build.upload.main value not ending in .mjs, an upload rule must be added to build.upload.rules. Consult https://developers.cloudflare.com/workers/cli-wrangler/configuration/#build'
);
}
}

return wrangler_config;
}

Expand All @@ -104,6 +143,13 @@ function validate_config(builder) {
route = ""
zone_id = ""
[build]
command = ""
[build.upload]
format = "modules"
main = "./worker.mjs"
[site]
bucket = "./.cloudflare/assets"
entry-point = "./.cloudflare/worker"`
Expand Down
4 changes: 2 additions & 2 deletions packages/kit/.gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
.DS_Store
/node_modules
/dist
/assets/*
/client/**/*.d.ts
/dist
/docs
/test/**/.svelte-kit
/test/**/build
!/src/core/adapt/fixtures/*/.svelte-kit
Expand Down
4 changes: 3 additions & 1 deletion packages/kit/scripts/extract-types.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'fs';
import ts from 'typescript';
import prettier from 'prettier';
import { mkdirp } from '../src/utils/filesystem.js';

/** @typedef {{ name: string, comment: string, snippet: string }} Extracted */

Expand Down Expand Up @@ -126,8 +127,9 @@ modules.push({

modules.sort((a, b) => (a.name < b.name ? -1 : 1));

mkdirp('docs');
fs.writeFileSync(
'../../documentation/types.js',
'docs/types.js',
`
/* This file is generated by running \`node scripts/extract-types.js\`
in the packages/kit directory — do not edit it */
Expand Down
12 changes: 10 additions & 2 deletions packages/kit/src/runtime/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,12 @@ export function create_client({ target, session, base, trailing_slash }) {
stuff
};

/** @param dep {string} */
function add_dependency(dep) {
const { href } = new URL(dep, url);
node.uses.dependencies.add(href);
}

if (props) {
// shadow endpoint props means we need to mark this URL as a dependency of itself
node.uses.dependencies.add(url.href);
Expand Down Expand Up @@ -516,8 +522,7 @@ export function create_client({ target, session, base, trailing_slash }) {
},
fetch(resource, info) {
const requested = typeof resource === 'string' ? resource : resource.url;
const { href } = new URL(requested, url);
node.uses.dependencies.add(href);
add_dependency(requested);

return started ? fetch(resource, info) : initial_fetch(resource, info);
},
Expand All @@ -542,6 +547,9 @@ export function create_client({ target, session, base, trailing_slash }) {

node.loaded = normalize(loaded);
if (node.loaded.stuff) node.stuff = node.loaded.stuff;
if (node.loaded.dependencies) {
node.loaded.dependencies.forEach(add_dependency);
}
} else if (props) {
node.loaded = normalize({ props });
}
Expand Down
Loading

0 comments on commit 16e4945

Please sign in to comment.