Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions develop/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,23 @@ endif
HOST_LAN_IP ?=
export HOST_LAN_IP

# --- Front hot-reload (source mode) ---
# All paths below are INSIDE the eo container. The repo root is bind-mounted at /develop
# (docker-compose.yml: `../:/develop`), which is why source paths are /develop/develop/... .
EO_REPO := /develop
LIVERELOAD_DIR := $(EO_REPO)/develop/setup/livereload-tools
LIVERELOAD_SRV := $(LIVERELOAD_DIR)/server.js
LIVERELOAD_PAT := $(LIVERELOAD_DIR)/[s]erver.js
NGINX_CONF := /etc/nginx/includes/ds-docservice.conf
NGINX_CONF_BAK := $(NGINX_CONF).prod.bak
DEV_CONF_SRC := $(EO_REPO)/develop/setup/ds-docservice-dev.conf
SDK_SENTINEL := $(EO_REPO)/sdkjs/common/AllFonts.js
# Canonical published docs (from documentation/brand.yml: brand.docs_url).
DOCS_HOTRELOAD := https://docs.euro-office.com/development/hot-reload/

.PHONY: local mobile next next-mobile pull wipe-nc wipe-next build \
front-dev front-prod front-dev-live sdkjs-dev refresh-urls print-nc-version

local:
@echo ""
@echo " ███████╗ ██████╗"
Expand Down Expand Up @@ -112,6 +129,77 @@ build:
(docker compose up -d) && \
(docker compose exec eo bash || true)

# Front hot-reload: serves /web-apps from the SOURCE tree (/develop) with no cache, so that
# editing + reloading the browser (Ctrl+Shift+R) reflects the change WITHOUT a rebuild.
# The SDK is also served from source via its develop loader (run `make sdkjs-dev` once;
# front-dev aborts if it is missing). Reversible with `make front-prod`.
# Details and limitations: https://docs.euro-office.com/development/hot-reload/
front-dev:
@docker compose exec -u root eo bash -lc '\
if [ ! -f $(SDK_SENTINEL) ] || [ ! -d $(EO_REPO)/sdkjs/develop/sdkjs ]; then \
echo "ERROR: SDK develop loader missing — run: make sdkjs-dev"; \
echo " Docs: $(DOCS_HOTRELOAD)"; \
exit 1; \
fi; \
[ -f $(NGINX_CONF_BAK) ] || cp $(NGINX_CONF) $(NGINX_CONF_BAK); \
cp $(DEV_CONF_SRC) $(NGINX_CONF); \
if nginx_err=$$(nginx -t 2>&1); then \
nginx -s reload && sleep 3; \
else \
echo "ERROR: dev nginx config is invalid — rolling back to production config."; \
echo "$$nginx_err"; \
cp $(NGINX_CONF_BAK) $(NGINX_CONF) && nginx -s reload 2>/dev/null || true; \
exit 1; \
fi'
@echo ""
@echo " SOURCE mode active (front hot-reload)."
@echo " Edit under web-apps/apps/.../ and hard-reload the browser (Ctrl+Shift+R)."
@echo " Back to production: make front-prod"
@echo ""

front-prod:
@docker compose exec -u root eo bash -lc "pkill -f '$(LIVERELOAD_PAT)' 2>/dev/null; true"
@docker compose exec -u root eo bash -lc '\
if [ -f $(NGINX_CONF_BAK) ]; then \
cp $(NGINX_CONF_BAK) $(NGINX_CONF); \
nginx -t && nginx -s reload && sleep 3; \
echo "PRODUCTION mode restored (compiled bundle + versioned cache)."; \
else echo "No backup found; the container is already in production mode."; fi'

# Like front-dev, but also starts the live-reload server: saving a file under web-apps/
# auto-reloads the editor tab (no browser action). The livereload client is injected via
# nginx (sub_filter) and proxied through :8080. Node deps install automatically on first
# run (npm ci, idempotent). Details: https://docs.euro-office.com/development/hot-reload/
front-dev-live: front-dev
@docker compose exec -u root eo bash -lc "pkill -f '$(LIVERELOAD_PAT)' 2>/dev/null; true"
@docker compose exec eo bash -lc '\
if [ ! -d $(LIVERELOAD_DIR)/node_modules ]; then \
echo "Installing live-reload dependencies (one-time)..."; \
cd $(LIVERELOAD_DIR) && npm ci --no-audit --no-fund; \
fi'
@docker compose exec -d eo bash -lc 'node $(LIVERELOAD_SRV) > /tmp/livereload.log 2>&1'
@sleep 2
@docker compose exec eo bash -lc 'curl -sf http://127.0.0.1:35729/livereload.js >/dev/null' \
&& echo "Live-reload server running (:35729, polling)." \
|| { echo "ERROR: live-reload server did not start. Log follows:"; \
docker compose exec eo cat /tmp/livereload.log; \
exit 1; }
@echo ""
@echo " Auto live-reload ACTIVE. Edit under web-apps/ and save:"
@echo " the editor tab reloads on its own (no commands)."
@echo " Stop: make front-prod"
@echo " Note: if you restart the eo container, re-run this command to restore live-reload."
@echo ""

# One-time SDK setup for source mode. Generates the SDK "develop loader"
# (sdkjs/develop/sdkjs/*/scripts.js) in the SOURCE tree and places the generated
# AllFonts.js there, so /develop/sdkjs serves a complete SDK coherent with the front.
# Re-run only when you change the sdkjs submodule. Then use `make front-dev-live`.
sdkjs-dev:
@docker compose exec eo bash -lc 'cd $(EO_REPO)/sdkjs/build && npm install --no-audit --no-fund && grunt develop'
@docker compose exec eo bash -lc 'cp $$EO_ROOT/sdkjs/common/AllFonts.js $(SDK_SENTINEL)'
@echo "SDK develop loader generated under $(EO_REPO)/sdkjs. Next: make front-dev-live"

# Align Euro-Office URLs and trusted_domains with the current mode.
# - If HOST_LAN_IP is set: mobile/LAN mode (DocumentServerUrl = http://<ip>:8080/, trusted_domains[2] = <ip>).
# - If HOST_LAN_IP is empty: localhost mode (DocumentServerUrl = http://localhost:8080/, trusted_domains[2] cleared).
Expand Down
153 changes: 153 additions & 0 deletions develop/setup/ds-docservice-dev.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# ds-docservice-dev.conf — DEVELOPMENT: editor served 100% from SOURCE (/develop)
#
# Replicates ONLYOFFICE's official "developer mode" (build_tools/develop): api.js, web-apps and
# sdkjs are served from the SOURCE tree, mutually coherent, instead of mixing compiled pieces
# (the root cause of the "Asc is not defined" and "R_ null" errors).
#
# Key points:
# - The SOURCE api.js keeps the {{PRODUCT_VERSION}} placeholder -> DocsAPI (extendAppPath,
# api.js:1327) does NOT add the /X.Y.Z-<hash>/ version prefix -> the editor loads from
# /web-apps/... unversioned and the SDK load order (synchronous document.write -> RequireJS)
# works as ONLYOFFICE designed it.
# - SDK served from /develop/sdkjs with the real develop loader (grunt develop) + AllFonts.js ->
# coherent with the front. Falls back to $EO_ROOT for generated binaries (.wasm, theme.bin)
# that are not present in the source tree.
# - Service worker neutralised + auto live-reload (livereload proxied through :8080).
#
# One-time requirement: the SDK develop loader in the source tree (make sdkjs-dev) and AllFonts.js
# under /develop/sdkjs/common. Toggle with: make front-dev / front-dev-live / front-prod.
# Docs: https://docs.euro-office.com/development/hot-reload/
#
# MAINTENANCE: the access-controlled tail of this file (cache/files secure_link, internal,
# info, versioned passthrough) mirrors the production ds-docservice.conf shipped in the image.
# If that production config changes (e.g. an access-control fix), mirror it in the blocks below.

#welcome page
location = / { return 302 $the_scheme://$the_host$the_prefix/welcome/; }

# --- DEV: front (web-apps) + api.js from SOURCE, no cache ---
location ^~ /web-apps/ {
alias /develop/web-apps/;
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
expires off;
error_log /dev/null crit; # silence unsupported-locale noise
gzip off;
sub_filter_once off;
# auto live-reload: inject the client (proxied through :8080, see /livereload* locations)
sub_filter '</body>' '<script src="/livereload.js?snipver=1"></script></body>';
try_files $uri =404;
}

# --- DEV: SDK from SOURCE (develop loader + individual sources coherent with the front) ---
# Falls back to $EO_ROOT (@sdkjs_compiled) for generated binaries (.wasm, etc.) absent in source.
location ^~ /sdkjs/ {
alias /develop/sdkjs/;
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
expires off;
error_log /dev/null crit;
try_files $uri @sdkjs_compiled;
}
location @sdkjs_compiled {
root /var/www/euro-office/documentserver;
add_header Cache-Control "no-store" always;
}

# --- Auto live-reload: proxy the client and the websocket to the internal :35729 server ---
# The client script is injected into every page (sub_filter above). In plain `front-dev`
# mode (no live server running) the upstream is down; we intercept the error and serve a
# harmless no-op so the browser console stays clean instead of logging a failed script load.
location = /livereload.js {
proxy_pass http://127.0.0.1:35729;
proxy_intercept_errors on;
error_page 502 504 = @livereload_off;
}
location @livereload_off {
default_type application/javascript;
add_header Cache-Control "no-store" always;
return 200 "/* live-reload server not running - start it with: make front-dev-live */";
}
location /livereload {
proxy_pass http://127.0.0.1:35729;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}

# --- DEV: service worker NEUTRALISED. The production SW caches the editor and breaks
# hot-reload (responses come back "from service worker"); we serve a SW that, on activation,
# DELETES all caches and does not intercept fetch.
location ~ /document_editor_service_worker\.js$ {
default_type application/javascript;
add_header Cache-Control "no-store, no-cache, must-revalidate" always;
return 200 "self.addEventListener('install',function(){self.skipWaiting()});self.addEventListener('activate',function(e){e.waitUntil(caches.keys().then(function(k){return Promise.all(k.map(function(c){return caches.delete(c);}));}).then(function(){return self.clients.claim();}));});";
}

# fonts / dictionaries / sdkjs-plugins → compiled ($EO_ROOT); unchanged while editing UI
location ~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\w]+)?\/(sdkjs-plugins|fonts|dictionaries)(\/.*)$ {
add_header Cache-Control "no-store" always;
error_log /dev/null crit;
alias /var/www/euro-office/documentserver/$2$3;
}

location ~* ^(\/cache\/files.*)(\/.*) {
alias /var/lib/euro-office/documentserver/App_Data$1;
add_header Content-Disposition "attachment; filename*=UTF-8''$arg_filename";

secure_link $arg_md5,$arg_expires;
secure_link_md5 "$secure_link_expires$uri$secure_link_secret";

if ($secure_link = "") {
return 403;
}

if ($secure_link = "0") {
return 410;
}
}

# Allow "/internal" interface only from 127.0.0.1
location ~* ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\w]+)?\/(internal)(\/.*)$ {
allow 127.0.0.1;
deny all;
proxy_pass http://docservice/$2$3;
}

# Allow "/info" interface only from 127.0.0.1 by default
location ~* ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\w]+)?\/(info)(\/.*)$ {
allow 127.0.0.1;
deny all;
proxy_pass http://docservice/$2$3;
}

#document formats discovery
location ~ ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\w]+)?\/(meta\/formats)$ {
add_header Cache-Control "no-store" always;
alias /var/www/euro-office/documentserver/document-formats/onlyoffice-docs-formats.json;
}

location / {
proxy_pass http://docservice;
proxy_http_version 1.1;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_connect_timeout 300s;
proxy_buffering on;
proxy_buffers 64 32k;
proxy_busy_buffers_size 64k;
proxy_max_temp_file_size 0;
proxy_redirect off;
}

location ~* ^(\/[\d]+\.[\d]+\.[\d]+[\.|-][\w]+)?\/(ai-proxy)(\/.*)?$ {
proxy_pass http://docservice/$2$3;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
send_timeout 300s;
}

location ~ ^/([\d]+\.[\d]+\.[\d]+[\.|-][\w]+)/(?<path>.*)$ {
proxy_pass http://docservice/$path$is_args$args;
proxy_http_version 1.1;
}
1 change: 1 addition & 0 deletions develop/setup/livereload-tools/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
Loading
Loading