Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

first crack at adapter-auto #2867

Merged
merged 12 commits into from
Nov 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/popular-schools-guess.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@sveltejs/adapter-auto': patch
'create-svelte': patch
---

Add adapter-auto
98 changes: 76 additions & 22 deletions documentation/docs/10-adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,99 @@
title: Adapters
---

Before you can deploy your SvelteKit app, you need to _adapt_ it for your deployment target. Adapters are small plugins that take the built app as input and generate output for deployment. Many adapters are optimised for a specific hosting provider, and you can generally find information about deployment in your adapter's documentation. However, some adapters, like `adapter-static`, build output that can be hosted on numerous hosting providers, so it may also be helpful to reference the documentation of your hosting provider in these cases.
Before you can deploy your SvelteKit app, you need to _adapt_ it for your deployment target. Adapters are small plugins that take the built app as input and generate output for deployment.

For example, if you want to run your app as a simple Node server, you would use the `@sveltejs/adapter-node@next` package:
By default, projects are configured to use `@sveltejs/adapter-auto`, which detects your production environment and selects the appropriate adapter where possible. If your platform isn't (yet) supported, you may need to [install a custom adapter](#adapters-installing-custom-adapters) or [write one](#adapters-writing-custom-adapters).

```js
> See the [adapter-auto README](https://github.com/sveltejs/kit/tree/master/packages/adapter-auto) for information on adding support for new environments.

### Supported environments

The following platforms are officially supported and require no additional configuration:

- [Cloudflare Pages](https://developers.cloudflare.com/pages/) via [`adapter-cloudflare`](https://github.com/sveltejs/kit/tree/master/packages/adapter-cloudflare)
- [Netlify](https://netlify.com) via [`adapter-netlify`](https://github.com/sveltejs/kit/tree/master/packages/adapter-netlify)
- [Vercel](https://vercel.com) via [`adapter-vercel`](https://github.com/sveltejs/kit/tree/master/packages/adapter-vercel)

### Installing custom adapters

Additional [community-provided adapters](https://sveltesociety.dev/components#adapters) exist for other platforms. After installing the relevant adapter with your package manager, update your `svelte.config.js`:

```diff
// svelte.config.js
import node from '@sveltejs/adapter-node';
-import adapter from '@sveltejs/adapter-auto';
+import adapter from 'svelte-adapter-[x]';
```

export default {
kit: {
adapter: node()
}
};
### Building a Node app

To create a simple Node server, install the `@sveltejs/adapter-node@next` package and update your `svelte.config.js`:

```diff
// svelte.config.js
-import adapter from '@sveltejs/adapter-auto';
+import adapter from '@sveltejs/adapter-node';
```

With this, [svelte-kit build](#command-line-interface-svelte-kit-build) will generate a self-contained Node app inside `build`. You can pass options to adapters, such as customising the output directory in `adapter-node`:
With this, [svelte-kit build](#command-line-interface-svelte-kit-build) will generate a self-contained Node app inside the `build` directory. You can pass options to adapters, such as customising the output directory:

```diff
// svelte.config.js
import node from '@sveltejs/adapter-node';
import adapter from '@sveltejs/adapter-node';

export default {
kit: {
- adapter: node()
+ adapter: node({ out: 'my-output-directory' })
- adapter: adapter()
+ adapter: adapter({ out: 'my-output-directory' })
}
};
```

A variety of official adapters exist for serverless platforms...
### Creating a static site

Most adapters will generate static HTML for any [prerenderable](#ssr-and-javascript-prerender) pages of your site. In some cases, your entire app might be prerenderable, in which case you can use `@sveltejs/adapter-static@next` to generate static HTML for _all_ your pages. A fully static site can be hosted on a wide variety of platforms, including static hosts like [GitHub Pages](https://pages.github.com/).

```diff
// svelte.config.js
-import adapter from '@sveltejs/adapter-auto';
+import adapter from '@sveltejs/adapter-static';
```

You can also use `adapter-static` to generate single-page apps (SPAs) by specifying a [fallback page](https://github.com/sveltejs/kit/tree/master/packages/adapter-static#spa-mode).

### Writing custom adapters

We recommend [looking at the source for an adapter](https://github.com/sveltejs/kit/tree/master/packages) to a platform similar to yours and copying it as a starting point.

Adapters packages must implement the following API, which creates an `Adapter`:

```js
/** @param {AdapterSpecificOptions} options */
export default function (options) {
/** @type {import('@sveltejs/kit').Adapter} */
return {
name: 'adapter-package-name',
async adapt({ utils, config }) {
// adapter implementation
}
};
}
```

The types for `Adapter` and its parameters are available in [types/config.d.ts](https://github.com/sveltejs/kit/blob/master/packages/kit/types/config.d.ts).

- [`adapter-cloudflare`](https://github.com/sveltejs/kit/tree/master/packages/adapter-cloudflare) — for [Cloudflare Pages](https://developers.cloudflare.com/pages/)
- [`adapter-cloudflare-workers`](https://github.com/sveltejs/kit/tree/master/packages/adapter-cloudflare-workers) — for [Cloudflare Workers](https://developers.cloudflare.com/workers/)
- [`adapter-netlify`](https://github.com/sveltejs/kit/tree/master/packages/adapter-netlify) — for [Netlify](https://netlify.com)
- [`adapter-vercel`](https://github.com/sveltejs/kit/tree/master/packages/adapter-vercel) — for [Vercel](https://vercel.com)
Within the `adapt` method, there are a number of things that an adapter should do:

...and traditional platforms:
- Clear out the build directory
- Output code that:
- Imports `init` and `render` from `.svelte-kit/output/server/app.js`
- Calls `init`, which configures the app
- Listens for requests from the platform, converts them to a a [SvelteKit request](#hooks-handle), calls the `render` function to generate a [SvelteKit response](#hooks-handle) and responds with it
- Globally shims `fetch` to work on the target platform, if necessary. SvelteKit provides a `@sveltejs/kit/install-fetch` helper for platforms that can use `node-fetch`
- Bundle the output to avoid needing to install dependencies on the target platform, if desired
- Call `utils.prerender`
- Put the user's static files and the generated JS/CSS in the correct location for the target platform

- [`adapter-node`](https://github.com/sveltejs/kit/tree/master/packages/adapter-node) — for creating self-contained Node apps
- [`adapter-static`](https://github.com/sveltejs/kit/tree/master/packages/adapter-static) — for prerendering your entire site as a collection of static files
If possible, we recommend putting the adapter output under the `build/` directory with any intermediate output placed under `.svelte-kit/[adapter-name]`.

As well as [community-provided adapters](https://sveltesociety.dev/components#adapters). You may also [write your own adapter](#writing-an-adapter).
> The adapter API may change before 1.0.
37 changes: 0 additions & 37 deletions documentation/docs/80-adapter-api.md

This file was deleted.

2 changes: 2 additions & 0 deletions packages/adapter-auto/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.DS_Store
node_modules
19 changes: 19 additions & 0 deletions packages/adapter-auto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# adapter-auto

Automatically chooses the adapter for your current environment, if possible.

## Supported environments

The following environments are supported out-of-the-box, meaning a newly created project can be deployed on one of these platforms without any additional configuration:

- [Cloudflare Pages](https://developers.cloudflare.com/pages/) via [adapter-cloudflare](../adapter-cloudflare)
- [Netlify](https://netlify.com/) via [adapter-netlify](../adapter-netlify)
- [Vercel](https://vercel.com/) via [adapter-vercel](../adapter-vercel)

## Community adapters

Support for additional environments can be added in [adapters.js](adapters.js). To avoid this package ballooning in size, community-supported adapters should not be added as dependencies — adapter-auto will instead prompt users to install missing packages as needed.

## Changelog

[The Changelog for this package is available on GitHub](https://github.com/sveltejs/kit/blob/master/packages/adapter-auto/CHANGELOG.md).
17 changes: 17 additions & 0 deletions packages/adapter-auto/adapters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export const adapters = [
{
name: 'Vercel',
test: () => !!process.env.VERCEL,
module: '@sveltejs/adapter-vercel'
},
{
name: 'Netlify',
test: () => !!process.env.NETLIFY,
module: '@sveltejs/adapter-netlify'
},
{
name: 'Cloudflare Pages',
test: () => !!process.env.CF_PAGES,
module: '@sveltejs/adapter-cloudflare'
}
];
4 changes: 4 additions & 0 deletions packages/adapter-auto/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Adapter } from '@sveltejs/kit';

declare function plugin(): Adapter;
export = plugin;
42 changes: 42 additions & 0 deletions packages/adapter-auto/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { adapters } from './adapters.js';

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

async adapt(options) {
for (const candidate of adapters) {
if (candidate.test()) {
options.utils.log.info(
`Detected environment: \u001B[1m\u001B[92m${candidate.name}\u001B[39m\u001B[22m. Using ${candidate.module}`
);

let module;

try {
module = await import(candidate.module);
} catch (error) {
if (
error.code === 'ERR_MODULE_NOT_FOUND' &&
error.message.startsWith(`Cannot find package '${candidate.module}'`)
) {
throw new Error(
`It looks like ${candidate.module} is not installed. Please install it and try building your project again.`
);
}

throw error;
}

const adapter = module.default();
return adapter.adapt(options);
}
}

options.utils.log.warn(
'Could not detect a supported production environment. See https://kit.svelte.dev/docs#adapters to learn how to configure your app to run on the platform of your choosing'
);
}
};
}
33 changes: 33 additions & 0 deletions packages/adapter-auto/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "@sveltejs/adapter-auto",
"version": "1.0.0-next",
"repository": {
"type": "git",
"url": "https://github.com/sveltejs/kit",
"directory": "packages/adapter-auto"
},
"homepage": "https://kit.svelte.dev",
"type": "module",
"exports": {
".": {
"import": "./index.js"
},
"./package.json": "./package.json"
},
"main": "index.js",
"types": "index.d.ts",
"files": [
"files",
"index.d.ts"
],
"scripts": {
"lint": "eslint --ignore-path .gitignore \"**/*.{ts,js,svelte}\" && npm run check-format",
"format": "npm run check-format -- --write",
"check-format": "prettier --check . --config ../../.prettierrc --ignore-path .gitignore"
},
"dependencies": {
Rich-Harris marked this conversation as resolved.
Show resolved Hide resolved
"@sveltejs/adapter-cloudflare": "workspace:*",
"@sveltejs/adapter-netlify": "workspace:*",
"@sveltejs/adapter-vercel": "workspace:*"
}
}
2 changes: 2 additions & 0 deletions packages/create-svelte/templates/default/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ node_modules
/.svelte-kit
/package
.env
.vercel
.output
6 changes: 2 additions & 4 deletions packages/create-svelte/templates/default/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
"start": "svelte-kit start"
},
"devDependencies": {
"@sveltejs/adapter-cloudflare-workers": "next",
"@sveltejs/adapter-netlify": "next",
"@sveltejs/adapter-vercel": "next",
"@sveltejs/kit": "next",
"@sveltejs/adapter-auto": "workspace:*",
"@sveltejs/kit": "workspace:*",
"svelte": "^3.44.0",
"svelte-preprocess": "^4.9.8",
"typescript": "^4.4.3"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"preview": "svelte-kit preview"
},
"devDependencies": {
"@sveltejs/adapter-auto": "workspace:*",
"@sveltejs/kit": "workspace:*",
"svelte": "^3.34.0"
},
Expand Down
10 changes: 3 additions & 7 deletions packages/create-svelte/templates/default/svelte.config.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
import adapter from '@sveltejs/adapter-auto';
import preprocess from 'svelte-preprocess';

const adapter = process.env.ADAPTER;
const options = JSON.parse(process.env.OPTIONS || '{}');

/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://github.com/sveltejs/svelte-preprocess
// for more information about preprocessors
preprocess: preprocess(),

kit: {
adapter: adapter(),

// hydrate the <div id="svelte"> element in src/app.html
target: '#svelte'
}
};

if (adapter) {
config.kit.adapter = (await import(adapter)).default(options);
}

export default config;
7 changes: 2 additions & 5 deletions packages/create-svelte/templates/skeleton/svelte.config.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import node from '@sveltejs/adapter-node';
import adapter from '@sveltejs/adapter-auto';

/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {
// By default, `npm run build` will create a standard Node app.
// You can create optimized builds for different platforms by
// specifying a different adapter
adapter: node(),
adapter: adapter(),

// hydrate the <div id="svelte"> element in src/app.html
target: '#svelte'
Expand Down
Loading