A Comprehensive Guide to Managing Environment Configurations in JoyID-based CKB Applications

Introduction

As a developer of JoyID-based CKB applications, managing environment configurations can be a time-consuming and error-prone task. With different environments (e.g., development, staging, production) requiring different configurations, it can be difficult to keep track of all the variables and settings. In this guide, we will provide a comprehensive solution to this problem by introducing a config.js file that can manage different configurations for different environments.

Although this guide is based on Create React App, I believe other frameworks should be similar, and only minor modifications may be needed to adapt to them. Let’s start it!

Guide

Step 1: Create a config.js file

The first step is to create a config.js file in the root directory of your JoyID-based CKB application. This file will contain all the environment-specific configurations and variables. We’ll edit it in step 3.

your_app/
├── build/
├── node_modules/
├── public/
├── src/
├── config.js
├── package.json
├── README.md
└── …

Step 2: Define environment variables

Next, define environment variables for each environment you want to support (e.g., development, staging, production). You can define these variables using the process.env object in Node.js, or by using a package like dotenv:

your_app/
├── build/
├── node_modules/
├── public/
├── src/
├── config.js
├── .env.development
├── package.json
├── README.md
└── …

Then edit the env file:
image

Step 3: Define configuration objects

Edit the config.js file, for each environment, define a configuration object that contains all the configuration variables and settings for that environment. Here is my config.js file:

import { predefined } from "@ckb-lumos/config-manager";

const prodConfig = {
    CKB: {
        CKB_RPC_URL: "https://mainnet.ckb.dev/rpc",
        CKB_INDEXER_URL: "https://mainnet.ckb.dev/indexer",
        CKB_EXPLORER_URL: "https://explorer.nervos.org/",
        PREFIX: "ckb",
        SCRIPTS: predefined.LINA.SCRIPTS,
    },
    JOYID: {
        SCRIPT: {
            CODE_HASH: "0xd00c84f0ec8fd441c38bc3f87a371f547190f2fcff88e642bc5bf54b9e318323",
            HASH_TYPE: "type",
            TX_HASH: "0xf05188e5f3a6767fc4687faf45ba5f1a6e25d3ada6129dae8722cb282f262493",
            INDEX: "0x0",
            DEP_TYPE: "depGroup"
        },
        APP_CONFIG: {
            // your app name
            name: "JoyGift",
            // your app logo
            logo: "https://joygiftdev.netlify.app/logo192.svg",
            // 
            network: "mainnet",
            //
            // JoyID app url, optional
            joyidAppURL: "https://app.joy.id",
            // JoyID server url, optional
            joyidServerURL: "https://api.joy.id",
        }

    }
};

const devConfig = {
    CKB: {
        CKB_RPC_URL: "https://testnet.ckb.dev/rpc",
        CKB_INDEXER_URL: "https://testnet.ckb.dev/indexer",
        CKB_EXPLORER_URL: "https://pudge.explorer.nervos.org/",
        PREFIX: "ckt",
        SCRIPTS: predefined.AGGRON4.SCRIPTS,
    },
    JOYID: {
        SCRIPT: {
            CODE_HASH: "0xd23761b364210735c19c60561d213fb3beae2fd6172743719eff6920e020baac",
            HASH_TYPE: "type",
            TX_HASH: "0x4dcf3f3b09efac8995d6cbee87c5345e812d310094651e0c3d9a730f32dc9263",
            INDEX: "0x0",
            DEP_TYPE: "depGroup"
        },
        APP_CONFIG: {
            // your app name
            name: "JoyGift",
            // your app logo
            logo: "https://joygiftdev.xxx/logo192.svg",
            // 
            network: "testnet",
            //
            // JoyID app url, optional
            joyidAppURL: "https://testnet.joyid.dev",
            // JoyID server url, optional
            joyidServerURL: "https://api.joyid.dev",
        }

    }

};

const env = process.env.REACT_APP_ENV;

let appConfig;

if (env === "production") {
    appConfig = prodConfig;
} else if (env === "dev" || env === "staging") {
    appConfig = devConfig;
} else {
    appConfig = devConfig;
}

export default appConfig;

Step 4: Export the configuration object for the current environment

Finally, export the configuration object for the current environment based on the value of the REACT_APP_ENV environment variable. This can be done using a conditional statement that checks the value of REACT_APP_ENV and sets the appConfig variable accordingly.

Step 5: Use the configuration object in your application

Now that you have defined the environment-specific configuration objects, you can use them in your application code. For example, you can import the appConfig object into your React components and use the variables and settings as needed.

// Index.js
import appConfig from './config';
import { initConfig } from '@joyid/ckb';

initConfig(appConfig.JOYID.APP_CONFIG);

If your application needs to send on-chain transactions and query on-chain information, such as querying the balance of a CKB address, etc., you will need lumos. Before using lumos, and some initialization is required. The following function can do the job:

import {
    initializeConfig,
    createConfig
} from '@ckb-lumos/config-manager'
import appConfig from './config';

function initLumos() {
    initializeConfig(
        createConfig({
            PREFIX: appConfig.CKB.PREFIX,
            SCRIPTS: {
                ...appConfig.CKB.SCRIPTS,
                JOYID: {
                    ...appConfig.JOYID.SCRIPT,
                    pubkey: '',
                    keyType: 'main_key',
                    alg: '-7'
                },
            },
        })
    )
}

Conclusion

By using a config.js file to manage environment configurations, you can simplify the process of deploying and testing your JoyID-based CKB applications. With this approach, you can define all the environment-specific variables and settings in one place, and easily switch between different environments as needed. I hope this guide has been helpful, and welcome any feedback or suggestions for improvement.

Let’s build on CKB, go go go.

8 Likes

A new version of the config.js file in dapps.

// config.js

import { predefined } from "@ckb-lumos/config-manager";

// 下面配置的 Urls 用于应用 rpc 请求分流,通过 randomIndex 来决定加载哪一个,
// 注意:
// 1、每组 url 的数量保持一致,如果应用有自己的 rpc 服务,可自行添加
// 2、如果你希望某一个 url 的请求概率增加,则在 url 数组里多添加该地址即可,比如:
//  希望生产环境上 https://mainnet.ckb.dev 的请求数量是 https://mainnet.ckbapp.dev 的两倍,
//  则在 prodUrls 里,进行这样的配置即可:
/*
const prodUrls = {
    ckb_indexer_url: [
        "https://mainnet.ckb.dev",
        "https://mainnet.ckb.dev",
        "https://mainnet.ckbapp.dev",
    ],
    ckb_rpc_url: [
        "https://mainnet.ckb.dev",
        "https://mainnet.ckb.dev",
        "https://mainnet.ckbapp.dev",
    ]
}

const RPC_COUNT = 3;   
*/
const devdUrls = {
    ckb_indexer_url: [
        "https://testnet.ckb.dev",      
        "https://testnet.ckbapp.dev",
    ],
    ckb_rpc_url: [
        "https://testnet.ckb.dev",  
        "https://testnet.ckbapp.dev", 
    ]
}

const prodUrls = {
    ckb_indexer_url: [
        "https://mainnet.ckb.dev",
        "https://mainnet.ckbapp.dev",
    ],
    ckb_rpc_url: [
        "https://mainnet.ckb.dev",
        "https://mainnet.ckbapp.dev",
    ]
}

const RPC_COUNT = 2;

// 生成一个 0 到 RPC_COUNT - 1的随机整数,用于确定页面 rpc 请求的 url
const randomIndex = Math.floor(Math.random() * RPC_COUNT);

const prodConfig = {
    APP: {
        IS_MAINNET: true,
        API_BASE_URL:"https://api.your-dapp-domain",   
        MAX_DECIMAL_PART_LENGTH: 8,
        JOYID_BUY_CKB:"https://app.joy.id/exchange?token=ckb",
    },
    CKB: {
        CKB_RPC_URL: prodUrls.ckb_rpc_url[randomIndex],
        CKB_INDEXER_URL: prodUrls.ckb_indexer_url[randomIndex],
        CKB_EXPLORER_URL: "https://explorer.nervos.org",
        PREFIX: 'ckb',
        SCRIPTS: predefined.LINA.SCRIPTS,
    },
    JOYID: {
        SCRIPT: {
            CODE_HASH: "0xd00c84f0ec8fd441c38bc3f87a371f547190f2fcff88e642bc5bf54b9e318323",
            HASH_TYPE: "type",
            TX_HASH: "0xf05188e5f3a6767fc4687faf45ba5f1a6e25d3ada6129dae8722cb282f262493",
            INDEX: "0x0",
            DEP_TYPE: "depGroup"
        },
        APP_CONFIG: {
            // your app name
            name: 'your app name',
            // your app logo
            logo: 'https://your-dapp-domain/your-logo.svg',
            // 
            network: 'mainnet',
            //
            // JoyID app url, optional
            joyidAppURL: 'https://app.joy.id',
            // JoyID server url, optional
            joyidServerURL: 'https://api.joy.id',
        }
    }
};

const devConfig = {
    APP: {
        IS_MAINNET: false,
        API_BASE_URL:"https://test-api.your-dapp-domain",
        MAX_DECIMAL_PART_LENGTH: 8,
        JOYID_BUY_CKB:"https://testnet.joyid.dev/exchange?token=ckb",
    },
    CKB: {
        CKB_RPC_URL: devdUrls.ckb_rpc_url[randomIndex],
        CKB_INDEXER_URL: devdUrls.ckb_indexer_url[randomIndex],
        CKB_EXPLORER_URL: "https://pudge.explorer.nervos.org",
        PREFIX: 'ckt',
        SCRIPTS: predefined.AGGRON4.SCRIPTS,
    },
    JOYID: {
        SCRIPT: {
            CODE_HASH: "0xd23761b364210735c19c60561d213fb3beae2fd6172743719eff6920e020baac",
            HASH_TYPE: "type",
            TX_HASH: "0x4dcf3f3b09efac8995d6cbee87c5345e812d310094651e0c3d9a730f32dc9263",
            INDEX: "0x0",
            DEP_TYPE: "depGroup"
        },
        APP_CONFIG: {
            // your app name
            name: 'your app name',
            // your app logo
            logo: 'https://your-dapp-domain/your-logo.svg',
            // 
            network: 'testnet',
            //
            // JoyID app url, optional
            joyidAppURL: 'https://testnet.joyid.dev',
            // JoyID server url, optional
            joyidServerURL: "https://api.joyid.dev",
        }
    }

};

const env = process.env.REACT_APP_ENV;

let appConfig;

if (env === "production") {
    appConfig = prodConfig;
} else if (env === "dev" || env === "staging") {
    appConfig = devConfig;
} else {
    appConfig = devConfig;
}

export default appConfig;
1 Like