Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: add contribution guide for device mode integration #1979

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 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
212 changes: 202 additions & 10 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ Thanks for taking the time and for your help in improving this project!

## RudderStack Contributor Agreement

To contribute to this project, we need you to sign the [**Contributor License Agreement (“CLA”)**][CLA] for the first commit you make. By agreeing to the [**CLA**][CLA]
we can add you to list of approved contributors and review the changes proposed by you.
To contribute to this project, we need you to sign the [**Contributor License Agreement (“CLA”)**][CLA] for the first commit you make. By agreeing to the [**CLA**][CLA] we can add you to list of approved contributors and review the changes proposed by you.

## Contribute to this project

Expand All @@ -28,19 +27,19 @@ One way you can contribute to this project is by adding integrations of your cho

### How to build the SDK

- Look for run scripts in the `package.json` file for getting the browser minified and non-minified builds. The builds are updated in the `dist` folder of the directory. Among the others, some of the important ones are:
- Look for run scripts in the `package.json` file for getting the builds. The builds are updated in the `dist` directory of corresponding package directories. Among the others, some of the important ones are:

- `npm run build:browser`: This outputs **rudder-analytics.min.js**.
- `npm run build:npm`: This outputs **rudder-sdk-js** folder that contains the npm package contents.
- `npm run build:integration:all`: This outputs **integrations** folder that contains the integrations.
- `npm run build:browser:modern`: This outputs **dist/cdn/modern** folder that contains the CDN package contents.
- `npm run build:npm:modern`: This outputs **dist/npm/modern** folder that contains the NPM package contents.
- `npm run build:integrations`: This outputs **dist/cdn/legacy** and **dist/cdn/modern** folders that contains the integration SDKs.

> We use **rollup** to build our SDKs. The configurations for them are present in `rollup-configs` folder.

- For adding or removing integrations, modify the imports in `index.js` under the `src/integrations` folder.
> We use **rollup** to build our SDKs. Each package directory contains the configuration for it in `rollup.config.mjs`.

## Committing

We prefer squash or rebase commits so that all changes from a branch are committed to master as a single commit. All pull requests are squashed when merged, but rebasing prior to merge gives you better control over the commit message.
Please raise a pull request from your forked repository to the `develop` branch of the main repository.

We prefer squash commits so that all changes from a branch are committed to `develop` branch as a single commit. All pull requests are squashed when merged, but rebasing prior to merge gives you better control over the commit message.

## Installing and setting up RudderStack

Expand All @@ -51,6 +50,199 @@ To contribute to this project, you may need to install RudderStack on your machi
For any questions, concerns, or queries, you can start by asking a question on our [**Slack**](https://rudderstack.com/join-rudderstack-slack-community/) channel.
<br><br>

----
# Guide to develop your first device mode RudderStack integration

Before diving into RudderStack integration development, it's essential to understand the [RudderStack Event Specification](https://www.rudderstack.com/docs/event-spec/standard-events/). This specification serves as the foundation for collecting data in a consistent format and then transforming data for the target destinations. In this guide, we'll focus specifically on developing a destination integration in device mode integration type.

## Understanding integration types
RudderStack supports two primary integration modes:

1. **Cloud Mode Integration**: Events are routed through the RudderStack data plane in this mode
2. **Device Mode Integration**: Events are sent directly from the client to the destination in this mode

## Device mode integration development journey

### 1. Initial setup and configuration
First, you'll need to configure the RudderStack UI in the [`rudder-integrations-config`](https://github.com/rudderlabs/rudder-integrations-config) repository:
- Navigate to [`src/configurations/destinations`](./src/configurations/destinations)
- Add necessary configuration files for dashboard setup
- Prepare integration documentation or planning documents

#### UI configuration
Two approaches for adding UI configurations:

1. **Manual configuration**
- Add config files in `src/configurations/destinations`
- Use existing templates as reference

2. **Automated generation**
```bash
python3 scripts/configGenerator.py <path-to-placeholder-file>
```

### 2. Core development steps

#### Setting up the development environment
```bash
# Clone the repository
git clone https://github.com/rudderlabs/rudder-sdk-js

# Setup the project
npm run setup

# To reset the project setup
npm run clean && npm cache clean --force && npm run setup
```
gitcommitshow marked this conversation as resolved.
Show resolved Hide resolved

#### Essential components
Your integration will require several key files:

1. **Constants definition** (`/packages/analytics-js-common/src/constants/integrations`)
- Integration name
- Display name
- Directory name

The integration and display names should be referred from the auto-generated file in `/packages/analytics-js-common/src/constants/integrations/Destinations.ts`. See the existing integrations for reference.

The directory name is the name of the integration directory in the `packages/analytics-js-integrations/src/integrations` directory. It should not contain any special characters or spaces.

2. **Main integration code** (`packages/analytics-js-integrations/src/integrations`)
```javascript
// browser.js structure
class TestIntegrationOne {
constructor(config, analytics, destinationInfo) {
// initialization code
}

init() {
// SDK initialization
}

// Core methods
isLoaded() { /**Your destination SDK is loaded successfully**/}
isReady() { /**At this point, you can start sending supported events to your destination e.g. track, identify, etc.**/ }

// Event handling
identify(rudderElement) {}
track(rudderElement) {}
page(rudderElement) {}
alias(rudderElement) {}
group(rudderElement) {}
}
```
gitcommitshow marked this conversation as resolved.
Show resolved Hide resolved

- `config` object contains the destination configuration settings.
- You can refer to individual configuration settings using `config.<setting_name>`.
- `analytics` object is the RudderStack SDK instance.
- It supports all the standard methods like `track`, `identify`, `page`, etc. along with getter methods like `getAnonymousId`, `getUserId`, etc.
- `rudderElement` object is a wrapper around the actual standard RudderStack event object.
```json
{
"message": <Event payload>
}
```

### 3. Building and testing

#### Build process
```bash
# For legacy build
npm run build:integration --environment INTG_NAME:TestIntegrationOne

# For modern build
npm run build:integration:modern --environment INTG_NAME:TestIntegrationOne
```

#### Testing setup
1. Serve the bundle:
```bash
npx serve dist/cdn/js-integrations
```
The bundle will be served at `http://localhost:3000`.

2. Configure test environment:
- Modify `packages/analytics-js/public/index.html` to mock source configuration data and point to the local integrations bundle.
```javascript
rudderanalytics.load(writeKey, dataPlaneUrl, {
destSDKBaseURL: 'http://localhost:3000',
getSourceConfig: () => ({
updatedAt: new Date().toISOString(),
source: {
// Use valid values from RS dashboard
name: SOURCE_NAME,
id: SOURCE_ID,
workspaceId: WORKSPACE_ID,
writeKey: WRITE_KEY,
updatedAt: new Date().toISOString(),
config: {
statsCollection: {
errors: {
enabled: false
},
metrics: {
enabled: false
},
}
},
enabled: true,
destinations: [
{
config: {
id: 'someId',
... add other properties as needed
},
id: 'dummyDestinationId',
enabled: true,
deleted: false,
destinationDefinition: {
name: 'TestIntegrationOne',
displayName: 'Test Integration One',
}
}
]
}
})
});
```
gitcommitshow marked this conversation as resolved.
Show resolved Hide resolved
- Set environment variables (WRITE_KEY, DATAPLANE_URL) in `.env` file.
- Run `npm run start`

### 4. Automated testing
Implement automated tests for your integration:

```bash
# Run tests for specific integration at packages/analytics-js-integrations/
npm run test -- TestIntegrationOne/
```

## Deployment and support
Once development is complete:
1. The RudderStack team will handle production deployment
2. An announcement will be made in the [Release Notes](https://www.rudderstack.com/docs/releases/) and Slack `#product-releases` channel
3. Ongoing support is available through:
- GitHub PR feedback
- [RudderStack Slack community](https://rudderstack.com/join-rudderstack-slack-community/) `#contributing-to-rudderstack` channel

gitcommitshow marked this conversation as resolved.
Show resolved Hide resolved
## Best practices
- Draft the integration plan document before coding
- Be judicious in choosing where you want to allow integration users to configure settings (in the control plane vs the sdk instrumentation code)
- Follow existing integration examples
- Document all configuration options
- Keep code modular and maintainable

Building a RudderStack integration requires attention to detail and thorough testing. The RudderStack team provides support throughout the development process, ensuring your integration meets quality standards and works reliably in production.

## References

- [RudderStack community on Slack](https://rudderstack.com/join-rudderstack-slack-community/)
- [Recording of the community workshop to develop device mode integration](https://youtu.be/70w2ESMBPCI)
- [Guide to develop source and cloud mode destination integration](https://github.com/rudderlabs/rudder-transformer/blob/develop/CONTRIBUTING.md)
- [Recording of the community workshop to develop source and cloud mode integration](https://youtu.be/OD2vCYG-P7k)
- [RudderStack Event Specification](https://www.rudderstack.com/docs/event-spec/standard-events/)

----

### We look forward to your feedback on improving this project!

<!----variables---->
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"build:modern:ci": "nx affected -t build:modern --base=$BASE_REF",
"build:browser": "nx run-many -t build:browser",
"build:browser:modern": "nx run-many -t build:browser:modern",
"build:npm:modern": "nx run-many -t build:npm:modern",
"build:package": "nx run-many -t build:package",
"build:package:modern": "nx run-many -t build:package:modern",
"package": "nx run-many -t package",
Expand Down
Loading