diff --git a/.gitignore b/.gitignore
index 4161f3a76..a63131ca9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,11 @@ flask_session/
.DS_Store
.venv
*.pyc
+.webassets-cache
+files/static/gen/
+
+# nodejs
+node_modules
# rdrama Media Runtime Artifacts
image.*
diff --git a/Dockerfile b/Dockerfile
index 2a3ac6a33..5a96442a7 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,6 +1,6 @@
###################################################################
# Base container
-FROM python:3.10 AS base
+FROM nikolaik/python-nodejs:python3.10-nodejs20 AS base
ARG DEBIAN_FRONTEND=noninteractive
@@ -10,6 +10,7 @@ RUN apt update && apt -y upgrade
WORKDIR /service
COPY pyproject.toml .
COPY poetry.lock .
+COPY package.json .
RUN pip install 'poetry==1.2.2'
RUN poetry config virtualenvs.create false
@@ -27,14 +28,11 @@ CMD [ "bootstrap/init.sh" ]
FROM base AS build
# Chat compilation framework
-ENV NODE_VERSION=16.13.0
-RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
-ENV NVM_DIRECTORY=/root/.nvm
-RUN . "$NVM_DIRECTORY/nvm.sh" && nvm install ${NODE_VERSION}
-RUN . "$NVM_DIRECTORY/nvm.sh" && nvm use v${NODE_VERSION}
-RUN . "$NVM_DIRECTORY/nvm.sh" && nvm alias default v${NODE_VERSION}
-ENV PATH="/root/.nvm/versions/node/v${NODE_VERSION}/bin/:${PATH}"
-RUN npm i -g yarn
+# We're using an image that comes with node and yarn installed
+
+# needed for ES2015 transpilation
+RUN npm install --global @babel/cli
+RUN yarn install
###################################################################
diff --git a/files/__main__.py b/files/__main__.py
index 475551700..5c9f04323 100644
--- a/files/__main__.py
+++ b/files/__main__.py
@@ -25,6 +25,7 @@ import gevent
import redis
from sqlalchemy.engine import Engine, create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
+from flask_assets import Environment, Bundle
from files.helpers.config.const import Service
from files.helpers.strings import bool_from_string
@@ -39,6 +40,11 @@ app = flask.app.Flask(__name__, template_folder='templates')
app.url_map.strict_slashes = False
app.jinja_env.cache = {}
app.jinja_env.auto_reload = True
+
+# set up assets
+assets = Environment(app)
+assets.from_yaml('files/bundles.yaml')
+
faulthandler.enable()
# ...then check that debug mode was not accidentally enabled...
diff --git a/files/assets/js/es/test.js b/files/assets/js/es/test.js
new file mode 100644
index 000000000..d7fd3bbb7
--- /dev/null
+++ b/files/assets/js/es/test.js
@@ -0,0 +1 @@
+globalThis.TRANSPILED_PACKAGES_WORK = true;
\ No newline at end of file
diff --git a/files/assets/js/es/test2.js b/files/assets/js/es/test2.js
new file mode 100644
index 000000000..329f6c19f
--- /dev/null
+++ b/files/assets/js/es/test2.js
@@ -0,0 +1 @@
+globalThis.MULTIPLE_FILES_WORK = true;
\ No newline at end of file
diff --git a/files/bundles.yaml b/files/bundles.yaml
new file mode 100644
index 000000000..c9371453e
--- /dev/null
+++ b/files/bundles.yaml
@@ -0,0 +1,7 @@
+es5-bundle:
+ # paths are relative to "files/static"
+ output: gen/es5.js
+ config:
+ BABEL_PRESETS: "@babel/preset-env"
+ filters: babel
+ contents: "../assets/js/es/*.js"
\ No newline at end of file
diff --git a/files/templates/default.html b/files/templates/default.html
index f2797dd34..dea457e36 100644
--- a/files/templates/default.html
+++ b/files/templates/default.html
@@ -303,5 +303,9 @@
+
+{% assets "es5-bundle" %}
+
+{% endassets %}