diff --git a/Makefile b/Makefile
index bb328b4f1..f6d24be08 100644
--- a/Makefile
+++ b/Makefile
@@ -136,6 +136,7 @@ help:
 	@echo " - lint              lint everything"
 	@echo " - lint-frontend     lint frontend files"
 	@echo " - lint-backend      lint backend files"
+	@echo " - watch-frontend    watch frontend files and continuously rebuild"
 	@echo " - webpack           build webpack files"
 	@echo " - fomantic          build fomantic files"
 	@echo " - generate          run \"go generate\""
@@ -275,6 +276,10 @@ lint-frontend: node_modules
 	npx eslint web_src/js webpack.config.js
 	npx stylelint web_src/less
 
+.PHONY: watch-frontend
+watch-frontend: node_modules
+	NODE_ENV=development npx webpack --hide-modules --display-entrypoints=false --watch
+
 .PHONY: test
 test:
 	$(GO) test $(GOTESTFLAGS) -mod=vendor -tags='sqlite sqlite_unlock_notify' $(GO_PACKAGES)
diff --git a/docs/content/doc/advanced/hacking-on-gitea.en-us.md b/docs/content/doc/advanced/hacking-on-gitea.en-us.md
index 902bf8473..31574d0a1 100644
--- a/docs/content/doc/advanced/hacking-on-gitea.en-us.md
+++ b/docs/content/doc/advanced/hacking-on-gitea.en-us.md
@@ -128,10 +128,28 @@ make revive vet misspell-check
 
 ### Working on JS and CSS
 
-Edit files in `web_src` and run the linter and build the files in `public`:
+For simple changes, edit files in `web_src`, run the build and start the server to test:
 
 ```bash
-make webpack
+make build && ./gitea
+```
+
+For more involved changes use the `watch-frontend` task to continuously rebuild files when their sources change. The `bindata` tag must be absent to ensure the file system will be used for files in `public`. First, build and run the backend:
+
+```bash
+make backend && ./gitea
+```
+
+With the backend running, open another terminal and run:
+
+```bash
+make watch-frontend
+```
+
+Before committing, make sure the linters pass:
+
+```bash
+make lint-frontend
 ```
 
 Note: When working on frontend code, it is advisable to set `USE_SERVICE_WORKER` to `false` in `app.ini` which will prevent undesirable caching of frontend assets.