@sveltejs/adapter-netlify 1.0.0-next.50 → 1.0.0-next.53
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/README.md +12 -4
- package/files/cjs/handler.js +6 -1
- package/files/esm/handler.js +6 -1
- package/index.d.ts +2 -1
- package/index.js +185 -87
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,10 +6,8 @@ If you're using [adapter-auto](../adapter-auto), you don't need to install this
|
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
9
|
-
> ⚠️ For the time being, the latest version of adapter-netlify is at the @next tag. If you get the error `config.kit.adapter should be an object with an "adapt" method.`, this is a sign that you are using the wrong version (eg `1.0.0-next.0` instead of `1.0.0-next.9`).
|
|
10
|
-
|
|
11
9
|
```bash
|
|
12
|
-
npm i -D @sveltejs/adapter-netlify
|
|
10
|
+
npm i -D @sveltejs/adapter-netlify
|
|
13
11
|
```
|
|
14
12
|
|
|
15
13
|
You can then configure it inside of `svelte.config.js`:
|
|
@@ -19,9 +17,15 @@ import adapter from '@sveltejs/adapter-netlify';
|
|
|
19
17
|
|
|
20
18
|
export default {
|
|
21
19
|
kit: {
|
|
20
|
+
// default options are shown
|
|
22
21
|
adapter: adapter({
|
|
22
|
+
// if true, will create a Netlify Edge Function rather
|
|
23
|
+
// than using standard Node-based functions
|
|
24
|
+
edge: false,
|
|
25
|
+
|
|
23
26
|
// if true, will split your app into multiple functions
|
|
24
|
-
// instead of creating a single one for the entire app
|
|
27
|
+
// instead of creating a single one for the entire app.
|
|
28
|
+
// if `edge` is true, this option cannot be used
|
|
25
29
|
split: false
|
|
26
30
|
})
|
|
27
31
|
}
|
|
@@ -38,6 +42,10 @@ Then, make sure you have a [netlify.toml](https://docs.netlify.com/configure-bui
|
|
|
38
42
|
|
|
39
43
|
If the `netlify.toml` file or the `build.publish` value is missing, a default value of `"build"` will be used. Note that if you have set the publish directory in the Netlify UI to something else then you will need to set it in `netlify.toml` too, or use the default value of `"build"`.
|
|
40
44
|
|
|
45
|
+
## Netlify Edge Functions (beta)
|
|
46
|
+
|
|
47
|
+
SvelteKit supports the beta release of Netlify Edge Functions. If you pass the option `edge: true` to the `adapter` function, server-side rendering will happen in a Deno-based edge function that's deployed close to the site visitor. If set to `false` (the default), the site will deploy to standard Node-based Netlify Functions.
|
|
48
|
+
|
|
41
49
|
## Netlify alternatives to SvelteKit functionality
|
|
42
50
|
|
|
43
51
|
You may build your app using functionality provided directly by SvelteKit without relying on any Netlify functionality. Using the SvelteKit versions of these features will allow them to be used in dev mode, tested with integration tests, and to work with other adapters should you ever decide to switch away from Netlify. However, in some scenarios you may find it beneficial to use the Netlify versions of these features. One example would be if you're migrating an app that's already hosted on Netlify to SvelteKit.
|
package/files/cjs/handler.js
CHANGED
|
@@ -50,7 +50,12 @@ function init(manifest) {
|
|
|
50
50
|
const server = new _0SERVER.Server(manifest);
|
|
51
51
|
|
|
52
52
|
return async (event, context) => {
|
|
53
|
-
const rendered = await server.respond(to_request(event), {
|
|
53
|
+
const rendered = await server.respond(to_request(event), {
|
|
54
|
+
platform: { context },
|
|
55
|
+
getClientAddress() {
|
|
56
|
+
return event.headers['x-nf-client-connection-ip'];
|
|
57
|
+
}
|
|
58
|
+
});
|
|
54
59
|
|
|
55
60
|
const partial_response = {
|
|
56
61
|
statusCode: rendered.status,
|
package/files/esm/handler.js
CHANGED
|
@@ -46,7 +46,12 @@ function init(manifest) {
|
|
|
46
46
|
const server = new Server(manifest);
|
|
47
47
|
|
|
48
48
|
return async (event, context) => {
|
|
49
|
-
const rendered = await server.respond(to_request(event), {
|
|
49
|
+
const rendered = await server.respond(to_request(event), {
|
|
50
|
+
platform: { context },
|
|
51
|
+
getClientAddress() {
|
|
52
|
+
return event.headers['x-nf-client-connection-ip'];
|
|
53
|
+
}
|
|
54
|
+
});
|
|
50
55
|
|
|
51
56
|
const partial_response = {
|
|
52
57
|
statusCode: rendered.status,
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { appendFileSync, existsSync, readFileSync, writeFileSync } from 'fs';
|
|
2
|
-
import { join, resolve } from 'path';
|
|
2
|
+
import { dirname, join, resolve, posix } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import glob from 'tiny-glob/sync.js';
|
|
5
5
|
import esbuild from 'esbuild';
|
|
@@ -12,10 +12,30 @@ import toml from '@iarna/toml';
|
|
|
12
12
|
* } & toml.JsonMap} NetlifyConfig
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {{
|
|
17
|
+
* functions: Array<
|
|
18
|
+
* | {
|
|
19
|
+
* function: string;
|
|
20
|
+
* path: string;
|
|
21
|
+
* }
|
|
22
|
+
* | {
|
|
23
|
+
* function: string;
|
|
24
|
+
* pattern: string;
|
|
25
|
+
* }
|
|
26
|
+
* >;
|
|
27
|
+
* version: 1;
|
|
28
|
+
* }} HandlerManifest
|
|
29
|
+
*/
|
|
30
|
+
|
|
15
31
|
const files = fileURLToPath(new URL('./files', import.meta.url).href);
|
|
32
|
+
const src = fileURLToPath(new URL('./src', import.meta.url).href);
|
|
33
|
+
const edgeSetInEnvVar =
|
|
34
|
+
process.env.NETLIFY_SVELTEKIT_USE_EDGE === 'true' ||
|
|
35
|
+
process.env.NETLIFY_SVELTEKIT_USE_EDGE === '1';
|
|
16
36
|
|
|
17
37
|
/** @type {import('.')} */
|
|
18
|
-
export default function ({ split = false } = {}) {
|
|
38
|
+
export default function ({ split = false, edge = edgeSetInEnvVar } = {}) {
|
|
19
39
|
return {
|
|
20
40
|
name: '@sveltejs/adapter-netlify',
|
|
21
41
|
|
|
@@ -26,97 +46,26 @@ export default function ({ split = false } = {}) {
|
|
|
26
46
|
const publish = get_publish_directory(netlify_config, builder) || 'build';
|
|
27
47
|
|
|
28
48
|
// empty out existing build directories
|
|
29
|
-
builder.rimraf(
|
|
49
|
+
builder.rimraf('.netlify/edge-functions');
|
|
30
50
|
builder.rimraf('.netlify/functions-internal');
|
|
31
51
|
builder.rimraf('.netlify/server');
|
|
32
52
|
builder.rimraf('.netlify/package.json');
|
|
33
53
|
builder.rimraf('.netlify/handler.js');
|
|
34
54
|
|
|
35
|
-
builder.mkdirp('.netlify/functions-internal');
|
|
36
|
-
|
|
37
55
|
builder.log.minor(`Publishing to "${publish}"`);
|
|
38
56
|
|
|
39
|
-
builder.writeServer('.netlify/server');
|
|
40
|
-
|
|
41
57
|
// for esbuild, use ESM
|
|
42
58
|
// for zip-it-and-ship-it, use CJS until https://github.com/netlify/zip-it-and-ship-it/issues/750
|
|
43
59
|
const esm = netlify_config?.functions?.node_bundler === 'esbuild';
|
|
44
60
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
'0SERVER': './server/index.js' // digit prefix prevents CJS build from using this as a variable name, which would also get replaced
|
|
50
|
-
};
|
|
61
|
+
if (edge) {
|
|
62
|
+
if (split) {
|
|
63
|
+
throw new Error('Cannot use `split: true` alongside `edge: true`');
|
|
64
|
+
}
|
|
51
65
|
|
|
52
|
-
|
|
53
|
-
builder.copy(`${files}/esm`, '.netlify', { replace });
|
|
66
|
+
await generate_edge_functions({ builder });
|
|
54
67
|
} else {
|
|
55
|
-
|
|
56
|
-
const filepath = `.netlify/server/${file}`;
|
|
57
|
-
const input = readFileSync(filepath, 'utf8');
|
|
58
|
-
const output = esbuild.transformSync(input, { format: 'cjs', target: 'node12' }).code;
|
|
59
|
-
writeFileSync(filepath, output);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
builder.copy(`${files}/cjs`, '.netlify', { replace });
|
|
63
|
-
writeFileSync(join('.netlify', 'package.json'), JSON.stringify({ type: 'commonjs' }));
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (split) {
|
|
67
|
-
builder.log.minor('Generating serverless functions...');
|
|
68
|
-
|
|
69
|
-
builder.createEntries((route) => {
|
|
70
|
-
const parts = [];
|
|
71
|
-
|
|
72
|
-
for (const segment of route.segments) {
|
|
73
|
-
if (segment.rest) {
|
|
74
|
-
parts.push('*');
|
|
75
|
-
break; // Netlify redirects don't allow anything after a *
|
|
76
|
-
} else if (segment.dynamic) {
|
|
77
|
-
parts.push(`:${parts.length}`);
|
|
78
|
-
} else {
|
|
79
|
-
parts.push(segment.content);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const pattern = `/${parts.join('/')}`;
|
|
84
|
-
const name = parts.join('-').replace(/[:.]/g, '_').replace('*', '__rest') || 'index';
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
id: pattern,
|
|
88
|
-
filter: (other) => matches(route.segments, other.segments),
|
|
89
|
-
complete: (entry) => {
|
|
90
|
-
const manifest = entry.generateManifest({
|
|
91
|
-
relativePath: '../server',
|
|
92
|
-
format: esm ? 'esm' : 'cjs'
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const fn = esm
|
|
96
|
-
? `import { init } from '../handler.js';\n\nexport const handler = init(${manifest});\n`
|
|
97
|
-
: `const { init } = require('../handler.js');\n\nexports.handler = init(${manifest});\n`;
|
|
98
|
-
|
|
99
|
-
writeFileSync(`.netlify/functions-internal/${name}.js`, fn);
|
|
100
|
-
|
|
101
|
-
redirects.push(`${pattern} /.netlify/functions/${name} 200`);
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
});
|
|
105
|
-
} else {
|
|
106
|
-
builder.log.minor('Generating serverless functions...');
|
|
107
|
-
|
|
108
|
-
const manifest = builder.generateManifest({
|
|
109
|
-
relativePath: '../server',
|
|
110
|
-
format: esm ? 'esm' : 'cjs'
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
const fn = esm
|
|
114
|
-
? `import { init } from '../handler.js';\n\nexport const handler = init(${manifest});\n`
|
|
115
|
-
: `const { init } = require('../handler.js');\n\nexports.handler = init(${manifest});\n`;
|
|
116
|
-
|
|
117
|
-
writeFileSync('.netlify/functions-internal/render.js', fn);
|
|
118
|
-
|
|
119
|
-
redirects.push('* /.netlify/functions/render 200');
|
|
68
|
+
await generate_lambda_functions({ builder, esm, split, publish });
|
|
120
69
|
}
|
|
121
70
|
|
|
122
71
|
builder.log.minor('Copying assets...');
|
|
@@ -124,11 +73,6 @@ export default function ({ split = false } = {}) {
|
|
|
124
73
|
builder.writeClient(publish);
|
|
125
74
|
builder.writePrerendered(publish);
|
|
126
75
|
|
|
127
|
-
builder.log.minor('Writing redirects...');
|
|
128
|
-
const redirect_file = join(publish, '_redirects');
|
|
129
|
-
builder.copy('_redirects', redirect_file);
|
|
130
|
-
appendFileSync(redirect_file, `\n\n${redirects.join('\n')}`);
|
|
131
|
-
|
|
132
76
|
builder.log.minor('Writing custom headers...');
|
|
133
77
|
const headers_file = join(publish, '_headers');
|
|
134
78
|
builder.copy('_headers', headers_file);
|
|
@@ -139,6 +83,160 @@ export default function ({ split = false } = {}) {
|
|
|
139
83
|
}
|
|
140
84
|
};
|
|
141
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* @param { object } params
|
|
88
|
+
* @param {import('@sveltejs/kit').Builder} params.builder
|
|
89
|
+
*/
|
|
90
|
+
async function generate_edge_functions({ builder }) {
|
|
91
|
+
// Don't match the static directory
|
|
92
|
+
const pattern = '^/.*$';
|
|
93
|
+
|
|
94
|
+
// Go doesn't support lookarounds, so we can't do this
|
|
95
|
+
// const pattern = appDir ? `^/(?!${escapeStringRegexp(appDir)}).*$` : '^/.*$';
|
|
96
|
+
|
|
97
|
+
/** @type {HandlerManifest} */
|
|
98
|
+
const edge_manifest = {
|
|
99
|
+
functions: [
|
|
100
|
+
{
|
|
101
|
+
function: 'render',
|
|
102
|
+
pattern
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
version: 1
|
|
106
|
+
};
|
|
107
|
+
const tmp = builder.getBuildDirectory('netlify-tmp');
|
|
108
|
+
|
|
109
|
+
builder.rimraf(tmp);
|
|
110
|
+
|
|
111
|
+
builder.mkdirp('.netlify/edge-functions');
|
|
112
|
+
|
|
113
|
+
builder.log.minor('Generating Edge Function...');
|
|
114
|
+
const relativePath = posix.relative(tmp, builder.getServerDirectory());
|
|
115
|
+
|
|
116
|
+
builder.copy(`${src}/edge_function.js`, `${tmp}/entry.js`, {
|
|
117
|
+
replace: {
|
|
118
|
+
'0SERVER': `${relativePath}/index.js`,
|
|
119
|
+
MANIFEST: './manifest.js'
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const manifest = builder.generateManifest({
|
|
124
|
+
relativePath
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
writeFileSync(
|
|
128
|
+
`${tmp}/manifest.js`,
|
|
129
|
+
`export const manifest = ${manifest};\n\nexport const prerendered = new Set(${JSON.stringify(
|
|
130
|
+
builder.prerendered.paths
|
|
131
|
+
)});\n`
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
await esbuild.build({
|
|
135
|
+
entryPoints: [`${tmp}/entry.js`],
|
|
136
|
+
outfile: '.netlify/edge-functions/render.js',
|
|
137
|
+
bundle: true,
|
|
138
|
+
format: 'esm',
|
|
139
|
+
target: 'es2020',
|
|
140
|
+
platform: 'browser'
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
writeFileSync('.netlify/edge-functions/manifest.json', JSON.stringify(edge_manifest));
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* @param { object } params
|
|
147
|
+
* @param {import('@sveltejs/kit').Builder} params.builder
|
|
148
|
+
* @param { string } params.publish
|
|
149
|
+
* @param { boolean } params.split
|
|
150
|
+
* @param { boolean } params.esm
|
|
151
|
+
*/
|
|
152
|
+
function generate_lambda_functions({ builder, publish, split, esm }) {
|
|
153
|
+
builder.mkdirp('.netlify/functions-internal');
|
|
154
|
+
|
|
155
|
+
/** @type {string[]} */
|
|
156
|
+
const redirects = [];
|
|
157
|
+
builder.writeServer('.netlify/server');
|
|
158
|
+
|
|
159
|
+
const replace = {
|
|
160
|
+
'0SERVER': './server/index.js' // digit prefix prevents CJS build from using this as a variable name, which would also get replaced
|
|
161
|
+
};
|
|
162
|
+
if (esm) {
|
|
163
|
+
builder.copy(`${files}/esm`, '.netlify', { replace });
|
|
164
|
+
} else {
|
|
165
|
+
glob('**/*.js', { cwd: '.netlify/server' }).forEach((file) => {
|
|
166
|
+
const filepath = `.netlify/server/${file}`;
|
|
167
|
+
const input = readFileSync(filepath, 'utf8');
|
|
168
|
+
const output = esbuild.transformSync(input, { format: 'cjs', target: 'node12' }).code;
|
|
169
|
+
writeFileSync(filepath, output);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
builder.copy(`${files}/cjs`, '.netlify', { replace });
|
|
173
|
+
writeFileSync(join('.netlify', 'package.json'), JSON.stringify({ type: 'commonjs' }));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (split) {
|
|
177
|
+
builder.log.minor('Generating serverless functions...');
|
|
178
|
+
|
|
179
|
+
builder.createEntries((route) => {
|
|
180
|
+
const parts = [];
|
|
181
|
+
// Netlify's syntax uses '*' and ':param' as "splats" and "placeholders"
|
|
182
|
+
// https://docs.netlify.com/routing/redirects/redirect-options/#splats
|
|
183
|
+
for (const segment of route.segments) {
|
|
184
|
+
if (segment.rest) {
|
|
185
|
+
parts.push('*');
|
|
186
|
+
break; // Netlify redirects don't allow anything after a *
|
|
187
|
+
} else if (segment.dynamic) {
|
|
188
|
+
parts.push(`:${parts.length}`);
|
|
189
|
+
} else {
|
|
190
|
+
parts.push(segment.content);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const pattern = `/${parts.join('/')}`;
|
|
195
|
+
const name = parts.join('-').replace(/[:.]/g, '_').replace('*', '__rest') || 'index';
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
id: pattern,
|
|
199
|
+
filter: (other) => matches(route.segments, other.segments),
|
|
200
|
+
complete: (entry) => {
|
|
201
|
+
const manifest = entry.generateManifest({
|
|
202
|
+
relativePath: '../server',
|
|
203
|
+
format: esm ? 'esm' : 'cjs'
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const fn = esm
|
|
207
|
+
? `import { init } from '../handler.js';\n\nexport const handler = init(${manifest});\n`
|
|
208
|
+
: `const { init } = require('../handler.js');\n\nexports.handler = init(${manifest});\n`;
|
|
209
|
+
|
|
210
|
+
writeFileSync(`.netlify/functions-internal/${name}.js`, fn);
|
|
211
|
+
|
|
212
|
+
redirects.push(`${pattern} /.netlify/functions/${name} 200`);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
});
|
|
216
|
+
} else {
|
|
217
|
+
builder.log.minor('Generating serverless functions...');
|
|
218
|
+
|
|
219
|
+
const manifest = builder.generateManifest({
|
|
220
|
+
relativePath: '../server',
|
|
221
|
+
format: esm ? 'esm' : 'cjs'
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const fn = esm
|
|
225
|
+
? `import { init } from '../handler.js';\n\nexport const handler = init(${manifest});\n`
|
|
226
|
+
: `const { init } = require('../handler.js');\n\nexports.handler = init(${manifest});\n`;
|
|
227
|
+
|
|
228
|
+
writeFileSync('.netlify/functions-internal/render.js', fn);
|
|
229
|
+
redirects.push('* /.netlify/functions/render 200');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
builder.log.minor('Writing redirects...');
|
|
233
|
+
const redirect_file = join(publish, '_redirects');
|
|
234
|
+
if (existsSync('_redirects')) {
|
|
235
|
+
builder.copy('_redirects', redirect_file);
|
|
236
|
+
}
|
|
237
|
+
builder.mkdirp(dirname(redirect_file));
|
|
238
|
+
appendFileSync(redirect_file, `\n\n${redirects.join('\n')}`);
|
|
239
|
+
}
|
|
142
240
|
|
|
143
241
|
function get_netlify_config() {
|
|
144
242
|
if (!existsSync('netlify.toml')) return null;
|
|
@@ -157,8 +255,8 @@ function get_netlify_config() {
|
|
|
157
255
|
**/
|
|
158
256
|
function get_publish_directory(netlify_config, builder) {
|
|
159
257
|
if (netlify_config) {
|
|
160
|
-
if (!netlify_config.build
|
|
161
|
-
builder.log.
|
|
258
|
+
if (!netlify_config.build?.publish) {
|
|
259
|
+
builder.log.minor('No publish directory specified in netlify.toml, using default');
|
|
162
260
|
return;
|
|
163
261
|
}
|
|
164
262
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltejs/adapter-netlify",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.53",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/sveltejs/kit",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@rollup/plugin-commonjs": "^21.0.0",
|
|
32
32
|
"@rollup/plugin-json": "^4.1.0",
|
|
33
33
|
"@rollup/plugin-node-resolve": "^13.0.5",
|
|
34
|
-
"@sveltejs/kit": "1.0.0-next.
|
|
34
|
+
"@sveltejs/kit": "1.0.0-next.318",
|
|
35
35
|
"rimraf": "^3.0.2",
|
|
36
36
|
"rollup": "^2.58.0",
|
|
37
37
|
"typescript": "^4.6.2",
|