Skip to content
This repository was archived by the owner on May 10, 2021. It is now read-only.

add support for background functions in api pages only #171

Merged
merged 2 commits into from
Feb 25, 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
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ The plugin can be found on [npm here](https://www.npmjs.com/package/@netlify/plu
- [Preview Locally](#preview-locally)
- [Custom Netlify Redirects](#custom-netlify-redirects)
- [Custom Netlify Functions](#custom-netlify-functions)
- [Background Functions](#background-functions)
- [Using Netlify Identity](#using-netlify-identity)
- [Caveats](#caveats)
- [Fallbacks for Pages with `getStaticPaths`](#fallbacks-for-pages-with-getstaticpaths)
Expand Down Expand Up @@ -223,7 +224,12 @@ Currently, there is no support for redirects set in your `netlify.toml` file.
### Custom Netlify Functions

`next-on-netlify` creates one Netlify Function for each of your
SSR pages and API endpoints. It is currently not possible to create custom Netlify Functions. This feature is on our list to do.
SSR pages and API endpoints. Currently, you can only create custom Netlify functions using [@netlify/plugin-nextjs](https://github.com/netlify/netlify-plugin-nextjs#custom-netlify-functions).

### Background Functions

If your Next.js API page/route ends in `-background`, it will be treated as a [Netlify background function](https://docs.netlify.com/functions/background-functions/).
Note: background functions are only available on certain plans.

### Using Netlify Identity

Expand Down
13 changes: 11 additions & 2 deletions lib/helpers/getNetlifyFunctionName.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const path = require("path");
// The function name will be next_directory_subdirectory_[id]
// We do this because every function needs to be at the top-level, i.e.
// nested functions are not allowed.
const getNetlifyFunctionName = (filePath) => {
const getNetlifyFunctionName = (filePath, isApiPage) => {
// Remove pages/ from file path:
// pages/directory/page.js > directory/page.js
const relativeFilePath = path.relative("pages", filePath);
Expand All @@ -24,7 +24,16 @@ const getNetlifyFunctionName = (filePath) => {
// Netlify Function names may not contain periods or square brackets.
// To be safe, we keep only alphanumeric characters and underscores.
// See: https://community.netlify.com/t/failed-to-upload-functions-file-function-too-large/3549/8
functionName = functionName.replace(/[^\w\d]/g, "");
const cleanNameRegex = new RegExp(/[^\w\d]/g);
// Allow users to use background functions for /api pages *only*
// Note: this means that there is a chance a Next on Netlify user could
// unknowingly create a background function if they're not familiar with them
// and their syntax
const allowBackgroundRegex = new RegExp(/[^\w\d-]|-(?!background$)/g);
functionName = functionName.replace(
isApiPage ? allowBackgroundRegex : cleanNameRegex,
""
);

return functionName;
};
Expand Down
17 changes: 14 additions & 3 deletions lib/helpers/setupNetlifyFunctionForPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,25 @@ const {
FUNCTION_TEMPLATE_PATH,
} = require("../config");
const getNetlifyFunctionName = require("./getNetlifyFunctionName");
const { logItem } = require("./logger");

// Create a Netlify Function for the page with the given file path
const setupNetlifyFunctionForPage = ({ filePath, functionsPath }) => {
const setupNetlifyFunctionForPage = ({
filePath,
functionsPath,
isApiPage,
}) => {
// Set function name based on file path
const functionName = getNetlifyFunctionName(filePath);
const functionName = getNetlifyFunctionName(filePath, isApiPage);
const functionDirectory = join(functionsPath, functionName);

// Copy function template
if (isApiPage && functionName.endsWith("-background")) {
logItem(
`👁 Setting up API page ${functionName} as a Netlify background function`
);
}

// Copy function templates
const functionTemplateCopyPath = join(
functionDirectory,
`${functionName}.js`
Expand Down
2 changes: 1 addition & 1 deletion lib/pages/api/redirects.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const pages = require("./pages");

const redirects = pages.map(({ route, filePath }) => ({
route,
target: `/.netlify/functions/${getNetlifyFunctionName(filePath)}`,
target: `/.netlify/functions/${getNetlifyFunctionName(filePath, true)}`,
}));

module.exports = redirects;
2 changes: 1 addition & 1 deletion lib/pages/api/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const setup = (functionsPath) => {
// Create Netlify Function for every page
pages.forEach(({ filePath }) => {
logItem(filePath);
setupNetlifyFunctionForPage({ filePath, functionsPath });
setupNetlifyFunctionForPage({ filePath, functionsPath, isApiPage: true });
});
};

Expand Down
1 change: 1 addition & 0 deletions tests/__snapshots__/defaults.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ exports[`Routing creates Netlify redirects 1`] = `
/_next/data/%BUILD_ID%/getStaticProps/withFallbackBlocking/4.json /.netlify/functions/next_getStaticProps_withFallbackBlocking_id 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/getStaticProps/withRevalidate/1.json /.netlify/functions/next_getStaticProps_withRevalidate_id 200
/_next/data/%BUILD_ID%/getStaticProps/withRevalidate/2.json /.netlify/functions/next_getStaticProps_withRevalidate_id 200
/api/hello-background /.netlify/functions/next_api_hello-background 200
/api/static /.netlify/functions/next_api_static 200
/getServerSideProps/static /.netlify/functions/next_getServerSideProps_static 200
/getStaticProps/1 /.netlify/functions/next_getStaticProps_id 200! Cookie=__prerender_bypass,__next_preview_data
Expand Down
1 change: 1 addition & 0 deletions tests/__snapshots__/i18n.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ exports[`Routing creates Netlify redirects 1`] = `
/_next/data/%BUILD_ID%/es/getStaticProps/static.json /.netlify/functions/next_getStaticProps_static 200! Cookie=__prerender_bypass,__next_preview_data
/_next/data/%BUILD_ID%/es/getStaticProps/with-revalidate.json /.netlify/functions/next_getStaticProps_withrevalidate 200
/_next/data/%BUILD_ID%/getServerSideProps/static.json /.netlify/functions/next_getServerSideProps_static 200
/api/hello-background /.netlify/functions/next_api_hello-background 200
/api/static /.netlify/functions/next_api_static 200
/en /.netlify/functions/next_index 200
/en/getServerSideProps/static /.netlify/functions/next_getServerSideProps_static 200
Expand Down
9 changes: 9 additions & 0 deletions tests/defaults.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ describe("API Pages", () => {
join(functionsDir, "next_api_shows_params", "next_api_shows_params.js")
)
).toBe(true);
expect(
existsSync(
join(
functionsDir,
"next_api_hello-background",
"next_api_hello-background.js"
)
)
).toBe(true);
});
});

Expand Down
5 changes: 5 additions & 0 deletions tests/fixtures/pages/api/hello-background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default (req, res) => {
res.setHeader("Content-Type", "application/json");
res.status(200);
res.json({ message: "hello world :)" });
};