diff --git a/.dockerignore b/.dockerignore
index ef69cb32eba7e5d8919950644a52eed8be00ee9d..36b421b8f6f98115216c0ee5274a2fe0e0530739 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,3 +1,4 @@
 node_modules/
 ./*/node_modules/
 annotot-db/
+.cache
diff --git a/Dockerfile b/Dockerfile
index ba72fd78e724ed27ea8bf4a58160659e30760b66..1e184c1ea866c24e3465372f7dc49e70d35618b4 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
 FROM debian:stable as builder
-RUN apt-get update && apt-get install -y npm git
+RUN apt-get update && apt-get install -y npm git jq
 
 COPY . /opt
 WORKDIR /opt
diff --git a/Dockerfile.devserver b/Dockerfile.devserver
index a17d73811f111d1c2bb60e0c69eae5ce9df8fe09..7d88b4b386ecf1080385582d6cba15246d94a448 100644
--- a/Dockerfile.devserver
+++ b/Dockerfile.devserver
@@ -1,5 +1,5 @@
 FROM debian:stable-slim
-RUN apt-get update && apt-get install -y git npm
+RUN apt-get update && apt-get install -y git npm jq inotify-tools
 RUN useradd --home-dir /opt node
 RUN chown node:node /opt
 EXPOSE 9000
diff --git a/build_deps.sh b/build_deps.sh
index 85429dc93f132c7629dbe9402be9e605aa6ec8ae..de4f6ada633927f76ddea32e0ef4fcebc533b7b4 100755
--- a/build_deps.sh
+++ b/build_deps.sh
@@ -1,25 +1,43 @@
 #!/bin/bash
-declare -A SUBMODULES=(
-    ['mirador-video-annotation']="build:es"
-    ['annotations-plugin']="build"
-)
-
-run_on_modules(){
-    for mod in "${!SUBMODULES[@]}"; do
-        echo -e "\t$mod"
-        cd $mod
-        if [ "$1" == "install" ]; then
-            npm install
-        else
-            npm run ${SUBMODULES[${mod}]}
-        fi
-        cd ..
-    done
+## Runs action $2 for submodule $1
+watch() {
+inotifywait \
+    --event modify \
+    --event create \
+    --event delete \
+    --event move \
+    --monitor \
+    --quiet \
+    --recursive \
+    --format '%e %w%f' \
+    ./src | while read line; do
+                echo "$line"
+                $@
+            done
+}
+run() {
+    mod=$1
+    shift
+    echo "Running '$@' on '$mod'"
+    cd $mod
+    $@
+    if $watch; then
+        watch $@ &
+    fi
+    cd ..
 }
 
-if [ "$1" == "install" ]; then
-    echo "Installing submodules"
-    run_on_modules install
+action=$1
+watch=false
+if [ "$action" == "watch" ]; then
+    action=build
+    watch=true
 fi
-echo "Compiling submodules"
-run_on_modules build
+
+echo "Submodule action '$action' triggered"
+jq -r --arg action "$action" \
+    '.subscripts | to_entries[] | "\(.key) \(.value | .[$action])"' \
+    package.json | \
+    while read line; do
+        run $line
+done
diff --git a/package.json b/package.json
index b8288f7cb8f2d452aa9593807cd5175c65154099..ceef3ebd7fcea49c8e8e53643efc7a05af49ca58 100644
--- a/package.json
+++ b/package.json
@@ -4,10 +4,20 @@
   "description": "",
   "private": true,
   "scripts": {
-    "preinstall": "./build_deps.sh install",
     "prebuild": "./build_deps.sh build",
     "build": "webpack --config webpack.config.js",
-    "serve": "npm install && webpack serve --config webpack.config.js"
+    "preserve": "./build_deps.sh watch",
+    "serve": "webpack serve --config webpack.config.js"
+  },
+  "subscripts": {
+      "annotations-plugin": {
+          "install": "npm install",
+          "build": "npm run build"
+      },
+      "mirador-video-annotation": {
+          "install": "npm install",
+          "build": "npm run build:es"
+      }
   },
   "author": "",
   "license": "ISC",