diff --git a/.gitignore b/.gitignore
index de6e4247d157351adae89b52149a8a59fbf3c682..9d5ca6163e101dc8bb59f7b6b2f93790899fb2a8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,10 @@
 # C extensions
 *.so
 
+# Flask-Assets files
+.webassets-cache
+*.compiled.js
+
 # Docker related files
 docker-compose.override.yml
 db
diff --git a/web/app/__init__.py b/web/app/__init__.py
index 9a399ddc8384f92a3bfcead220701b049d803c9d..75be421365c7219c3d4e9be150ad6436f24df36e 100644
--- a/web/app/__init__.py
+++ b/web/app/__init__.py
@@ -5,8 +5,10 @@ from flask_mail import Mail
 from flask_paranoid import Paranoid
 from flask_socketio import SocketIO
 from flask_sqlalchemy import SQLAlchemy
+import flask_assets
 
 
+assets = flask_assets.Environment()
 db = SQLAlchemy()
 login_manager = LoginManager()
 login_manager.login_view = 'auth.login'
@@ -20,6 +22,7 @@ def create_app(config_name):
     app = Flask(__name__)
     app.config.from_object(config[config_name])
 
+    assets.init_app(app)
     config[config_name].init_app(app)
     db.init_app(app)
     login_manager.init_app(app)
diff --git a/web/app/templates/nopaque.html.j2 b/web/app/templates/nopaque.html.j2
index 3e7978bc9d1fb53b3cd7ff1623096524c886018b..f53ad1898752bd9b02cc043a6b6aab97e6269afb 100644
--- a/web/app/templates/nopaque.html.j2
+++ b/web/app/templates/nopaque.html.j2
@@ -254,17 +254,23 @@
 <script src="{{ url_for('static', filename='js/list.min.js') }}"></script>
 <script src="{{ url_for('static', filename='js/socket.io.min.js') }}"></script>
 <script src="{{ url_for('static', filename='js/nopaque/main.js') }}"></script>
-<script src="{{ url_for('static', filename='js/nopaque/RessourceDisplays/RessourceDisplay.js') }}"></script>
-<script src="{{ url_for('static', filename='js/nopaque/RessourceDisplays/CorpusDisplay.js') }}"></script>
-<script src="{{ url_for('static', filename='js/nopaque/RessourceDisplays/JobDisplay.js') }}"></script>
-<script src="{{ url_for('static', filename='js/nopaque/RessourceLists/RessourceList.js') }}"></script>
-<script src="{{ url_for('static', filename='js/nopaque/RessourceLists/CorpusList.js') }}"></script>
-<script src="{{ url_for('static', filename='js/nopaque/RessourceLists/CorpusFileList.js') }}"></script>
-<script src="{{ url_for('static', filename='js/nopaque/RessourceLists/JobList.js') }}"></script>
-<script src="{{ url_for('static', filename='js/nopaque/RessourceLists/JobInputList.js') }}"></script>
-<script src="{{ url_for('static', filename='js/nopaque/RessourceLists/JobResultList.js') }}"></script>
-<script src="{{ url_for('static', filename='js/nopaque/RessourceLists/QueryResultList.js') }}"></script>
-<script src="{{ url_for('static', filename='js/nopaque/RessourceLists/UserList.js') }}"></script>
+{% assets output="js/nopaque/RessourceDisplays.compiled.js",
+          "js/nopaque/RessourceDisplays/RessourceDisplay.js",
+          "js/nopaque/RessourceDisplays/CorpusDisplay.js",
+          "js/nopaque/RessourceDisplays/JobDisplay.js" %}
+<script src="{{ ASSET_URL }}"></script>
+{% endassets %}
+{% assets output="js/nopaque/RessourceLists.compiled.js",
+          "js/nopaque/RessourceLists/RessourceList.js",
+          "js/nopaque/RessourceLists/CorpusList.js",
+          "js/nopaque/RessourceLists/CorpusFileList.js",
+          "js/nopaque/RessourceLists/JobList.js",
+          "js/nopaque/RessourceLists/JobInputList.js",
+          "js/nopaque/RessourceLists/JobResultList.js",
+          "js/nopaque/RessourceLists/QueryResultList.js",
+          "js/nopaque/RessourceLists/UserList.js" %}
+<script src="{{ ASSET_URL }}"></script>
+{% endassets %}
 <script>
   // Disable all option elements with no value
   for (let optionElement of document.querySelectorAll('option[value=""]')) {optionElement.disabled = true;}
diff --git a/web/requirements.txt b/web/requirements.txt
index e1faf1c51b7afcd2c76e1ff88d730ff32eb73663..97c941901c3bd683766c0ae86421cc59543798e9 100644
--- a/web/requirements.txt
+++ b/web/requirements.txt
@@ -2,6 +2,7 @@ cqi
 docker
 eventlet
 Flask
+Flask-Assets
 Flask-Login
 Flask-Mail
 Flask-Migrate