Skip to content

Instantly share code, notes, and snippets.

@joeldenning
Created June 12, 2019 13:17
Show Gist options
  • Save joeldenning/a3fbe21e1eb9ff930f4b8818181a5e66 to your computer and use it in GitHub Desktop.
Save joeldenning/a3fbe21e1eb9ff930f4b8818181a5e66 to your computer and use it in GitHub Desktop.

Creating a new single-spa subapp

  1. Create new repo in gitlab

  2. Clone it locally

  3. Create .babelrc in project root:

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react",
    ],
    "plugins": [
        // https://github.com/babel/babel-loader#babel-is-injecting-helpers-into-each-file-and-bloating-my-code
        "@babel/plugin-transform-runtime",
    ]
}
    
  1. create webpack config (webpack.config.js) in project root:
const path = require('path')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports = function(webpackOptions = {}) {
  return {
    entry: path.resolve(__dirname, 'src/<NAME_OF_PROJECT>.js'),
    output: {
      libraryTarget: '<system || amd>',
      filename: '<NAME_OF_PROJECT>.js',
      path: __dirname + path.sep + 'build',
    },
    module: {
      rules: [
        {
          test: /\.m?js$/,
          exclude: /(node_modules|bower_components)/,
          use: {
            loader: 'babel-loader',
          },
        },
        {
          parser: {
            system: false, // https://github.com/systemjs/systemjs#compatibility-with-webpack
          }
        },
      ],
    },
    devtool: 'sourcemap',
    devServer: {
      https: true,
      headers: {
        "Access-Control-Allow-Origin": "*",
      },
      disableHostCheck: true,
    },
    externals: [
      'react',
      'react-dom',
      'single-spa',
      /^@jump\/.+/,
    ],
    plugins: [
      new BundleAnalyzerPlugin({
        analyzerMode: webpackOptions.analyze ? 'server' : 'disabled',
      })
    ]
  }
}
  1. create directory /src
mkdir src
cd src
  1. in src, create the single-spa entry point
// src/[project-name].js
import React from 'react'
import ReactDOM from 'react-dom'
import singleSpaReact from 'single-spa-react'
import Root from './root.component'

const reactLifecycles = singleSpaReact({
  React,
  ReactDOM,
  rootComponent: Root,
})

export const bootstrap = reactLifecycles.bootstrap
export const mount = reactLifecycles.mount
export const unmount = reactLifecycles.unmount
export const devtools = {
  overlays: {
    selectors: [
      '#PROJECT_NAME'
    ]
  }
}
  1. create Root component
// /src/root.component

import React from 'react'

export default function Root(props) {
  return (
    <h1>
      hello world
    </h1>
  )
}
  1. create jest.json
{
  "setupFilesAfterEnv": [
    "<rootDir>/src/setup-tests.js"
  ]
}
  1. create src/setup-tests.js
import { configure } from "enzyme";
import Adapter from "enzyme-adapter-react-16";

configure({ adapter: new Adapter() });
  1. create .eslintrc
{
  "extends": "jump-software"
}
  1. In the terminal create an .nvmrc file $ echo "v10.15.3" > .nvmrc

The file will include an empty second line (which is required by nvm)

You'll need to have NVM installed. https://github.com/creationix/nvm#installation-and-update

$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash

  1. create .gitlab-ci.yml
image: node:10-slim

stages:
  - setup
  - build
  - deploy-stage
  - deploy-prod

install:
  stage: setup
  script: npm ci
  artifacts:
    paths:
      - node_modules

test:
  stage: build
  script: npm test
  dependencies:
    - install

build:
  stage: build
  script: npm run build
  dependencies:
    - install
  artifacts:
    paths:
      - build

lint:
  stage: build
  script: npm run lint
  dependencies:
    - install

check-format:
  stage: build
  script: npm run check-format
  dependencies:
    - install

.deploy:
  image: registry.gitlab.com/jump-software/aws-tools:latest
  before_script:
    - echo "Commit sha is $CI_COMMIT_SHORT_SHA. This will be the directory name under $CI_PROJECT_NAME in S3."
  script:
    - aws s3 sync build/ s3://$DEPLOYER_BUCKET/$CI_PROJECT_NAME/$CI_COMMIT_SHORT_SHA --cache-control max-age=31536000
    - echo "Updating import map"
    - curl -u $DEPLOYER_USERNAME:$DEPLOYER_PASSWORD -d '{ "service":"@jump/'"$CI_PROJECT_NAME"'","url":"https://'"$CF_PUBLIC_URL"'/'"$CI_PROJECT_NAME"'/'"$CI_COMMIT_SHORT_SHA"'/'"$CI_PROJECT_NAME"'.js" }' -X PATCH https://$DEPLOYER_HOST/services\?env=$CI_ENVIRONMENT_NAME -H "Accept:application/json" -H "Content-Type:application/json"
  dependencies:
    - build
  only:
    - master

deploy-stage:
  extends: .deploy
  stage: deploy-stage
  environment:
    name: stage
  variables:
    DEPLOYER_BUCKET: '$STAGING_SINGLESPA_BUCKET'
    DEPLOYER_HOST: '$STAGING_DEPLOYER_HOST'
    CF_PUBLIC_URL: app.staging.jumpsoftware.com

deploy-prod:
  extends: .deploy
  stage: deploy-prod
  environment:
    name: prod
  variables:
    DEPLOYER_BUCKET: '$PRODUCTION_SINGLESPA_BUCKET'
    DEPLOYER_HOST: '$PRODUCTION_DEPLOYER_HOST'
    CF_PUBLIC_URL: app.jumpsoftware.com
  when: manual
  1. add a package.json
{
  "name": "[project-name]",
  "description": "New single-spa application",
  "scripts": {
    "start": "webpack-dev-server --port",
    "build": "webpack --mode=production",
    "analyze": "webpack --mode=production --env.analyze=true --watch",
    "prettier": "pretty-quick --pattern \"src/**/*\" --pattern \"__mocks__/**/*\"",
    "check-format": "prettier --check \"{src,__mocks__}/**/*.{js,css}\"",
    "lint": "eslint src",
    "test": "jest --config jest.json",
    "test:watch": "jest --config jest.json --watch"
  },
  "husky": {
    "hooks": {
      "pre-commit": "npm run prettier -- --staged && npm run lint"
    }
  }
}
  1. add .gitignore
node_modules
build
.DS_Store
  1. install dependencies
npm install --save react react-dom single-spa-react

npm install --save-dev @babel/core @babel/preset-env @babel/preset-react @babel/runtime babel-eslint babel-loader enzyme eslint eslint-plugin-react-hooks husky jest jest-cli eslint-config-jump-software prettier webpack webpack-bundle-analyzer webpack-cli webpack-dev-server pretty-quick enzyme-adapter-react-16 @babel/plugin-transform-runtime
  1. start with [port]
npm start [port number]
  1. View your bundle size analysis
npm run analyze
  1. Verify that jest runs your tests
npm run test:watch
  1. Verify that prettier and eslint run when you do a git commit
git add .
git commit -m "Initial configuration"
  1. in single spa root: in index.js register the new app
registerApplication(
  "[project-name]",
  () => import("@jump/[project-name]"),
  location => true // activity function TBD
)
  1. Start single-spa-root. Then use the local storage override
localStorage.setItem('jump:overrides:package:@jump/single-spa-root', 'https://localhost:8000/index.js')
localStorage.setItem('jump:overrides:package:@jump/[app-name]', 'https://localhost:[** port from above]/[app-name].js')
  1. Set environment variables in Gitlab Go to springboard-client's environment variables and copy paste them into your project's gitlab settings.

  2. Merge/push your code to master and verify it deploys to stage correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment