From 222e9cc8fad11575b27637c6a718bc311214dc43 Mon Sep 17 00:00:00 2001 From: xiaomingwang Date: Thu, 29 Aug 2024 10:24:48 +0800 Subject: [PATCH 1/6] fixbug: new prod site with sqlite will init fail(migrate fail). --- store/migrator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/store/migrator.go b/store/migrator.go index 166261fa47409..a06f5f0be4d35 100644 --- a/store/migrator.go +++ b/store/migrator.go @@ -263,7 +263,7 @@ func (s *Store) normalizedMigrationHistoryList(ctx context.Context) error { } schemaVersionMap := map[string]string{} - filePaths, err := fs.Glob(migrationFS, fmt.Sprintf("%s/*/*.sql", s.getMigrationBasePath())) + filePaths, err := fs.Glob(migrationFS, fmt.Sprintf("%s*/*.sql", s.getMigrationBasePath())) if err != nil { return errors.Wrap(err, "failed to read migration files") } From cfc094c66df4009beed47fd44f87db50abf48ee4 Mon Sep 17 00:00:00 2001 From: xiaomingwang Date: Thu, 29 Aug 2024 10:25:54 +0800 Subject: [PATCH 2/6] feature: supports deploying memos to a subdirectory of the domain(with nginx reverse proxy). --- bin/memos/main.go | 9 +++++ server/profile/profile.go | 2 + server/router/frontend/frontend.go | 55 +++++++++++++++++++++++++-- web/index.html | 10 +++-- web/src/components/MemoActionMenu.tsx | 2 +- web/src/components/UserAvatar.tsx | 2 +- web/src/components/UserBanner.tsx | 2 +- web/src/grpcweb.ts | 2 +- web/src/layouts/RootLayout.tsx | 2 +- web/src/pages/UserProfile.tsx | 2 +- web/src/router/index.tsx | 2 +- web/src/utils/resource.ts | 2 +- 12 files changed, 77 insertions(+), 15 deletions(-) diff --git a/bin/memos/main.go b/bin/memos/main.go index 4e0f7709348e4..2b4387a6c59e4 100644 --- a/bin/memos/main.go +++ b/bin/memos/main.go @@ -44,6 +44,7 @@ var ( DSN: viper.GetString("dsn"), InstanceURL: viper.GetString("instance-url"), Version: version.GetCurrentVersion(viper.GetString("mode")), + BaseURL: viper.GetString("base-url"), } if err := instanceProfile.Validate(); err != nil { panic(err) @@ -110,6 +111,7 @@ func init() { rootCmd.PersistentFlags().String("driver", "sqlite", "database driver") rootCmd.PersistentFlags().String("dsn", "", "database source name(aka. DSN)") rootCmd.PersistentFlags().String("instance-url", "", "the url of your memos instance") + rootCmd.PersistentFlags().String("base-url", "", "the base url of your memos instance") if err := viper.BindPFlag("mode", rootCmd.PersistentFlags().Lookup("mode")); err != nil { panic(err) @@ -132,12 +134,18 @@ func init() { if err := viper.BindPFlag("instance-url", rootCmd.PersistentFlags().Lookup("instance-url")); err != nil { panic(err) } + if err := viper.BindPFlag("base-url", rootCmd.PersistentFlags().Lookup("base-url")); err != nil { + panic(err) + } viper.SetEnvPrefix("memos") viper.AutomaticEnv() if err := viper.BindEnv("instance-url", "MEMOS_INSTANCE_URL"); err != nil { panic(err) } + if err := viper.BindEnv("base-url", "MEMOS_BASE_URL"); err != nil { + panic(err) + } } func printGreetings(profile *profile.Profile) { @@ -150,6 +158,7 @@ addr: %s port: %d mode: %s driver: %s +base_url: %s --- `, profile.Version, profile.Data, profile.DSN, profile.Addr, profile.Port, profile.Mode, profile.Driver) diff --git a/server/profile/profile.go b/server/profile/profile.go index e6bbaf28b7457..5d5050c0317ce 100644 --- a/server/profile/profile.go +++ b/server/profile/profile.go @@ -30,6 +30,8 @@ type Profile struct { Version string // InstanceURL is the url of your memos instance. InstanceURL string + // BaseURL is the base url of your memos instance. + BaseURL string } func (p *Profile) IsDev() bool { diff --git a/server/router/frontend/frontend.go b/server/router/frontend/frontend.go index 81285b3840019..286d78a7dd68d 100644 --- a/server/router/frontend/frontend.go +++ b/server/router/frontend/frontend.go @@ -6,6 +6,9 @@ import ( "io/fs" "net/http" + "io" + "html/template" + "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" @@ -29,18 +32,62 @@ func NewFrontendService(profile *profile.Profile, store *store.Store) *FrontendS } } -func (*FrontendService) Serve(_ context.Context, e *echo.Echo) { +var base_url = "" + +func indexHander(c echo.Context) error { + // open index.html + file, err := embeddedFiles.Open("dist/index.html") + if err != nil { + return c.String(http.StatusInternalServerError, err.Error()) + } + defer file.Close() + // render it. + b, err := io.ReadAll(file) + if err != nil { + return c.String(http.StatusInternalServerError, err.Error()) + } + + c.Response().WriteHeader(http.StatusOK) + template.Must(template.New("index.html").Parse(string(b))).Execute(c.Response().Writer, map[string]any{ + "baseurl": base_url, + }) + + return nil +} + +func (f *FrontendService) Serve(_ context.Context, e *echo.Echo) { skipper := func(c echo.Context) bool { - return util.HasPrefixes(c.Path(), "/api", "/memos.api.v1") + path_ := c.Path() + return path_ == "/" || path_ == "/index.html" || util.HasPrefixes(path_, "/api", "/memos.api.v1") } + e.GET("/", indexHander) + e.GET("/index.html", indexHander) + // save base_url from profile. + base_url = f.Profile.BaseURL + // Use echo static middleware to serve the built dist folder. // Reference: https://github.com/labstack/echo/blob/master/middleware/static.go e.Use(middleware.StaticWithConfig(middleware.StaticConfig{ - HTML5: true, + HTML5: false, Filesystem: getFileSystem("dist"), Skipper: skipper, - })) + }), func (skipper middleware.Skipper) echo.MiddlewareFunc { + return func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) (err error) { + // skip + if skipper(c) { + return next(c) + } + // skip assets + if (util.HasPrefixes(c.Path(), "/assets")){ + return next(c) + } + // otherwise (NotFound), serve index.html + return indexHander(c) + } + } + }(skipper)) // Use echo gzip middleware to compress the response. // Reference: https://echo.labstack.com/docs/middleware/gzip e.Group("assets").Use(middleware.GzipWithConfig(middleware.GzipConfig{ diff --git a/web/index.html b/web/index.html index 2bbab70e75ebd..86ed3cd273cac 100644 --- a/web/index.html +++ b/web/index.html @@ -1,15 +1,19 @@ + - - - + + + Memos +