Skip to content

Commit af88239

Browse files
authored
[feat] use Netlify internal functions directory for generated functions (#2113)
1 parent ab37911 commit af88239

File tree

9 files changed

+63
-30
lines changed

9 files changed

+63
-30
lines changed

.changeset/brave-clouds-protect.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/adapter-netlify': patch
3+
---
4+
5+
Deploy generated Netlify entrypoint to the internal functions directory. This allows it to co-exist with other Netlify functions.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ yarn.lock
1111
.svelte-kit
1212
.cloudflare
1313
.pnpm-debug.log
14+
.netlify

examples/hn.svelte.dev/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
node_modules
33
/.svelte
44
/build
5-
/functions
5+
/.netlify/functions*

examples/hn.svelte.dev/.netlify/netlify-plugin-pnpm/index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
export default {
1+
module.exports = {
22
onPreBuild: async ({ utils: { build, run } }) => {
33
try {
44
await run.command("npm install -g pnpm")
5-
await run.command("pnpm install")
5+
await run.command("pnpm -w install")
6+
await run.command("pnpm -w build")
67
} catch (error) {
78
return build.failBuild(error)
89
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"type":"commonjs"}

examples/hn.svelte.dev/netlify.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
[build]
22
command = "npm run build"
3-
publish = ".svelte-kit/netlify/build/"
4-
functions = ".svelte-kit/netlify/functions/"
3+
publish = "build"
54

65
[build.environment]
76
NPM_FLAGS="--prefix=/dev/null"

packages/adapter-netlify/README.md

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,16 @@ export default {
2727
};
2828
```
2929

30-
Then, make sure you have a [netlify.toml](https://docs.netlify.com/configure-builds/file-based-configuration) file in the project root. This will determine where to write static assets and functions to based on the `build.publish` and `build.functions` settings, as per this sample configuration:
30+
Then, make sure you have a [netlify.toml](https://docs.netlify.com/configure-builds/file-based-configuration) file in the project root. This will determine where to write static assets based on the `build.publish` settings, as per this sample configuration:
3131

3232
```toml
3333
[build]
3434
command = "npm run build"
35-
publish = "build/publish/"
36-
functions = "build/functions/"
35+
publish = "build"
3736
```
3837

38+
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"`.
39+
3940
## Netlify alternatives to SvelteKit functionality
4041

4142
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.
@@ -53,6 +54,20 @@ During compilation a required "catch all" redirect rule is automatically appende
5354
2. Netlify's build bot parses your HTML files at deploy time, which means your form must be [prerendered](https://kit.svelte.dev/docs#ssr-and-javascript-prerender) as HTML. You can either add `export const prerender = true` to your `contact.svelte` to prerender just that page or set the `kit.prerender.force: true` option to prerender all pages.
5455
3. If your Netlify form has a [custom success message](https://docs.netlify.com/forms/setup/#success-messages) like `<form netlify ... action="/success">` then ensure the corresponding `/routes/success.svelte` exists and is prerendered.
5556

57+
### Using Netlify Functions
58+
59+
[Netlify Functions](https://docs.netlify.com/functions/overview/) can be used alongside your SvelteKit routes. If you would like to add them to your site, you should create a directory for them and add the configuration to your `netlify.toml` file. For example:
60+
61+
```toml
62+
[build]
63+
command = "npm run build"
64+
publish = "build"
65+
66+
[functions]
67+
directory = "functions"
68+
node_bundler = "esbuild"
69+
```
70+
5671
## Advanced Configuration
5772

5873
### esbuild
@@ -77,7 +92,8 @@ The default options for this version are as follows:
7792
```js
7893
{
7994
entryPoints: ['.svelte-kit/netlify/entry.js'],
80-
outfile: `pathToFunctionsFolder/render/index.js`,
95+
// This is Netlify's internal functions directory, not the one for user functions.
96+
outfile: '.netlify/functions-internal/__render.js',
8197
bundle: true,
8298
inject: ['pathTo/shims.js'],
8399
platform: 'node'

packages/adapter-netlify/index.js

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { appendFileSync, existsSync, readFileSync, writeFileSync } from 'fs';
2-
import { join } from 'path';
2+
import { join, resolve } from 'path';
33
import { fileURLToPath } from 'url';
44
import esbuild from 'esbuild';
55
import toml from '@iarna/toml';
@@ -19,10 +19,12 @@ export default function (options) {
1919
name: '@sveltejs/adapter-netlify',
2020

2121
async adapt({ utils }) {
22-
const { publish, functions } = validate_config().build;
22+
// "build" is the default publish directory when Netlify detects SvelteKit
23+
const publish = get_publish_directory(utils) || 'build';
24+
25+
utils.log.minor(`Publishing to "${publish}"`);
2326

2427
utils.rimraf(publish);
25-
utils.rimraf(functions);
2628

2729
const files = fileURLToPath(new URL('./files', import.meta.url));
2830

@@ -32,7 +34,9 @@ export default function (options) {
3234
/** @type {BuildOptions} */
3335
const defaultOptions = {
3436
entryPoints: ['.svelte-kit/netlify/entry.js'],
35-
outfile: join(functions, 'render/index.js'),
37+
// Any functions in ".netlify/functions-internal" are bundled in addition to user-defined Netlify functions.
38+
// See https://github.com/netlify/build/pull/3213 for more details
39+
outfile: '.netlify/functions-internal/__render.js',
3640
bundle: true,
3741
inject: [join(files, 'shims.js')],
3842
platform: 'node'
@@ -43,9 +47,9 @@ export default function (options) {
4347

4448
await esbuild.build(buildOptions);
4549

46-
writeFileSync(join(functions, 'package.json'), JSON.stringify({ type: 'commonjs' }));
50+
writeFileSync(join('.netlify', 'package.json'), JSON.stringify({ type: 'commonjs' }));
4751

48-
utils.log.info('Prerendering static pages...');
52+
utils.log.minor('Prerendering static pages...');
4953
await utils.prerender({
5054
dest: publish
5155
});
@@ -55,16 +59,21 @@ export default function (options) {
5559
utils.copy_client_files(publish);
5660

5761
utils.log.minor('Writing redirects...');
58-
utils.copy('_redirects', `${publish}/_redirects`);
59-
appendFileSync(`${publish}/_redirects`, '\n\n/* /.netlify/functions/render 200');
62+
63+
const redirectPath = join(publish, '_redirects');
64+
utils.copy('_redirects', redirectPath);
65+
appendFileSync(redirectPath, '\n\n/* /.netlify/functions/__render 200');
6066
}
6167
};
6268

6369
return adapter;
6470
}
65-
66-
function validate_config() {
71+
/**
72+
* @param {import('@sveltejs/kit').AdapterUtils} utils
73+
**/
74+
function get_publish_directory(utils) {
6775
if (existsSync('netlify.toml')) {
76+
/** @type {{ build?: { publish?: string }} & toml.JsonMap } */
6877
let netlify_config;
6978

7079
try {
@@ -74,23 +83,25 @@ function validate_config() {
7483
throw err;
7584
}
7685

77-
if (!netlify_config.build || !netlify_config.build.publish || !netlify_config.build.functions) {
78-
throw new Error(
79-
'You must specify build.publish and build.functions in netlify.toml. Consult https://github.com/sveltejs/kit/tree/master/packages/adapter-netlify#configuration'
80-
);
86+
if (!netlify_config.build || !netlify_config.build.publish) {
87+
utils.log.warn('No publish directory specified in netlify.toml, using default');
88+
return;
8189
}
8290

8391
if (netlify_config.redirects) {
8492
throw new Error(
8593
"Redirects are not supported in netlify.toml. Use _redirects instead. For more details consult the readme's troubleshooting section."
8694
);
8795
}
88-
89-
return netlify_config;
96+
if (resolve(netlify_config.build.publish) === process.cwd()) {
97+
throw new Error(
98+
'The publish directory cannot be set to the site root. Please change it to another value such as "build" in netlify.toml.'
99+
);
100+
}
101+
return netlify_config.build.publish;
90102
}
91103

92-
// TODO offer to create one?
93-
throw new Error(
94-
'Missing a netlify.toml file. Consult https://github.com/sveltejs/kit/tree/master/packages/adapter-netlify#configuration'
104+
utils.log.warn(
105+
'No netlify.toml found. Using default publish directory. Consult https://github.com/sveltejs/kit/tree/master/packages/adapter-netlify#configuration for more details '
95106
);
96107
}
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
[build]
22
command = "npm run build"
3-
publish = ".svelte-kit/netlify/build/"
4-
functions = ".svelte-kit/netlify/functions/"
3+
publish = "build"

0 commit comments

Comments
 (0)