How to develop front-end locally?

Viewed 468

I pulled the open source code and wanted to make some layout adjustments to the front-end page. I started Answer using SQLite as binary as in the documentation.

Then enter the ui directory of the project and start the front-end project locally, but the interface cannot be pulled. I want to know how to get the interface?

3 Answers

Apache Answer UI requries backend to run. Before starting UI, you need to start your backend.

Follow this to start backend https://answer.apache.org/community/development#backend

In UI repo Make sure you have updated your .env.development.local file so that your UI points to correct backend

The frontend documentation is a bit spare, along with the the accepted answer. Are you guys sure the env files are working in the steps described? Regardless of the values used in either of these files:

ui/.env.development
ui/.env.development.local

The frontend is always trying to send the API requests to localhost:3000 which doesn't seem right, unless we're missing a step and there's more to it? Seeing the same exact thing that's mentioned in the original post after setting the values in any of those env files and using:

pnpm run start

My environment:

go version go1.22.0 linux/amd64
node: v21.6.2
pnpm: 8.15.4

When I copy the failed requests from the network console as cURL:

curl 'http://localhost:3000/answer/api/v1/question/page?page=1&page_size=6&order=frequent&in_days=7' \
  -H 'Accept: */*' \
  -H 'Accept-Language: en_US' \
  -H 'Authorization;' \
  -H 'Connection: keep-alive' \
  -H 'Referer: http://localhost:3000/' \
  -H 'Sec-Fetch-Dest: empty' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'Sec-Fetch-Site: same-origin' \
  -H 'Sec-GPC: 1' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36' \
  -H 'sec-ch-ua: "Not A(Brand";v="99", "Brave";v="121", "Chromium";v="121"' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-platform: "macOS"' \
  --compressed

Then run in the terminal I see a proxy error:

Error occurred while trying to proxy: localhost:3000/answer/api/v1/question/page?page=1&page_size=6&order=frequent&in_days=7

The same proxy error occurs when trying to load the custom.css which isn't shown in the original screenshots in this post. Can also reproduce by visiting these urls in the browser instead of using cURL.


I was able to resolve it, but not exactly sure how it has been working as described in the documentation and in this thread.

Originally the axios base url was configurable in commit 30921fd. Then it was later removed for some reason in commit 1f26219, but no reason was given for why it was not needed. Adding that line back to axios base config allows the base URL to work properly with the env file url.

The next issue is once that is working, there are CORS issues. The local running API backend rejects requests that originate from localhost:3000. It doesn't look like the backend uses any cors middleware. After adding CORS to the backend router it will work.

That can be confirmed with an options request:

curl 'http://localhost/answer/api/v1/siteinfo' \
  -I \
  -X 'OPTIONS' \
  -H 'Accept: */*' \
  -H 'Access-Control-Request-Headers: accept-language,authorization' \
  -H 'Access-Control-Request-Method: GET' \
  -H 'Origin: http://localhost:3000' \
  -H 'Sec-Fetch-Mode: cors' \
  -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36' \
  --compressed

The response headers:

HTTP/1.1 204 No Content
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Origin,Content-Length,Content-Type,Authorization,Accept,Accept-Language
Access-Control-Allow-Methods: GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Max-Age: 43200
Content-Encoding: br
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Date: Sun, 03 Mar 2024 17:49:17 GMT

Now the react app on localhost:3000 can connect with the backend API running on an alternate port. So for example my .env.development.local file:

PUBLIC_URL
REACT_APP_API_URL = http://localhost:61697/

Here's a patch that got it working for me with the steps I've described:

diff --git a/internal/base/server/http.go b/internal/base/server/http.go
index daaf90fb..c990881b 100644
--- a/internal/base/server/http.go
+++ b/internal/base/server/http.go
@@ -28,6 +28,7 @@ import (
 	"github.com/apache/incubator-answer/internal/router"
 	"github.com/apache/incubator-answer/plugin"
 	"github.com/apache/incubator-answer/ui"
+	"github.com/gin-contrib/cors"
 	"github.com/gin-gonic/gin"
 )
 
@@ -50,7 +51,11 @@ func NewHTTPServer(debug bool,
 		gin.SetMode(gin.ReleaseMode)
 	}
 	r := gin.New()
-	r.Use(brotli.Brotli(brotli.DefaultCompression), middleware.ExtractAndSetAcceptLanguage, shortIDMiddleware.SetShortIDFlag())
+	config := cors.DefaultConfig()
+	config.AllowOrigins = []string{"http://localhost:3000"}
+	config.AllowCredentials = true
+	config.AllowHeaders = []string{"Origin", "Content-Length", "Content-Type", "Authorization", "Accept", "Accept-Language"}
+	r.Use(brotli.Brotli(brotli.DefaultCompression), middleware.ExtractAndSetAcceptLanguage, shortIDMiddleware.SetShortIDFlag(), cors.New(config))
 	r.GET("/healthz", func(ctx *gin.Context) { ctx.String(200, "OK") })
 
 	html, _ := fs.Sub(ui.Template, "template")
diff --git a/ui/config-overrides.js b/ui/config-overrides.js
index 293d6bc1..00b8a71a 100644
--- a/ui/config-overrides.js
+++ b/ui/config-overrides.js
@@ -48,6 +48,7 @@ module.exports = {
   devServer: function(configFunction) {
     return function(proxy, allowedHost) {
       const config = configFunction(proxy, allowedHost);
+      config.allowedHosts = ["http://localhost:3000"];
       config.proxy = [
         {
           context: ['/answer', '/installation'],
diff --git a/ui/src/utils/request.ts b/ui/src/utils/request.ts
index 48f50e6e..6c4050ff 100644
--- a/ui/src/utils/request.ts
+++ b/ui/src/utils/request.ts
@@ -31,6 +31,7 @@ import { floppyNavigation } from './floppyNavigation';
 import { isIgnoredPath, IGNORE_PATH_LIST } from './guard';
 
 const baseConfig = {
+  baseURL: process.env.REACT_APP_API_URL || '',
   timeout: 10000,
   withCredentials: true,
 };

Place that patch into a file frontend-local-dev.patch and apply it:

git apply frontend-local-dev.patch

Then install the gin cors package, rebuild the go backend and start it:

go get github.com/gin-contrib/cors
make build
./answer run -C ./answer-data/

Then start the frontend:

pnpm start

It doesn't resolve the issue with the custom.css file that I mentioned earlier, but it does allow the API requests to start working.