From dfa985de67f23c49890505411495bfef77991a52 Mon Sep 17 00:00:00 2001 From: Byron Matto Date: Tue, 16 Apr 2024 12:34:36 -0400 Subject: [PATCH 1/4] Example with Developer Platform Serverless function --- examples/serverless/.eslintrc.js | 23 ++++++++ examples/serverless/.gitignore | 3 ++ examples/serverless/.prettierrc | 14 +++++ .../cms-with-serverless-project/.hsignore | 4 ++ .../app/app.functions/package.json | 6 +++ .../app/app.functions/parrot-function.js | 8 +++ .../app/app.functions/serverless.json | 11 ++++ .../cms-with-serverless-project/app/app.json | 16 ++++++ .../cms-react/cms-assets.json | 4 ++ .../MakeServerlessRequestIsland.jsx | 52 +++++++++++++++++++ .../modules/MakeServerlessRequest/index.jsx | 21 ++++++++ .../cms-react/package.json | 21 ++++++++ .../hsproject.json | 5 ++ examples/serverless/jsconfig.json | 5 ++ examples/serverless/package.json | 25 +++++++++ 15 files changed, 218 insertions(+) create mode 100644 examples/serverless/.eslintrc.js create mode 100644 examples/serverless/.gitignore create mode 100644 examples/serverless/.prettierrc create mode 100644 examples/serverless/cms-with-serverless-project/.hsignore create mode 100644 examples/serverless/cms-with-serverless-project/app/app.functions/package.json create mode 100644 examples/serverless/cms-with-serverless-project/app/app.functions/parrot-function.js create mode 100644 examples/serverless/cms-with-serverless-project/app/app.functions/serverless.json create mode 100644 examples/serverless/cms-with-serverless-project/app/app.json create mode 100644 examples/serverless/cms-with-serverless-project/cms-react/cms-assets.json create mode 100644 examples/serverless/cms-with-serverless-project/cms-react/components/modules/MakeServerlessRequest/MakeServerlessRequestIsland.jsx create mode 100644 examples/serverless/cms-with-serverless-project/cms-react/components/modules/MakeServerlessRequest/index.jsx create mode 100644 examples/serverless/cms-with-serverless-project/cms-react/package.json create mode 100644 examples/serverless/cms-with-serverless-project/hsproject.json create mode 100644 examples/serverless/jsconfig.json create mode 100644 examples/serverless/package.json diff --git a/examples/serverless/.eslintrc.js b/examples/serverless/.eslintrc.js new file mode 100644 index 0000000..69e9d9f --- /dev/null +++ b/examples/serverless/.eslintrc.js @@ -0,0 +1,23 @@ +module.exports = { + parserOptions: { + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, + }, + env: { + node: true, + es2021: true, + }, + extends: ['eslint:recommended', 'prettier', 'plugin:react/recommended'], + rules: { + 'react/react-in-jsx-scope': 'off', + 'react/prop-types': 'off', + }, + ignorePatterns: ['hello-world-project/hello-world-app/dist/*'], + settings: { + react: { + version: '18.1', + }, + }, +}; diff --git a/examples/serverless/.gitignore b/examples/serverless/.gitignore new file mode 100644 index 0000000..15c3c79 --- /dev/null +++ b/examples/serverless/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +hubspot.config.yml +dist \ No newline at end of file diff --git a/examples/serverless/.prettierrc b/examples/serverless/.prettierrc new file mode 100644 index 0000000..a460b0a --- /dev/null +++ b/examples/serverless/.prettierrc @@ -0,0 +1,14 @@ +{ + "trailingComma": "all", + "tabWidth": 2, + "semi": true, + "singleQuote": true, + "overrides": [ + { + "files": "*.hubl.html", + "options": { + "parser": "hubl" + } + } + ] +} diff --git a/examples/serverless/cms-with-serverless-project/.hsignore b/examples/serverless/cms-with-serverless-project/.hsignore new file mode 100644 index 0000000..b1d9729 --- /dev/null +++ b/examples/serverless/cms-with-serverless-project/.hsignore @@ -0,0 +1,4 @@ +README.md +tsconfig.json +yarn.lock +dist diff --git a/examples/serverless/cms-with-serverless-project/app/app.functions/package.json b/examples/serverless/cms-with-serverless-project/app/app.functions/package.json new file mode 100644 index 0000000..9d5bc02 --- /dev/null +++ b/examples/serverless/cms-with-serverless-project/app/app.functions/package.json @@ -0,0 +1,6 @@ +{ + "name": "app.functions", + "version": "1.0.0", + "description": "", + "dependencies": {} +} diff --git a/examples/serverless/cms-with-serverless-project/app/app.functions/parrot-function.js b/examples/serverless/cms-with-serverless-project/app/app.functions/parrot-function.js new file mode 100644 index 0000000..d6a2906 --- /dev/null +++ b/examples/serverless/cms-with-serverless-project/app/app.functions/parrot-function.js @@ -0,0 +1,8 @@ +exports.main = async (context) => { + return { + statusCode: 200, + body: { + message: `SQUAWK: ${context.params.message}`, + }, + }; +}; diff --git a/examples/serverless/cms-with-serverless-project/app/app.functions/serverless.json b/examples/serverless/cms-with-serverless-project/app/app.functions/serverless.json new file mode 100644 index 0000000..d389a19 --- /dev/null +++ b/examples/serverless/cms-with-serverless-project/app/app.functions/serverless.json @@ -0,0 +1,11 @@ +{ + "appFunctions": { + "parrotFunction": { + "file": "parrot-function.js", + "endpoint": { + "path": "parrot", + "method": ["GET"] + } + } + } +} diff --git a/examples/serverless/cms-with-serverless-project/app/app.json b/examples/serverless/cms-with-serverless-project/app/app.json new file mode 100644 index 0000000..512137b --- /dev/null +++ b/examples/serverless/cms-with-serverless-project/app/app.json @@ -0,0 +1,16 @@ +{ + "name": "CMS React With Serverless", + "description": "This app contains CMS React Component which talks talks to serverless functions", + "scopes": [ + "crm.objects.companies.read", + "crm.objects.companies.write", + "collector.graphql_schema.read", + "collector.graphql_query.execute", + "crm.objects.custom.write", + "crm.objects.custom.read", + "crm.schemas.custom.read", + "crm.schemas.custom.write" + ], + "uid": "cms_react_serverless_app", + "public": false +} diff --git a/examples/serverless/cms-with-serverless-project/cms-react/cms-assets.json b/examples/serverless/cms-with-serverless-project/cms-react/cms-assets.json new file mode 100644 index 0000000..4929ace --- /dev/null +++ b/examples/serverless/cms-with-serverless-project/cms-react/cms-assets.json @@ -0,0 +1,4 @@ +{ + "label": "CMS React", + "outputPath": "" +} diff --git a/examples/serverless/cms-with-serverless-project/cms-react/components/modules/MakeServerlessRequest/MakeServerlessRequestIsland.jsx b/examples/serverless/cms-with-serverless-project/cms-react/components/modules/MakeServerlessRequest/MakeServerlessRequestIsland.jsx new file mode 100644 index 0000000..5693bd6 --- /dev/null +++ b/examples/serverless/cms-with-serverless-project/cms-react/components/modules/MakeServerlessRequest/MakeServerlessRequestIsland.jsx @@ -0,0 +1,52 @@ +import { useState } from 'react'; + +export default function MakeServerlessRequestIsland() { + const [data, setData] = useState([]); + const [message, setMessage] = useState(''); + + function makeRequestToProjectFunction(event) { + event.preventDefault(); + + return fetch(`/hs/serverless/parrot?message=${message}`) + .then((response) => response.json()) + .then((jsonResponse) => { + setData([...data, jsonResponse.message]); + }); + } + + return ( + <> +
+
+ + Make a request to the Developer Platform Serverless Function + + + setMessage(e.target.value)} + value={message} + /> +
+ +
+
+
+ + + ); +} diff --git a/examples/serverless/cms-with-serverless-project/cms-react/components/modules/MakeServerlessRequest/index.jsx b/examples/serverless/cms-with-serverless-project/cms-react/components/modules/MakeServerlessRequest/index.jsx new file mode 100644 index 0000000..2140ed4 --- /dev/null +++ b/examples/serverless/cms-with-serverless-project/cms-react/components/modules/MakeServerlessRequest/index.jsx @@ -0,0 +1,21 @@ +import { Island } from '@hubspot/cms-components'; + +import MakeServerlessRequestIsland from './MakeServerlessRequestIsland?island'; + +export function Component() { + return ( +
+

Parrot Island

+ +
+ ); +} + +export const fields = []; + +export const meta = { + label: 'Make Serverless Requests', +}; diff --git a/examples/serverless/cms-with-serverless-project/cms-react/package.json b/examples/serverless/cms-with-serverless-project/cms-react/package.json new file mode 100644 index 0000000..6fc4d06 --- /dev/null +++ b/examples/serverless/cms-with-serverless-project/cms-react/package.json @@ -0,0 +1,21 @@ +{ + "name": "module-components-app", + "version": "0.1.0", + "type": "module", + "dependencies": { + "@hubspot/cms-components": "latest", + "prop-types": "^15.8.1", + "react": "^18.1.0" + }, + "devDependencies": { + "@hubspot/cms-dev-server": "latest", + "@testing-library/react": "^13.4.0", + "@vitejs/plugin-react": "^2.1.0", + "jsdom": "^20.0.1", + "vitest": "^0.24.3" + }, + "scripts": { + "start": "hs-cms-dev-server .", + "test": "vitest" + } +} diff --git a/examples/serverless/cms-with-serverless-project/hsproject.json b/examples/serverless/cms-with-serverless-project/hsproject.json new file mode 100644 index 0000000..76494e7 --- /dev/null +++ b/examples/serverless/cms-with-serverless-project/hsproject.json @@ -0,0 +1,5 @@ +{ + "name": "cms-with-serverless-project", + "srcDir": ".", + "platformVersion": "2023.2" +} diff --git a/examples/serverless/jsconfig.json b/examples/serverless/jsconfig.json new file mode 100644 index 0000000..0d505be --- /dev/null +++ b/examples/serverless/jsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "moduleResolution": "NodeNext" + } +} diff --git a/examples/serverless/package.json b/examples/serverless/package.json new file mode 100644 index 0000000..72d8582 --- /dev/null +++ b/examples/serverless/package.json @@ -0,0 +1,25 @@ +{ + "name": "cms-with-serverless", + "description": "CMS React Module Components Example", + "license": "Apache-2.0", + "devDependencies": { + "@hubspot/cli": "latest", + "@hubspot/prettier-plugin-hubl": "latest", + "eslint": "^8.24.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-react": "^7.31.10", + "prettier": "^2.7.1", + "yarpm": "^1.2.0" + }, + "scripts": { + "start": "cd cms-with-serverless-project/src/cms-react && yarpm start", + "postinstall": "cd cms-with-serverless-project/src/cms-react && yarpm install", + "lint:js": "eslint . --ext .js,.jsx", + "prettier": "prettier . --check", + "deploy": "hs project upload cms-with-serverless-project" + }, + "dependencies": {}, + "engines": { + "node": ">=16.0.0" + } +} From d0305b8a6c94316a40cd55b380663096ae3e01af Mon Sep 17 00:00:00 2001 From: Byron Matto Date: Tue, 16 Apr 2024 13:44:15 -0400 Subject: [PATCH 2/4] add read me --- examples/serverless/README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 examples/serverless/README.md diff --git a/examples/serverless/README.md b/examples/serverless/README.md new file mode 100644 index 0000000..fdb89f0 --- /dev/null +++ b/examples/serverless/README.md @@ -0,0 +1,19 @@ +# CMS React Module with Serverless Functions Example + +This directory contains an example of a CMS React Module that makes use of serverless functions on the new HubSpot developer platform. + +## Overview + +This example demonstrates how to build a CMS React Module that leverages serverless functions to enhance the functionality of your HubSpot CMS. By combining the power of React and serverless functions, you can create dynamic and interactive modules that seamlessly integrate with the HubSpot developer platform. + +## Resources + +For more information about CMS React Modules and serverless functions on the HubSpot developer platform, refer to the following resources: + +- [HubSpot CMS Developer Documentation](https://developers.hubspot.com/cms/) +- [React Documentation](https://reactjs.org/) +- [HubSpot Developer Platform Serverless Documentation](https://developers.hubspot.com/docs/platform/serverless-functions) + +## License + +This example is licensed under the [MIT License](LICENSE). From cce1853aad58d318e9c5f726df9f30922aab16d7 Mon Sep 17 00:00:00 2001 From: Byron Matto Date: Tue, 16 Apr 2024 14:25:10 -0400 Subject: [PATCH 3/4] Add documenation on Serverless --- docs/reference/serverless.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 docs/reference/serverless.md diff --git a/docs/reference/serverless.md b/docs/reference/serverless.md new file mode 100644 index 0000000..274a251 --- /dev/null +++ b/docs/reference/serverless.md @@ -0,0 +1,31 @@ +# HubSpot Serverless Functions with CMS React Modules + +## Introduction + +HubSpot provides two different types of serverless functions: [CMS Serverless Functions](https://developers.hubspot.com/docs/cms/data/serverless-functions/reference) and [Developer Platform Serverless Functions](https://developers.hubspot.com/docs/platform/serverless-functions). While they are similar in many ways, there are some key differences between them. This documentation will help you understand these differences and guide you on how to use them effectively with CMS React Modules. + +## CMS Serverless Functions + +CMS Serverless Functions were specifically designed to work with the HubSpot CMS. They are tightly integrated with the CMS. You deploy them via the CLI to the Design Manager and can edit them locally or in the Design Manager + +### Limitations to CMS Serverless Functions + +- CMS Serverless functions do not allow you to add your own dependencies i.e. 3rd party packages. + +- Because Developer Platform Serverless functions are defined within a "Private App" they inherit the scopes assigned to that Private App. That level of granular control is no available with CMS Serverless Functions. They rely on storing a personal access token in hs secrets which is then referenced in the serverless function. + +## Developer Platform Serverless Functions + +Developer Platform Serverless Functions, on the other hand, are part of the broader HubSpot Developer Platform. They are built on projects, the same system that CMS React is built on. Thus a developer may have a single project with a CMS React component as well as a Private App with a serverless function. + +Please see an example of a CMS React component along side a Developer Platform Serverless functions here https://github.com/HubSpot/cms-react/tree/main/examples/serverless + +### Limitations with Developer Platform Functions + +- Currently there is no access to logs for Developer Platform Endpoint functions. + +## How to Decide Which To Use + +Ultimately we are going to provide a migration path for CMS Serverless Functions to the Developer Platform Serverless functions. At this current moment the limitation on logging may give a CMS Developer pause for using these functions. It is for that reason that we suggest CMS Developers continue to use the CMS Serverless Functions until such time that logging is fully supported in the Developer Platform Serverless Functions. + +However, if a developer finds the convenience of a single build system, and access to the 3rd party deps outweighs that limitation the upside will be that they will be ahead of the game in terms of any migrations that might be required. From c7d8e5af3e83e815356e59300ed1e48b719fb56a Mon Sep 17 00:00:00 2001 From: Byron Matto Date: Tue, 16 Apr 2024 14:47:35 -0400 Subject: [PATCH 4/4] PR reivew for docs --- docs/reference/serverless.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/reference/serverless.md b/docs/reference/serverless.md index 274a251..403fb33 100644 --- a/docs/reference/serverless.md +++ b/docs/reference/serverless.md @@ -18,7 +18,9 @@ CMS Serverless Functions were specifically designed to work with the HubSpot CMS Developer Platform Serverless Functions, on the other hand, are part of the broader HubSpot Developer Platform. They are built on projects, the same system that CMS React is built on. Thus a developer may have a single project with a CMS React component as well as a Private App with a serverless function. -Please see an example of a CMS React component along side a Developer Platform Serverless functions here https://github.com/HubSpot/cms-react/tree/main/examples/serverless +Please see an example of a CMS React component along side a Developer Platform Serverless functions here https://github.com/HubSpot/cms-react/examples/serverless + +Looking forward the Developer Platform will offer one system to learn across CRM, CMS, and other parts of Hubspot. erverless function capabilities can be more easily upgraded overtime by HubSpot due to being tied into the Projects versioning system. Unlocking a better developer experience, performance, security, etc. A unified system for managing secrets. Private apps could also be shared between website and UI Extensions. ### Limitations with Developer Platform Functions