Skip to content

Commit

Permalink
Merge pull request #46 from HubSpot/bmatto/example-with-serverless
Browse files Browse the repository at this point in the history
Example with Developer Platform Serverless function
  • Loading branch information
bmatto authored Apr 16, 2024
2 parents ac10483 + c7d8e5a commit cddeb57
Show file tree
Hide file tree
Showing 17 changed files with 270 additions and 0 deletions.
33 changes: 33 additions & 0 deletions docs/reference/serverless.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# 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/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

- 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.
23 changes: 23 additions & 0 deletions examples/serverless/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -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',
},
},
};
3 changes: 3 additions & 0 deletions examples/serverless/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules/
hubspot.config.yml
dist
14 changes: 14 additions & 0 deletions examples/serverless/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"trailingComma": "all",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"overrides": [
{
"files": "*.hubl.html",
"options": {
"parser": "hubl"
}
}
]
}
19 changes: 19 additions & 0 deletions examples/serverless/README.md
Original file line number Diff line number Diff line change
@@ -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).
4 changes: 4 additions & 0 deletions examples/serverless/cms-with-serverless-project/.hsignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
README.md
tsconfig.json
yarn.lock
dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "app.functions",
"version": "1.0.0",
"description": "",
"dependencies": {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
exports.main = async (context) => {
return {
statusCode: 200,
body: {
message: `SQUAWK: ${context.params.message}`,
},
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"appFunctions": {
"parrotFunction": {
"file": "parrot-function.js",
"endpoint": {
"path": "parrot",
"method": ["GET"]
}
}
}
}
16 changes: 16 additions & 0 deletions examples/serverless/cms-with-serverless-project/app/app.json
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "CMS React",
"outputPath": ""
}
Original file line number Diff line number Diff line change
@@ -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 (
<>
<form onSubmit={makeRequestToProjectFunction}>
<fieldset>
<legend>
Make a request to the Developer Platform Serverless Function
</legend>
<label htmlFor="message">Message:</label>
<input
type="text"
id="message"
name="message"
onChange={(e) => setMessage(e.target.value)}
value={message}
/>
<div style={{ marginTop: '10px' }}>
<button type="submit">Make Request</button>
</div>
</fieldset>
</form>
<ul
style={{
listStyle: 'none',
margin: '0',
padding: '0',
}}
>
{data.map((item) => (
<li style={{ margin: '5px 0' }} key={item}>
{item}
</li>
))}
</ul>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Island } from '@hubspot/cms-components';

import MakeServerlessRequestIsland from './MakeServerlessRequestIsland?island';

export function Component() {
return (
<div>
<h1>Parrot Island</h1>
<Island
id="make-serverless-request"
module={MakeServerlessRequestIsland}
/>
</div>
);
}

export const fields = [];

export const meta = {
label: 'Make Serverless Requests',
};
Original file line number Diff line number Diff line change
@@ -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"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "cms-with-serverless-project",
"srcDir": ".",
"platformVersion": "2023.2"
}
5 changes: 5 additions & 0 deletions examples/serverless/jsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"compilerOptions": {
"moduleResolution": "NodeNext"
}
}
25 changes: 25 additions & 0 deletions examples/serverless/package.json
Original file line number Diff line number Diff line change
@@ -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"
}
}

0 comments on commit cddeb57

Please sign in to comment.