diff --git a/packages/element-web-module-api/Dockerfile b/packages/element-web-module-api/Dockerfile index 70f589b8c5..a858dc6aed 100644 --- a/packages/element-web-module-api/Dockerfile +++ b/packages/element-web-module-api/Dockerfile @@ -1,19 +1,23 @@ ARG ELEMENT_VERSION=latest -FROM vectorim/element-web:${ELEMENT_VERSION} -ARG ELEMENT_WEB_MODULES="" -# Override default nginx config. Templates in `/etc/nginx/templates` are passed -# through `envsubst` by the nginx docker image entry point. -COPY /docker/nginx-templates/* /etc/nginx/templates/ -COPY /docker/docker-entrypoint.d/* /docker-entrypoint.d/ +FROM --platform=$BUILDPLATFORM node:lts-alpine AS builder -# Create directories before we gain privileges -RUN mkdir -p /tmp/element-web-config /tmp/element-web-modules +ARG BUILD_CONTEXT -# Escalate privileges to install jq and moreutils and run the fetch modules script -USER root -RUN apk add jq moreutils -RUN ELEMENT_WEB_MODULES=${ELEMENT_WEB_MODULES} /docker-entrypoint.d/17-fetch-element-modules.sh +RUN apk add --no-cache jq -# Drop privileges back to nginx -USER nginx \ No newline at end of file +WORKDIR /app +COPY package.json yarn.lock ./ +COPY ./$BUILD_CONTEXT/package.json ./$BUILD_CONTEXT/ +RUN yarn install --frozen-lockfile --ignore-scripts +COPY tsconfig.json ./ +COPY ./$BUILD_CONTEXT ./$BUILD_CONTEXT +RUN cd $BUILD_CONTEXT && yarn vite build +RUN mkdir /modules +RUN cp -r ./$BUILD_CONTEXT/lib/ /modules/$(jq -r '"\(.name)-v\(.version)"' ./$BUILD_CONTEXT/package.json) + +FROM ghcr.io/element-hq/element-web:${ELEMENT_VERSION} +ARG ELEMENT_VERSION=latest +ARG BUILD_CONTEXT + +COPY --from=builder /modules/* /tmp/element-web-modules/ \ No newline at end of file diff --git a/packages/element-web-module-api/README.md b/packages/element-web-module-api/README.md index d1f3c94fc5..93186ed438 100644 --- a/packages/element-web-module-api/README.md +++ b/packages/element-web-module-api/README.md @@ -4,28 +4,6 @@ API surface for extending Element Web in a safe & predictable way. This project is still in early development but aims to replace matrix-react-sdk-module-api and Element Web deprecated customisations. -## Using the Docker image - -The docker image specified by the Dockerfile in this directory can be used in one of four ways. - -You can specify `ELEMENT_WEB_MODULES` as a build-arg or as a runtime environment variable to fetch & load a module -from a remote URL at runtime or to bundle it into the docker image for easier deployment respectively. -The format this variable should take is a comma-delimited list of URLs followed by the optional tarball hash after a `#` character, e.g. -`ELEMENT_WEB_MODULES=https://example.com/module.tgz#abc123,https://example.com/another-module.tgz#`. - -You can also use it as a base image and add your desired modules into `/tmp/element-web-modules` each in their own directory. -Finally, you can bind mount modules into the `/tmp/element-web-modules` directory at runtime. -The default entrypoint will be index.js in that directory but can be overriden if a package.json file is found with a `main` directive. - -The container expects a config.json file to be bind mounted or copied into the `/app/config.json` path. -The container runs an nginx web server in rootless mode on port 8080. -If you wish to use docker in read-only mode, you should follow the [upstream instructions](https://hub.docker.com/_/nginx#:~:text=Running%20nginx%20in%20read%2Donly%20mode) -but additionally include the following directories: - -- /tmp/element-web-modules/ -- /tmp/element-web-config/ -- /etc/nginx/conf.d/ - ## Using the API Modules are loaded by Element Web at runtime via a dynamic ecmascript import, but can be bundled into a webapp for deployment convenience. @@ -74,6 +52,10 @@ class ExampleModule implements Module { // ... ``` +## Releases + +The API is versioned using semver, with the major version incremented for breaking changes. + ## Copyright & License Copyright (c) 2025 New Vector Ltd diff --git a/packages/element-web-module-api/docker/docker-entrypoint.d/17-fetch-element-modules.sh b/packages/element-web-module-api/docker/docker-entrypoint.d/17-fetch-element-modules.sh deleted file mode 100755 index ff57e90d53..0000000000 --- a/packages/element-web-module-api/docker/docker-entrypoint.d/17-fetch-element-modules.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -# Loads modules specified via env var ELEMENT_WEB_MODULES -# in a comma delimited format of `url#hash,url#hash,...` -# the URL should point to a gzipped tarball, e.g. https://registry.npmjs.org/level/-/level-9.0.0.tgz -# the hash should a sha256sum of the tgz/tar.gz archive, it can be omitted though -# Runs both during the build stage and the runtime entrypoint for added flexibility - -set -e - -entrypoint_log() { - if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then - echo "$@" - fi -} - -if [ -z "${ELEMENT_WEB_MODULES}" ]; then - entrypoint_log "ELEMENT_WEB_MODULES is not set, skipping module loading" - exit 0 -fi - -for MODULE in ${ELEMENT_WEB_MODULES//,/ } -do - MODULE_URL=${MODULE%#*} - EXPECTED_HASH=${MODULE#*#} - - entrypoint_log "Fetching module from $MODULE_URL" - wget -O /tmp/element-web-modules/module.tar.gz "$MODULE_URL" - HASH=$(sha256sum /tmp/element-web-modules/module.tar.gz | awk '{ print $1 }') - if [ -n "$EXPECTED_HASH" ] && [ "$HASH" != "$EXPECTED_HASH" ]; then - echo "Hash mismatch for $MODULE_URL: expected $EXPECTED_HASH, got $HASH" - exit 1 - fi - - mkdir -p "/tmp/element-web-modules/$HASH" - tar xvf /tmp/element-web-modules/module.tar.gz -C "/tmp/element-web-modules/$HASH" --strip-components=1 - rm -Rf /tmp/element-web-modules/module.tar.gz -done \ No newline at end of file diff --git a/packages/element-web-module-api/docker/docker-entrypoint.d/18-load-element-modules.sh b/packages/element-web-module-api/docker/docker-entrypoint.d/18-load-element-modules.sh deleted file mode 100755 index fe08194de0..0000000000 --- a/packages/element-web-module-api/docker/docker-entrypoint.d/18-load-element-modules.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/sh - -# Loads modules from `/tmp/element-web-modules` into config.json's `modules` field - -set -e - -entrypoint_log() { - if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then - echo "$@" - fi -} - -# If there are modules to be loaded -if [ -d "/tmp/element-web-modules" ]; then - cd /tmp/element-web-modules - - # Copy these config files as a base - cp /app/config*.json /tmp/element-web-config/ - - for MODULE in * - do - # If the module has a package.json, use its main field as the entrypoint - ENTRYPOINT="index.js" - if [ -f "/tmp/element-web-modules/$MODULE/package.json" ]; then - ENTRYPOINT=$(jq -r '.main' "/tmp/element-web-modules/$MODULE/package.json") - fi - - entrypoint_log "Loading module $MODULE with entrypoint $ENTRYPOINT" - - # Append the module to the config - jq ".modules += [\"/modules/$MODULE/$ENTRYPOINT\"]" /tmp/element-web-config/config.json | sponge /tmp/element-web-config/config.json - done -fi \ No newline at end of file diff --git a/packages/element-web-module-api/docker/nginx-templates/default.conf.template b/packages/element-web-module-api/docker/nginx-templates/default.conf.template deleted file mode 100644 index 83813ddcd2..0000000000 --- a/packages/element-web-module-api/docker/nginx-templates/default.conf.template +++ /dev/null @@ -1,24 +0,0 @@ -server { - listen 8080; - server_name localhost; - - root /app; - index index.html; - - location = /index.html { - add_header Cache-Control "no-cache"; - } - location = /version { - add_header Cache-Control "no-cache"; - } - # covers config.json and config.hostname.json requests as it is prefix. - location /config { - root /tmp/element-web-config; - add_header Cache-Control "no-cache"; - } - location /modules { - root /tmp/element-web-modules; - } - error_page 500 502 503 504 /50x.html; -} -