UI Extension

Unlike the way extensions are loaded locally in development mode, the ks-console running in production mode only discovers and loads extensions from the JSBundle API. After completing the frontend development, it’s necessary to package the code to generate JS Bundle files and inject the extension into ks-console through JSBundle resource declarations.

Package frontend extension

In the frontend project directory, use yarn build:ext <extension> to package the frontend extension, which will generate the index.js file in the extension source code directory extensions/<extensionName>/dist.

Using the hello-world extension in the extension-samples project as an example, let’s build the extension JS Bundle files in the following way:

➜  extension-samples git:(master) ✗ cd extensions-frontend 
➜  extensions-frontend git:(master) ✗ yarn build:ext hello-world
yarn run v1.22.17
ksc build:ext hello-world
Browserslist: caniuse-lite is outdated. Please run:
  npx update-browserslist-db@latest
  Why you should do it regularly: https://github.com/browserslist/update-db#readme
asset index.js 4.63 KiB [compared for emit] [minimized] (name: index)
webpack 5.74.0 compiled successfully in 525 ms

  Webpack Finished

✨  Done in 2.88s.
Show extensions/hello-world/dist/index.js

yarn-build-ext

Save JS Bundle Files via ConfigMap

Create a ConfigMap to store JS Bundle files in the default namespace.

➜  extension-samples git:(master) cd extensions-frontend 
➜  extensions-frontend git:(master) kubectl create configmap hello-world --from-file=extensions/hello-world/dist/index.js
configmap/hello-world created

Create JSBundle

JSBundle:

cat << EOF | kubectl apply -f -
apiVersion: extensions.kubesphere.io/v1alpha1
kind: JSBundle
metadata:
  name: hello-world
spec:
  rawFrom:
    configMapKeyRef:
      key: index.js
      name: hello-world
      namespace: default
status:
  link: /dist/hello-world/index.js
  state: Available
EOF

Explanation of JSBundle fields

apiVersion: extensions.kubesphere.io/v1alpha1
kind: JSBundle
metadata:
  name: hello-world
spec:
  rawFrom:
  # url: http://frontend.extension-hello-world.svc/dist/hello-world-ui/index.js
    configMapKeyRef:
      name: jsbundle
      key: index.js
      namespace: extension-hello-world
  # secretKeyRef:
  #   name: jsbundle
  #   key: index.js
  #   namespace: extension-hello-world
status:
  # The default generated static file address format is /dist/{extensionName}/index.js
  # The access address of static files can be manually specified as /dist/{extensionName}/{subPath}/{fileName}
  link: /dist/hello-world/index.js 
  state: Available
FieldDescription
spec.raw
spec.rawFrom.configMapKeyRef
spec.rawFrom.secretKeyRef
Small-sized JS Bundle files can be directly defined in the JSBundle declaration or saved by ConfigMap and Secret.
spec.rawFrom.urlLarge-sized JS Bundle files should be provided through an additional file service.

Create ExtensionEntry

In addition to configuring the mounting point in the menus section of the frontend JS/TS files of the extension, you can also configure it through ExtensionEntry.

The priority of ExtensionEntry is higher than menus. If valid mounting points are configured in both ExtensionEntry and menus, only the settings in ExtensionEntry will take effect, and the configurations in menus will be ignored.

Example of ExtensionEntry:

cat << EOF | kubectl apply -f -
apiVersion: extensions.kubesphere.io/v1alpha1
kind: ExtensionEntry
metadata:
  name: {{ include "frontend.fullname" . }}-extension-entries
spec:
  entries:
    - parent: "global"
      name: "hello-world"
      link: "/hello-world"
      title: "HELLO_WORLD"
      icon: "cluster"
      order: 0
      desc: "HELLO_WORLD_DESC"
      authKey: "hello"
      authAction: "hello-view"
      skipAuth: true
EOF

Explanation of ExtensionEntry Fields

The fields in ExtensionEntry are similar to those in menus, please refer to Configure a mount point for more information.