Create Your Microfrontend's Repository

Note that throughout this How-to we use XXX to represent the name of your repository/app, and YYY to represent the sub-domain you've chosen.

  1. Pick a name.  It should follow the convention: frontend-app-XXX.

    1. The repo name may or may not correspond with the sub-domain.  Examples:

      1. frontend-app-profile is served at profile.edx.org

      2. frontend-app-ecommerce is served at orders.edx.org

      3. If you can keep it one word it will make things easier

  2. We have a GitHub template repository to help bootstrap your new application.

    1. If you have permission to create new repositories:

      1. Visit https://github.com/edx/frontend-template-application

      2. Click the "Use this template" button.

      3. Put in your chosen micro-frontend application name.

      4. Make sure to create it in the edX organization.

    2. If you do not have permission to create a new repository:

      1. Get someone to do the above steps for you.  You can read through How to request a new GitHub Repo to find a way to get someone to help you.

    3. Do a find and replace in your new repository to replace frontend-template-application with frontend-app-XXX.

    4. Similarly, there's an example module which demonstrates a basic module.  Feel free to rename the "example" directory or delete it.

  3. Add a link to your new repo to Frontend Repos.

  4. If you are replacing an existing legacy frontend, update MFE Rewrite Status accordingly.


Setup Automated Deployment

We serve our frontend applications from S3 through CloudFlare distributions.  We deploy them with GoCD. We manage the creation of these resources/pipelines via configuration in edx/terraform and edx/edx-internal.

In this section you will be creating a series of pull requests for the following:

  1. The AWS resources like the S3 Bucket and Route53 domain name

    1. To add these you will need to open a PR to https://github.com/edx/terraform (e.g. https://github.com/edx/terraform/pull/2728/files)

    2. The Route53 domain and S3 Bucket are created using the frontend.hostname variable (the creation of which you can see in the above PR)

  2. The remote config blocks for Related Django services

    1. To add these you will need to open a PR to https://github.com/edx/edx-internal and optionally https://github.com/edx/edge-internal (e.g. https://github.com/edx/edx-internal/pull/2374/files)

  3. The GoCD deployment pipelines

    1. See https://github.com/edx/edx-internal/blob/master/gocd/README#L31-L39

  4. Sandboxes

    1. Beware of dragons, this will require a PR to https://github.com/edx/configuration , please see How To Add an MFE to a Sandbox for more information.

After all your PRs are made, you will create an SRE Support ticket or a ticket to your eSRE for review.


1: edx/terraform

Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. This repo contains terraform modules for deploying our applications on AWS, Cloudflare, NewRelic, Kubernetes and Snowflake.

note

Here we will leverage an existing frontend terraform module for provisioning new frontend infrastructure.

Here we will leverage an existing frontend terraform module for provisioning new frontend infrastructure.

Create a branch/PR with the following changes:

  1. In edx/terraform, create two files:

    plans/edx/prod-frontends/frontend-app-XXXXX.tf

    variable "frontend_app_XXXXX_hostname" {
      type        = string
      description = "Hostname of the frontend-app-XXXXX used for bucket naming and routing"
    }
    
    module "frontend_app_XXXXX_frontend" {
      source                     = "../../../modules/frontends/frontend"
      cloudflare_record_name     = "XXXXX"
      route53_zone_id            = var.route53_zone_id_edx_org
      frontend_hostname          = var.frontend_app_XXXXX_hostname
      internal_frontend_hostname = "${var.environment}-XXXXX.edx.org"
      aws_region                 = var.aws_region
      deployer_user              = aws_iam_user.frontend_deployer_user.arn
      cloudflare_zone_id         = var.cloudflare_zone_id_edx_org
      cdn_type                   = "cloudflare"
    }
    


    plans/edx/stage-frontends/frontend-app-XXXXX.tf

    variable "frontend_app_XXXXX_hostname" {
      type        = string
      description = "Hostname of the frontend-app-XXXXX used for bucket naming and routing"
    }
    
    module "frontend_app_XXXXX_frontend" {
      source                     = "../../../modules/frontends/frontend"
      cloudflare_record_name     = "XXXXX.stage"
      route53_zone_id            = var.route53_zone_id_edx_org
      frontend_hostname          = var.frontend_app_XXXXX_hostname
      internal_frontend_hostname = "${var.environment}-XXXXX.edx.org"
      aws_region                 = var.aws_region
      deployer_user              = aws_iam_user.frontend_deployer_user.arn
      cloudflare_zone_id         = var.cloudflare_zone_id_edx_org
      cdn_type                   = "cloudflare"
    }
    

    Note the only difference between the stage plan and the prod plan is the cloudflare_record_name. For examples, see the existing plans/edx/prod-frontends/frontend-app-* configurations.

  2. Add variables for your application for stage and prod:

    plans/edx/prod-frontends/terraform.tfvars

    ...
    
    # frontend-app-XXXXX
    frontend_app_XXXXX_hostname = "YYYYY.edx.org"


    plans/edx/stage-frontends/terraform.tfvars

    ...
    
    # frontend-app-XXXXX
    frontend_app_XXXXX_hostname = "YYYYY.stage.edx.org"

  3. Optional for edge deployment

  1. plans/edge/prod-frontends/frontend-app-XXXXX.tf

    variable "frontend_app_XXXXX_hostname" {
      type        = string
      description = "Hostname of the frontend-app-XXXXX used for bucket naming and routing"
    }
    
    module "frontend_app_XXXXX_frontend" {
      source                     = "../../../modules/frontend"
      cloudflare_record_name     = "XXXXX.edge"
      route53_zone_id            = var.route53_zone_id_edx_org
      frontend_hostname          = var.frontend_app_XXXXX_hostname
      internal_frontend_hostname = "${var.environment}-XXXXX.edx.org"
      aws_region                 = var.aws_region
      deployment                 = var.deployment
      deployer_user              = aws_iam_user.frontend_deployer_user.arn
      cloudflare_zone_id         = var.cloudflare_zone_id_edx_org
      cdn_type                   = "cloudflare"
      logging_target_bucket      = "edx-edge-s3-logs"
    }
  2. plans/edge/prod-frontends/terraform.tfvars

    ...
    
    # frontend-app-XXXXX
    frontend_app_XXXXX_hostname = "YYYYY.edge.edx.org"

2: edx/edx-internal (and edge-internal)

EdX Internal is a private configuration repo for the edx.org deployment. It contains private but not restricted/secure data. Here we will add configuration variable files for your frontend application to edx-internal/frontends.

Create a branch/PR with the following changes.

If you're setting up NewRelic alerts, or Segment tracking there's additional configuration to define (NEW_RELIC_APP_ID and SEGMENT_KEY) in this repository that's described below.  You may want to do it as part of the same PR to save time.

Optional: ecommerce access

Note that this is only necessary if you intend to call APIs in ecommerce.  We used this for frontend-app-ecommerce, for instance.

If you need to call ecommerce, you need to add your domain to the CORS_ORIGIN_WHITELIST variables

  1. Add the following changes to your edx-remote-config PR/branch.

  2. Add your domain in:

    CORS_ORIGIN_WHITELIST:
      - orders.edx.org
      - YYY.edx.org

  3. Also add it in ansible/vars/stage-edx.yml

    CORS_ORIGIN_WHITELIST:
      - orders.stage.edx.org
      - YYY.stage.edx.org

Optional: edge-internal configuration for edge deployment

Add configuration for edge deployments in https://github.com/edx/edge-internal

Create a branch/PR with the following changes.

  • Create a subdirectory in edge-internal/frontends for your app: edge-internal/frontends/frontend-app-XXX

  • Add the following file:

    prod_config.yml

    S3_BUCKET_NAME: "YYY.edx.org"
    APP_CONFIG:
      BASE_URL: "https://YYY.edx.org"
      # This is not secure, as it will be exposed in the client for the purpose
      # of sending tracking events to Segment.
      SEGMENT_KEY: ""
      NEW_RELIC_APP_ID: ""

    For examples, see the existing frontend-app-* configurations in edge-internal/frontends.

  • Add some variables for your application in

  • EDXAPP_XXX_MICROFRONTEND_URL is used to let the LMS link to your frontend.
    EDXAPP_CORS_ORIGIN_WHITELIST allows requests to LMS from your frontend.
    EDXAPP_LOGIN_REDIRECT_WHITELIST allows the LMS login process to redirect to your frontend.

    edge-remote-config/prod/lms.yml

    CORS_ORIGIN_WHITELIST:
      - "edx.org"
      - "www.edx.org"
      ...
      - "YYY.edx.org"
    
    LOGIN_REDIRECT_WHITELIST:
      - "www.edx.org"
      - "course.edx.org"
      ...
      - "YYY.edx.org"

GoCD Pipeline Steps

We define our GoCD pipelines and their stages, jobs, and tasks in yaml. Here we will provision GoCD deployment pipelines for our app.

Create a PR/branch with the following changes.

  1. Add your frontend application to  in order to provision Go CD pipelines. 
    See:
    https://github.com/edx/edx-internal/blob/master/gocd/README#L31-L39

  2. Your pipelines will be generated once your PR is merged.

Enable edge deployment

In the config https://github.com/edx/edx-internal/blob/master/gocd/generated-pipelines/frontend-generator-inputs.yaml  flip is_deployed_to_edge to true and make a PR, your pipeline definition will be regenerated with an edge deployment.

4: edx/configuration (optional)

Note that this section is only necessary if you intend to have links from the LMS to your microfrontend.  

This repository is a collection of tools and scripts that edx.org uses to deploy openedx. The purpose of this repository is to share portions of our toolchain with the community.  This directory contains ansible playbooks that can be used to configure individual services in the openedx platform.

Create a PR/branch with the following changes:

  1. Edit playbooks/roles/edxapp/defaults/main.yml to add the microfrontend URL defined above in edx/edx-internal.  

    ...
    # Needed to link to the new XXX micro-frontend.
    EDXAPP_XXX_MICROFRONTEND_URL: null
    
     #-------- Everything below this line is internal to the role ------------


  2. Also add it to the lms_env_config in the same file:

    lms_env_config:
      <<: *edxapp_generic_env
      ...
      XXX_MICROFRONTEND_URL: "{{ EDXAPP_XXX_MICROFRONTEND_URL }}"

Wondering where in the file these two code blocks can be found?

The first is about here: playbooks/roles/edxapp/defaults/main.yml#L950

The second "lms_env_config" block starts here: playbooks/roles/edxapp/defaults/main.yml#L1420



Setup Devstack

You should be able to run your micro-frontend out-of-the-box with:

<start your required backend services>
cd <your frontend repository>
npm install
npm start

However, the next two optional steps may make development a bit more seamless.

Allow LMS login redirection in Devstack

Add your MFE to Devstack

Adding your MFE to the devstack repository is optional. The main benefit is that you will be able to bring up the MFE and any required backend services with a singular command: make dev.up.frontend-app-XXXX. Whether or not you do this step, you should be able to run your MFE directly with npm install && npm start.

If you choose to add it to Devstack, here is an example PR to follow: https://github.com/edx/devstack/pull/556/files. For the depends_on key in docker-compose.yml, specify the backend services that your MFE needs running in order to function.


Setup Segment

  1. See /wiki/spaces/AN/pages/938705325

  2. Add the Segment write keys (SEGMENT_KEY) to prod_config.yml and stage_config.yml in your edx-internal/frontends sub-directory. You created it above during "Setup Automated Deployment".

  3. Make sure that you are using frontend-platform's builtin support for segment page tracking by using PageRoute, which is a drop-in replacement for react’s normal Route. (Or alternatively, AuthenticatedPageRoute for login-required pages.)

    import { PageRoute } from '@edx/frontend-platform/react';
    ...
      <PageRoute path="/an/example/url" component={AnExamplePage} />
  4. Verification:


Setup New Relic

We use this procedure to insert Browser's JavaScript snippet for browser monitoring into our frontends, see New Relic’s docs for more details.

See "prod-frontend-app-profile" and "stage-frontend-app-profile" for example configurations.

  1. Go to one.newrelic.com  > Browser > Add more data

  2. Click on “New Relic Browser”.

  3. Select Copy/Paste JavaScript Code, leave Pro + SPA checked and switch on Distributed Tracing.

  4. Enter an app name as "prod-frontend-app-XXX" and click Enable

  5. In the Javascript snippet that appears, copy the "applicationID" value out of the last line before the closing </script> tag:

    ;NREUM.info={beacon:"bam.nr-data.net",errorBeacon:"bam.nr-data.net",licenseKey:"1beac94c95",applicationID:"YOU WANT THIS ID HERE",sa:1}

  6. Add the NewRelic application ID you just copied to prod_config.yml as its NEW_RELIC_APP_ID value.  You created this file during "Setup Automated Deployment" in your edx-internal/frontends sub-directory. 

  7. Repeat steps 1 through 6 for stage_config.yml.  You should have a different application ID for staging.


Setup New Relic alerts in Opsgenie

Note that your alerting needs may differ from other apps.

FYI – Alerts used to be set up via terraform via terraform/plans/newrelic/edx/channels.tf

  1. If your team doesn’t already have a New Relic integration, go to Opsgenie > Teams and choose a team

    1. Click integrations.

    2. Click Add Integration

    3. Search for New Relic (New) and click add

    4. Follow the instructions on the page to use the api key to add a notification channel in New Relic.

  2. Go to New Relic Browser

  3. Under your app go to alert conditions

  4. Click Manage Alert Policies and search for the name of your app to find its alert policy

  5. Add an Apdex and JS Error conditions as seen here https://one.nr/0mMRNPPqlQn for prod-frontend-app-learning

  6. Add a New Relic notification channel

    1. If your team doesn’t already have one, you may need to ask your eSRE or file an SRE support ticket to copy in the API key from the Opsgenie integration.


Create a support ticket with SRE for your PRs

At this point you'll want to create an SRE ticket to review your PRs and give you a sanity check on everything else.

  1. The creation of the ticket depends on whether you have an eSRE on your team. If you do & you’re not sure what process to follow, consult them.

    1. If your team does not have an eSRE, then you should create a SRE Support ticket via the old process.

  2. In filing the ticket, include links to all the PRs you created above.

  3. Include also your Opsgenie New Relic API Key if you want to set up alerting.


Add Annotated Feature Toggle

This is only needed if you want a rollout feature toggle (from LMS for example) to your new page.


Configure i18n Jenkins and Transifex

  1. Follow

    1. New docs in @edx/frontend-platform https://github.com/edx/frontend-platform/blob/master/docs/how_tos/i18n.rst  

    2. Old docs for @edx/frontend-i18n i18n how-to documentation

    3. If you created the shell of your application code as described above, many of the steps in this documentation will already be done for you.

  2. Actual i18n code should be completed separately as strings are added to the code.


Backend JWT Cookies Support

At this point, most IDAs support JWT cookie, but not all.