This boilerplate provides a template to customize your own marketplace DAM app.
- Contentstack Account
Nodejs
- v20.10.0 &NPM
- v10.2.4
Reveal/Collapse the code structure
marketplace-dam-boilerplate-app
└── ui
├── babel.config.js
├── example
│ ├── bynder
│ │ ├── root_config
│ │ │ ├── ConfigScreen
│ │ │ │ └── index.tsx
│ │ │ ├── CustomField
│ │ │ │ └── index.tsx
│ │ │ ├── DamEnv
│ │ │ │ └── index.ts
│ │ │ ├── index.tsx
│ │ │ └── SelectorPage
│ │ │ └── index.tsx
│ │ └── rte_config
│ │ ├── DamEnv
│ │ │ └── index.tsx
│ │ ├── index.tsx
│ │ └── RTEFunctions
│ │ └── index.tsx
│ ├── cloudinary
│ │ ├── root_config
│ │ │ ├── ConfigScreen
│ │ │ │ └── index.tsx
│ │ │ ├── CustomField
│ │ │ │ └── index.tsx
│ │ │ ├── DamEnv
│ │ │ │ └── index.ts
│ │ │ ├── index.tsx
│ │ │ └── SelectorPage
│ │ │ └── index.tsx
│ │ └── rte_config
│ │ ├── DamEnv
│ │ │ └── index.tsx
│ │ ├── index.tsx
│ │ └── RTEFunctions
│ │ └── index.tsx
│ └── sample_dam_app
│ ├── root_config
│ │ ├── AssetData
│ │ │ └── index.tsx
│ │ ├── ConfigScreen
│ │ │ └── index.tsx
│ │ ├── CustomComponent
│ │ │ └── index.tsx
│ │ ├── CustomField
│ │ │ └── index.tsx
│ │ ├── DamEnv
│ │ │ └── index.ts
│ │ ├── index.tsx
│ │ ├── SelectorPage
│ │ │ └── index.tsx
│ │ ├── styles.scss
│ │ └── utils
│ │ └── index.tsx
│ └── rte_config
│ ├── DamEnv
│ │ └── index.tsx
│ ├── index.tsx
│ └── RTEFunctions
│ └── index.tsx
├── jest.config.js
├── jest.CSStub.js
├── jest.setup.js
├── package.json
├── package-lock.json
├── public
│ ├── favicon.ico
│ └── index.html
├── rte
│ ├── custom.d.ts
│ ├── LICENSE
│ ├── package.json
│ ├── package-lock.json
│ ├── SECURITY.md
│ ├── src
│ │ ├── common
│ │ │ ├── constants
│ │ │ │ └── index.ts
│ │ │ ├── locale
│ │ │ │ └── en-us
│ │ │ │ └── index.ts
│ │ │ └── utils
│ │ │ └── index.ts
│ │ ├── components
│ │ │ ├── DAMIcon
│ │ │ │ └── index.js
│ │ │ ├── DeleteModal
│ │ │ │ └── index.js
│ │ │ ├── EmbedBtn
│ │ │ │ └── index.js
│ │ │ ├── ErrorImage
│ │ │ │ └── index.js
│ │ │ ├── ImageEditModal
│ │ │ │ └── index.js
│ │ │ ├── ImageElement
│ │ │ │ └── index.js
│ │ │ └── styles.scss
│ │ ├── dam.ts
│ │ ├── plugin.tsx
│ │ └── rte_config
│ │ ├── DamEnv
│ │ │ └── index.tsx
│ │ ├── index.tsx
│ │ └── RTEFunctions
│ │ └── index.tsx
│ ├── tsconfig.json
│ ├── webpack.common.js
│ ├── webpack.dev.js
│ └── webpack.prod.js
├── src
│ ├── common
│ │ ├── asset
│ │ │ ├── logo.svg
│ │ │ └── NoImg.svg
│ │ ├── constants
│ │ │ └── index.tsx
│ │ ├── contexts
│ │ │ ├── AppConfigContext.tsx
│ │ │ ├── ConfigStateContext.tsx
│ │ │ ├── CustomFieldContext.tsx
│ │ │ └── MarketplaceAppContext.tsx
│ │ ├── hooks
│ │ │ └── useAppLocation.ts
│ │ ├── locale
│ │ │ └── en-us
│ │ │ └── index.ts
│ │ ├── providers
│ │ │ ├── AppConfigProvider.tsx
│ │ │ ├── ConfigStateProvider.tsx
│ │ │ ├── CustomFieldProvider.tsx
│ │ │ └── MarketplaceAppProvider.tsx
│ │ ├── types
│ │ │ └── index.ts
│ │ └── utils
│ │ ├── ConfigScreenUtils.tsx
│ │ ├── CustomFieldUtils.tsx
│ │ └── SelectorPageUtils.tsx
│ ├── components
│ │ ├── AppFailed
│ │ │ └── index.tsx
│ │ ├── DeleteModal
│ │ │ └── index.tsx
│ │ ├── ErrorBoundary
│ │ │ └── index.tsx
│ │ ├── Loaders
│ │ │ ├── ConfigLoader.tsx
│ │ │ ├── CustomFieldLoader.tsx
│ │ │ └── SelectorPage.tsx
│ │ ├── NoImage
│ │ │ └── index.tsx
│ │ └── WarningMessage
│ │ └── index.tsx
│ ├── containers
│ │ ├── App
│ │ │ ├── index.tsx
│ │ │ └── styles.scss
│ │ ├── ConfigScreen
│ │ │ ├── Components.tsx
│ │ │ ├── index.tsx
│ │ │ └── styles.scss
│ │ ├── CustomField
│ │ │ ├── AssetContainer.tsx
│ │ │ ├── Card
│ │ │ │ ├── AssetCardContainer.tsx
│ │ │ │ └── AssetCard.tsx
│ │ │ ├── index.tsx
│ │ │ ├── List
│ │ │ │ ├── AssetListContainer.tsx
│ │ │ │ └── AssetList.tsx
│ │ │ └── styles.scss
│ │ └── SelectorPage
│ │ ├── index.tsx
│ │ └── style.scss
│ ├── Images
│ │ ├── bobatea.jpeg
│ │ ├── burger.jpeg
│ │ ├── coffee.jpeg
│ │ ├── cupcake.jpeg
│ │ ├── friedeggs.jpeg
│ │ ├── fries.jpeg
│ │ ├── icecream.jpeg
│ │ ├── orangejuice.jpeg
│ │ ├── pancake.jpeg
│ │ ├── pizza.jpeg
│ │ ├── spaghetti.jpeg
│ │ ├── sushi.jpeg
│ │ ├── taco.jpeg
│ │ ├── waffle.jpeg
│ │ └── wrap.jpeg
│ ├── index.css
│ ├── index.tsx
│ ├── react-app-env.d.ts
│ ├── reportWebVitals.ts
│ ├── root_config
│ │ ├── AssetData
│ │ ├── ConfigScreen
│ │ │ └── index.tsx
│ │ ├── CustomComponent
│ │ │ └── index.tsx
│ │ ├── CustomField
│ │ │ └── index.tsx
│ │ ├── DamEnv
│ │ │ └── index.ts
│ │ ├── index.tsx
│ │ ├── SelectorPage
│ │ │ └── index.tsx
│ │ ├── styles.scss
│ │ └── utils
│ │ └── index.tsx
│ ├── services
│ │ └── index.ts
│ └── __tests__
│ ├── ConfigScreen
│ │ ├── ConfigScreen.spec.tsx
│ │ └── Utils.spec.tsx
│ ├── CustomField
│ │ ├── CustomField.spec.tsx
│ │ └── Utils.spec.tsx
│ └── SelectorPage
│ ├── SelectorPage.spec.tsx
│ └── Utils.spec.tsx
└── tsconfig.json
-
To start the development of a DAM app using boilerplate, first Clone DAM Boilerplate GitHub Repository and copy the content of this repo to the new repo of your APP.
-
The new app repo source folder will be referred to as APP_DIRECTORY from now on.
-
Open the package.json inside the ui and rte folders (
<APP_DIRECTORY>/ui/package.json
&<APP_DIRECTORY>/ui/rte/package.json
) and update the name attribute to your app name. -
Open the root html file of the app (available at
<APP_DIRECTORY>/ui/public/index.html
) and update the<title>
tag value to the name of your app. -
Change the favicon.ico as per the requirement of your app. favicon.ico file is available at
<APP_DIRECTORY>/ui/public/favicon.ico
.
-
.env
files are required in both ui and ui/rte. Rename.env.example
files to.env
and add the following values. -
UI ENVIRONMENT VARIABLES (<APP_DIRECTORY>/ui/.env)
REACT_APP_UI_URL_NA = https://rte-extension.contentstack.com REACT_APP_UI_URL_EU = https://eu-rte-extension.contentstack.com REACT_APP_UI_URL_AZURE_NA = https://azure-na-rte-extension.contentstack.com REACT_APP_UI_URL_AZURE_EU = https://azure-eu-rte-extension.contentstack.com REACT_APP_CUSTOM_FIELD_URL = http://localhost:4000
-
RTE ENVIRONMENT VARIABLES (<APP_DIRECTORY>/ui/rte/.env)
REACT_APP_UI_URL_NA = https://rte-extension.contentstack.com REACT_APP_UI_URL_EU = https://eu-rte-extension.contentstack.com REACT_APP_UI_URL_AZURE_NA = https://azure-na-rte-extension.contentstack.com REACT_APP_UI_URL = http://localhost:4000
-
In the terminal go to APP_DIRECTORY and install the necessary packages :
cd <APP_DIRECTORY> npm i
-
To install the necessary packages for ui , navigate to the ui folder
cd <APP_DIRECTORY>/ui npm i
-
After you install the packages, run the following command in the ui folder to get started:
-
For Linux / MacOS
npm run start
-
For Windows
npm run winStart
-
The UI server will start at port 4000.
-
To install the necessary packages for rte , navigate to the rte folder
cd <APP_DIRECTORY>/ui/rte npm i
-
After you install the packages, run the following command in the rte folder to start the webpack server.
npm run start
The webpack server will start at port 1268.
-
<MarketplaceAppProvider>
: The MarketplaceAppProvider usesMarketplaceAppContext
and initializes the Contentstack App SDK and shares its instance and configuration across components using the useContext hook, eliminating the need for prop drilling. -
<AppConfigProvider>
: The AppConfigProvider usesAppConfigContext
and generates dynamic state values based on the rootConfig's configuration and manages installation data, providing centralized state accessible via the useContext hook for child components. -
<ConfigStateProvider>
: The ConfigStateProvider usesConfigStateContext
and handles local state management for ConfigScreen UI Location, accessed by sub-components. -
<CustomFieldProvider>
: The CustomFieldProvider usesCustomFieldContext
and consolidates the management of state and rendering data, distributing it to multiple child components. It is responsible for both retrieving and updating this data.
useAppLocation
: The useAppLocation hook retrieves the location instance from the app-sdk by accessing the MarketplaceAppContext. It returns the location name (e.g., "CustomField") and the location instance.
Each route represents one location. It is recommended to lazy load the route components to reduce the bundle size.
- ConfigScreen
(path = "/config")
- CustomField
(path = "/custom-field")
- SelectorPage
(path = "/selector-page")
- Create a new Route component inside route. Use default export
- Inside
ui/src/containers/App/index.tsx
, lazy load the route component. Example:const ConfigScreen = React.lazy(() => import("../ConfigScreen"));
- Add the route wrapped inside
Suspense
. Example:<Route path="/config" element={ <Suspense fallback={<ConfigLoader />}> <AppConfigProvider> <ConfigScreen /> </AppConfigProvider> </Suspense> } />
- Inside
- This setup uses basic SCSS for styling
-
Go to developer hub at NA Region, EU Region, AZURE-NA Region, AZURE-EU Region.
-
Create a new app by clicking
+ New App
button at top right and Select app type asStack App
, add Name and Description. The app will be initially private. To make an app public on Contextstack Marketplace, refer App Submission and Approval Guide. -
After creating an app, you will be redirected to the Basic Information page. Add the icon for your app.
-
Open the UI Locations tab and add the URL of your app. For e.g. : https://localhost:4000
-
From Available location(s) , add App Configuration, Custom Field and JSON RTE.
-
For App Configuration, add path. The value of path is the route added for ConfigScreen in
<APP_DIRECTORY>/ui/src/containers/App/index.tsx
. Also we are using HashRouter for routing. So the value of path should be/#/config
. -
For Custom Field, add name and path. The value of path is the route added for CustomField in
<APP_DIRECTORY>/ui/src/containers/App/index.tsx
i.e./#/custom-field
. Select the Data Type asJSON
. -
For JSON RTE, add the name and path. For this location, there won’t be a route path in
<APP_DIRECTORY>/ui/src/containers/App/index.tsx
. We are serving webpack build file. For localhost, webpack file will be served ashttps://localhost:1268/dam.js
. So the path should be/dam.js
. For production environments, path should be/dist/dam.js
.
For all locations, Switch on the toggle for
Signed
if required. Switch on the toggle forEnabled
to enable the location. Add theDescription
if required.Note :-
- When hosting your app locally, you can't include a JSON RTE within the same app on the Developer Hub because it uses a different port. To work around this, after completion of the UI of the Configscreen, Customfield and Selectorpage, change the
App URL
in your app and set it to "https://localhost:1268" and add the JSON RTE with the path "/dam.js." - The App will now work on a different port but use the same configuration saved on configscreen. Here, the Configscreen and Customfield location will not be visible.
-
-
Now install the app by clicking the Install App button at top right. From the next window, select the stack in which you want to install the app.
Note : You can give any path values but make sure the path value in
<APP_DIRECTORY>/ui/src/containers/App/index.tsx
and in UI location should be the same.
After the app is installed, you can refer to the pages developed at various UI locations in the stack. Below are the various UI locations and their corresponding page in source code:
UI Location | Page Source |
---|---|
Config Screen | <APP_DIRECTORY>/ui/src/containers/ConfigScreen/index.tsx |
Custom Field | <APP_DIRECTORY>/ui/src/containers/CustomField/index.tsx |
RTE | <APP_DIRECTORY>/ui/rte/src/plugin.tsx |
To create build for development, staging and production environments, we have added build.sh file at the location <APP_DIRECTORY>/build.sh
Command to run the build script is
bash build.sh <UI_URL>
This command takes one argument, which is the UI URL of the app. We are taking this argument to rename the app URL as per the environment in the .env files of ui and ui/rte.
After the execution of the build script, the build folder will get created inside the ui folder. Inside that build folder, there will be a dist folder which has the webpack output files for RTE location. Other folders and files from the build folder will be for Configuration and Custom Field locations.
If you don’t want to use build script, then use below command
-
To create build for ui, navigate to ui
cd <APP_DIRECTORY>/ui npm run build
-
To create build for rte, navigate to rte
cd <APP_DIRECTORY>/ui/rte npm run build
You need to upload all the files from the build folder on AWS S3 or any static file hosting service of your preference.
To develop your Marketplace DAM App, you have to customize root_config
files for UI and rte_config
files for JSON RTE as per your needs.
Please refer to the TEMPLATE.md
file placed in <APP_DIRECTORY>/TEMPLATE.md
, for more details.
For reference purpose, Examples of DAM Apps like Bynder
and Cloudinary
are added to the 'example'
directory.
- Refer
<APP_DIRECTORY>/ui/example/bynder/root_config
directory for UI implementation of Bynder App. - Refer
<APP_DIRECTORY>/ui/example/bynder/rte_config
directory for JSON RTE implementation of Bynder App.