From e228bbc6467c5e261be926ba958ca5b752c87bb8 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 5 Aug 2021 16:21:56 +0100 Subject: [PATCH 1/7] [feat] allow Netlify functions to coexist --- .changeset/brave-clouds-protect.md | 5 +++++ .gitignore | 1 + examples/hn.svelte.dev/.gitignore | 3 ++- .../.netlify/netlify-plugin-pnpm/index.js | 5 +++-- .../.netlify/netlify-plugin-pnpm/package.json | 1 + examples/hn.svelte.dev/netlify.toml | 5 ++++- packages/adapter-netlify/README.md | 5 ++--- packages/adapter-netlify/index.js | 17 +++++++++-------- 8 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 .changeset/brave-clouds-protect.md create mode 100644 examples/hn.svelte.dev/.netlify/netlify-plugin-pnpm/package.json diff --git a/.changeset/brave-clouds-protect.md b/.changeset/brave-clouds-protect.md new file mode 100644 index 000000000000..d7714173f895 --- /dev/null +++ b/.changeset/brave-clouds-protect.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-netlify': patch +--- + +Deploy generated Netlify entrypoint to the internal functions directory. This allows it to co-exist with other Netlify functions. diff --git a/.gitignore b/.gitignore index bd91a5e43f60..005c7a4cb282 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ yarn.lock .svelte-kit .cloudflare .pnpm-debug.log +.netlify diff --git a/examples/hn.svelte.dev/.gitignore b/examples/hn.svelte.dev/.gitignore index 77b1ebd8489d..5239a9e29e2f 100644 --- a/examples/hn.svelte.dev/.gitignore +++ b/examples/hn.svelte.dev/.gitignore @@ -2,4 +2,5 @@ node_modules /.svelte /build -/functions \ No newline at end of file +/functions +/.netlify/functions* diff --git a/examples/hn.svelte.dev/.netlify/netlify-plugin-pnpm/index.js b/examples/hn.svelte.dev/.netlify/netlify-plugin-pnpm/index.js index 2ec6ed05a4a0..c449653efc2f 100644 --- a/examples/hn.svelte.dev/.netlify/netlify-plugin-pnpm/index.js +++ b/examples/hn.svelte.dev/.netlify/netlify-plugin-pnpm/index.js @@ -1,8 +1,9 @@ -export default { +module.exports = { onPreBuild: async ({ utils: { build, run } }) => { try { await run.command("npm install -g pnpm") - await run.command("pnpm install") + await run.command("pnpm -w install") + await run.command("pnpm -w build") } catch (error) { return build.failBuild(error) } diff --git a/examples/hn.svelte.dev/.netlify/netlify-plugin-pnpm/package.json b/examples/hn.svelte.dev/.netlify/netlify-plugin-pnpm/package.json new file mode 100644 index 000000000000..0292b9956f2e --- /dev/null +++ b/examples/hn.svelte.dev/.netlify/netlify-plugin-pnpm/package.json @@ -0,0 +1 @@ +{"type":"commonjs"} \ No newline at end of file diff --git a/examples/hn.svelte.dev/netlify.toml b/examples/hn.svelte.dev/netlify.toml index 600583b92a4d..746e35685bb3 100644 --- a/examples/hn.svelte.dev/netlify.toml +++ b/examples/hn.svelte.dev/netlify.toml @@ -1,10 +1,13 @@ [build] command = "npm run build" publish = ".svelte-kit/netlify/build/" - functions = ".svelte-kit/netlify/functions/" [build.environment] NPM_FLAGS="--prefix=/dev/null" [[plugins]] package = "/.netlify/netlify-plugin-pnpm" + +[dev] +# Disable svelte-kit dev so we can test functions +framework = "#static" diff --git a/packages/adapter-netlify/README.md b/packages/adapter-netlify/README.md index b7248d1bef4d..fb96922b08f6 100644 --- a/packages/adapter-netlify/README.md +++ b/packages/adapter-netlify/README.md @@ -27,16 +27,15 @@ export default { }; ``` -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: +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` settings, as per this sample configuration: ```toml [build] command = "npm run build" publish = ".svelte-kit/netlify/build/" - functions = ".svelte-kit/netlify/functions/" ``` -In this example, we placed the `build` and `functions` folders under `.svelte-kit/netlify`. If you specify another location, you will probably also want to add them to your `.gitignore`. +There should be no need to change the publish location, but if you specify another location, you will probably also want to add it to your `.gitignore`. ## Netlify alternatives to SvelteKit functionality diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js index 5f8cf38edb84..1e9b85b537c2 100644 --- a/packages/adapter-netlify/index.js +++ b/packages/adapter-netlify/index.js @@ -19,10 +19,9 @@ export default function (options) { name: '@sveltejs/adapter-netlify', async adapt({ utils }) { - const { publish, functions } = validate_config().build; + const { publish } = validate_config().build; utils.rimraf(publish); - utils.rimraf(functions); const files = fileURLToPath(new URL('./files', import.meta.url)); @@ -32,7 +31,7 @@ export default function (options) { /** @type {BuildOptions} */ const defaultOptions = { entryPoints: ['.svelte-kit/netlify/intermediate/entry.js'], - outfile: join(functions, 'render/index.js'), + outfile: '.netlify/functions-internal/__render.js', bundle: true, inject: [join(files, 'shims.js')], platform: 'node' @@ -43,7 +42,7 @@ export default function (options) { await esbuild.build(buildOptions); - writeFileSync(join(functions, 'package.json'), JSON.stringify({ type: 'commonjs' })); + writeFileSync(join('.netlify', 'package.json'), JSON.stringify({ type: 'commonjs' })); utils.log.info('Prerendering static pages...'); await utils.prerender({ @@ -55,8 +54,10 @@ export default function (options) { utils.copy_client_files(publish); utils.log.minor('Writing redirects...'); - utils.copy('_redirects', `${publish}/_redirects`); - appendFileSync(`${publish}/_redirects`, '\n\n/* /.netlify/functions/render 200'); + + const redirectPath = join(publish, '_redirects'); + utils.copy('_redirects', redirectPath); + appendFileSync(redirectPath, '\n\n/* /.netlify/functions/__render 200'); } }; @@ -74,9 +75,9 @@ function validate_config() { throw err; } - if (!netlify_config.build || !netlify_config.build.publish || !netlify_config.build.functions) { + if (!netlify_config.build || !netlify_config.build.publish) { throw new Error( - 'You must specify build.publish and build.functions in netlify.toml. Consult https://github.com/sveltejs/kit/tree/master/packages/adapter-netlify#configuration' + 'You must specify build.publish in netlify.toml. Consult https://github.com/sveltejs/kit/tree/master/packages/adapter-netlify#configuration' ); } From 2bcbeb7955dfd860d671ebc65dbd8ed3b9d0b286 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 16 Aug 2021 10:58:56 +0100 Subject: [PATCH 2/7] Remove framework override --- examples/hn.svelte.dev/netlify.toml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/examples/hn.svelte.dev/netlify.toml b/examples/hn.svelte.dev/netlify.toml index 746e35685bb3..76d0cd81bd63 100644 --- a/examples/hn.svelte.dev/netlify.toml +++ b/examples/hn.svelte.dev/netlify.toml @@ -7,7 +7,3 @@ [[plugins]] package = "/.netlify/netlify-plugin-pnpm" - -[dev] -# Disable svelte-kit dev so we can test functions -framework = "#static" From b730c549ed91074799efa23ce0c0ea76ac9e9458 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 16 Aug 2021 19:29:12 +0100 Subject: [PATCH 3/7] Changes from review --- examples/hn.svelte.dev/.gitignore | 1 - packages/adapter-netlify/index.js | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/hn.svelte.dev/.gitignore b/examples/hn.svelte.dev/.gitignore index 5239a9e29e2f..3b224dd75119 100644 --- a/examples/hn.svelte.dev/.gitignore +++ b/examples/hn.svelte.dev/.gitignore @@ -2,5 +2,4 @@ node_modules /.svelte /build -/functions /.netlify/functions* diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js index f395c10535a5..d736776673e7 100644 --- a/packages/adapter-netlify/index.js +++ b/packages/adapter-netlify/index.js @@ -31,6 +31,7 @@ export default function (options) { /** @type {BuildOptions} */ const defaultOptions = { entryPoints: ['.svelte-kit/netlify/entry.js'], + // Any functions in ".netlify/functions-internal" are bundled in addition to user-defined Netlify functions. outfile: '.netlify/functions-internal/__render.js', bundle: true, inject: [join(files, 'shims.js')], From bb5939ddb9c5c8d7c609e7579d7ed9a809aff130 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 16 Aug 2021 21:10:57 +0100 Subject: [PATCH 4/7] Apply suggestions from code review Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com> --- packages/adapter-netlify/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js index d736776673e7..1d485ab11ec5 100644 --- a/packages/adapter-netlify/index.js +++ b/packages/adapter-netlify/index.js @@ -32,6 +32,7 @@ export default function (options) { const defaultOptions = { entryPoints: ['.svelte-kit/netlify/entry.js'], // Any functions in ".netlify/functions-internal" are bundled in addition to user-defined Netlify functions. + // See https://github.com/netlify/build/pull/3213 for more details outfile: '.netlify/functions-internal/__render.js', bundle: true, inject: [join(files, 'shims.js')], From b10fcb9df1b351cea57f82fa63dcbb673ba83c82 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Wed, 18 Aug 2021 08:48:45 +0100 Subject: [PATCH 5/7] Chnages from review --- examples/hn.svelte.dev/netlify.toml | 2 +- packages/adapter-netlify/README.md | 23 ++++++++++++++++--- packages/adapter-netlify/index.js | 34 ++++++++++++++++++----------- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/examples/hn.svelte.dev/netlify.toml b/examples/hn.svelte.dev/netlify.toml index 76d0cd81bd63..ea296e225b49 100644 --- a/examples/hn.svelte.dev/netlify.toml +++ b/examples/hn.svelte.dev/netlify.toml @@ -1,6 +1,6 @@ [build] command = "npm run build" - publish = ".svelte-kit/netlify/build/" + publish = "build" [build.environment] NPM_FLAGS="--prefix=/dev/null" diff --git a/packages/adapter-netlify/README.md b/packages/adapter-netlify/README.md index 4e2a659c7ef3..cf5d92ae0692 100644 --- a/packages/adapter-netlify/README.md +++ b/packages/adapter-netlify/README.md @@ -27,14 +27,16 @@ export default { }; ``` -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` settings, as per this sample configuration: +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: ```toml [build] command = "npm run build" - publish = "build/publish/" + publish = "build" ``` +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"`. + ## Netlify alternatives to SvelteKit functionality 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. @@ -52,6 +54,20 @@ During compilation a required "catch all" redirect rule is automatically appende 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. 3. If your Netlify form has a [custom success message](https://docs.netlify.com/forms/setup/#success-messages) like `
` then ensure the corresponding `/routes/success.svelte` exists and is prerendered. +### Using Netlify Functions + +[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: + +```toml +[build] + command = "npm run build" + publish = "build" + +[functions] + directory = "functions" + node_bundler = "esbuild" +``` + ## Advanced Configuration ### esbuild @@ -76,7 +92,8 @@ The default options for this version are as follows: ```js { entryPoints: ['.svelte-kit/netlify/entry.js'], - outfile: `pathToFunctionsFolder/render/index.js`, + // This is Netlify's internal functions directory, not the one for user functions. + outfile: '.netlify/functions-internal/__render.js', bundle: true, inject: ['pathTo/shims.js'], platform: 'node' diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js index 1d485ab11ec5..204e0de78117 100644 --- a/packages/adapter-netlify/index.js +++ b/packages/adapter-netlify/index.js @@ -1,5 +1,5 @@ import { appendFileSync, existsSync, readFileSync, writeFileSync } from 'fs'; -import { join } from 'path'; +import { join, resolve } from 'path'; import { fileURLToPath } from 'url'; import esbuild from 'esbuild'; import toml from '@iarna/toml'; @@ -19,7 +19,10 @@ export default function (options) { name: '@sveltejs/adapter-netlify', async adapt({ utils }) { - const { publish } = validate_config().build; + // "build" is the default publish directory when Netlify detects SvelteKit + const publish = get_publish_directory(utils) || 'build'; + + utils.log.minor(`Publishing to "${publish}"`); utils.rimraf(publish); @@ -46,7 +49,7 @@ export default function (options) { writeFileSync(join('.netlify', 'package.json'), JSON.stringify({ type: 'commonjs' })); - utils.log.info('Prerendering static pages...'); + utils.log.minor('Prerendering static pages...'); await utils.prerender({ dest: publish }); @@ -65,9 +68,12 @@ export default function (options) { return adapter; } - -function validate_config() { +/** + * @param {import('@sveltejs/kit').AdapterUtils} utils + **/ +function get_publish_directory(utils) { if (existsSync('netlify.toml')) { + /** @type {{ build?: { publish?: string }} & toml.JsonMap } */ let netlify_config; try { @@ -78,9 +84,8 @@ function validate_config() { } if (!netlify_config.build || !netlify_config.build.publish) { - throw new Error( - 'You must specify build.publish in netlify.toml. Consult https://github.com/sveltejs/kit/tree/master/packages/adapter-netlify#configuration' - ); + utils.log.warn('No publish directory specified in netlify.toml, using default'); + return; } if (netlify_config.redirects) { @@ -88,12 +93,15 @@ function validate_config() { "Redirects are not supported in netlify.toml. Use _redirects instead. For more details consult the readme's troubleshooting section." ); } - - return netlify_config; + if (resolve(netlify_config.build.publish) === process.cwd()) { + throw new Error( + 'The publish directory cannot be set to the site root. Please change it to "build" in netlify.toml.' + ); + } + return netlify_config.build.publish; } - // TODO offer to create one? - throw new Error( - 'Missing a netlify.toml file. Consult https://github.com/sveltejs/kit/tree/master/packages/adapter-netlify#configuration' + utils.log.warn( + 'No netlify.toml found. Using default publish directory. Consult https://github.com/sveltejs/kit/tree/master/packages/adapter-netlify#configuration for more details ' ); } From 4fe2486b4ed062d20fc33f6ccdc48cc3bb0a3974 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Wed, 18 Aug 2021 09:20:24 +0100 Subject: [PATCH 6/7] Update default template with new netlify adapter config --- packages/create-svelte/templates/default/netlify.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/create-svelte/templates/default/netlify.toml b/packages/create-svelte/templates/default/netlify.toml index 52f34ade09eb..e58f4d0cd837 100644 --- a/packages/create-svelte/templates/default/netlify.toml +++ b/packages/create-svelte/templates/default/netlify.toml @@ -1,4 +1,3 @@ [build] command = "npm run build" - publish = ".svelte-kit/netlify/build/" - functions = ".svelte-kit/netlify/functions/" + publish = "build" From 12e37667ae3974808c386988a11c31df6c02363a Mon Sep 17 00:00:00 2001 From: Ben McCann <322311+benmccann@users.noreply.github.com> Date: Wed, 18 Aug 2021 08:22:16 -0700 Subject: [PATCH 7/7] Update packages/adapter-netlify/index.js --- packages/adapter-netlify/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js index 204e0de78117..07693b96dc5c 100644 --- a/packages/adapter-netlify/index.js +++ b/packages/adapter-netlify/index.js @@ -95,7 +95,7 @@ function get_publish_directory(utils) { } if (resolve(netlify_config.build.publish) === process.cwd()) { throw new Error( - 'The publish directory cannot be set to the site root. Please change it to "build" in netlify.toml.' + 'The publish directory cannot be set to the site root. Please change it to another value such as "build" in netlify.toml.' ); } return netlify_config.build.publish;