Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate react-scripts to vite #696

Open
wants to merge 46 commits into
base: master
Choose a base branch
from

Conversation

mfechner
Copy link

Fixes #695

To test this modification:

(cd ui && yarn)
(cd ui && yarn build)
go run .
(cd ui && yarn start)

Now access the address yarn start shows you.

@mfechner mfechner mentioned this pull request Oct 15, 2024
@mfechner
Copy link
Author

Ok, to sum it up.
The migration to vite is more or less done.
But it seems that state management is broken, after a login the message component is not loaded.

I tried to update the router, but that is even worse. They broke the complete API and do not even provide a migration script for it.

As I mainly develop in Angular I need to read about react before I continue, but it seems that this upgrade to vite is depending on updating all libs to a more current version.

If someone else here have a strategy how to update the ui, any feedback is welcome.
I understand now the comment from @jmattheis that this will not be an easy task ;)

@jmattheis
Copy link
Member

@mfechner I feel you (:, I think the only good way it to start from scratch and copy component by component into a new project, so that you don't have to fix 100 errors to get something working. It's on my todo list, sadly it's multi hour effort.

@mfechner
Copy link
Author

@jmattheis thanks a lot for your feedback. I currently study react to better understand react itself.
It's to early to really make a statement here, but why you do not use the standard state management of react. That would help to get rid of a third party lib and would also simplify upgrade in the future.

I'm on this task but it will take some time ;)

@jmattheis
Copy link
Member

The codebase is quite old, pre react hooks. In my experience it wasn't that ergonomic to use contexts for global state, so I've used a lib. Currently I like https://github.com/pmndrs/zustand for it's simplicity and small footprint.

@mfechner
Copy link
Author

I started now with a rewrite, but this will be a massiv change.
Steps I plan to do:

  • rewrite all class based components as functional components to be able to use all hook
  • upgrade react in first step to 18.3.1 and later to 19
  • upgrade material to v6
  • replace state management with @reduxjs/toolkit and react-redux
  • upgrade react-router to 7
  • use vite 6

I think it will be nearly impossible to get this changes sliced into small commit, as all steps link somehow together.
Maybe later try to get also rid of not needed third party libs like axios. The fetch API is normally more than enough nowadays.

I update you, if I have something to show, but it will for sure take some days maybe some weeks.

@mfechner mfechner force-pushed the react_scripts_to_vite branch from f296d85 to 1bf4902 Compare January 1, 2025 12:44
In DEV mode, you just do:
go run .
(cd ui && yarn start)
In dev mode there is a proxy in vite used to not have CORS problem.
You can access the UI on:
http://localhost:5173
The UI prefix every request to the backup with `/api` so the proxy can correctly handle it, the proxy strips the `/api` so the backend is equal to production mode.
changing (observed) observable values without using an action
@mfechner mfechner force-pushed the react_scripts_to_vite branch from 1bf4902 to 3d6fca9 Compare January 1, 2025 12:50
@mfechner
Copy link
Author

mfechner commented Jan 1, 2025

This is now a first version we can start.
The newly rewritten react app looks ok and tests I did are working fine.
There can be some finetuning, like loading indicator or use redux RTK query.

There are some todos left (infinite loading component for messages), but it is now a good starting point.

The only problem I have is that puppeteer sometimes is just not loading the page and therefore tests are not running.
Maybe someone has an idea why?

@jmattheis would be nice if you can have a look, it was really a lot of work

@mfechner
Copy link
Author

mfechner commented Jan 2, 2025

All tests are now working fine for me.

@mfechner mfechner marked this pull request as ready for review January 2, 2025 08:25
@mfechner mfechner requested a review from a team as a code owner January 2, 2025 08:25
@jmattheis
Copy link
Member

I'll have a look at this in the coming days, but I'll take some time.

@jmattheis jmattheis self-requested a review January 2, 2025 17:11
@mfechner
Copy link
Author

mfechner commented Jan 2, 2025

I'll have a look at this in the coming days, but I'll take some time.

thank you very much. I found other small issues I corrected in the meantime.
The webinterface itself seems to work, but I have problem with the tests.
Sometimes they are failing (about 2 failures if doing 10 test runs).

The problems I found is that for most actions a submit or a click on a button was not blocking (running in background), which I reverted to the behaviour the released gotify version has.
But something with the test is maybe broken and as I never used pupeteer before, that is hard for me to analyse, so I need some help with the tests.

Later we can addnice indicators, if you e.g. click on Submit the button is replaced by an loading indicator.

I have here some very nice ideas, but I will provide this later in another PR, as that is not related to this topic.

Let us first get the update to react 19 merged, then we can continue further in smaller steps.

Maybe we can release these changes as a beta version to enable users testing it.

Copy link
Member

@jmattheis jmattheis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not finished with reviewing, this was only glancing through some files.

ui/src/App.tsx Outdated Show resolved Hide resolved
ui/src/App.tsx Show resolved Hide resolved
ui/src/App.tsx Show resolved Hide resolved
ui/src/App.tsx Outdated Show resolved Hide resolved
ui/serve.go Outdated
@@ -32,7 +31,7 @@ func Register(r *gin.Engine, version model.VersionInfo, register bool) {
return strings.Replace(content, "%CONFIG%", string(uiConfigBytes), 1)
}

ui := r.Group("/", gzip.Gzip(gzip.DefaultCompression))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot reproduce the net:ERR_INCOMPLETE_CHUNKED_ENCODING error with your listed steps:

cd ui
yarn build
yarn run test user

with having the compression enabled here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a test is failing, I always see the following error message in the javascript of the puppeteer browser:

grafik

or

grafik

Not sure if that is a problem related to my machine, some virus scanner or anything else.

But if I remove this commit again, all tests are failing 100% with the error message:
grafik

ui/vite.config.ts Show resolved Hide resolved
ui/src/message/Messages.tsx Outdated Show resolved Hide resolved
<LoadingSpinner />
) : hasMessages ? (
<div style={{width: '100%'}} id="messages">
{/* TODO: maybe replace ReactInfitite with react-window, which is also documented here: https://mui.com/material-ui/react-list/#virtualized-list */}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've recently tried a lot of window libraries for another project and landed on https://tanstack.com/virtual/latest/docs/introduction react-window doesn't play to well with having a window over the whole screen.

ui/src/common/SettingsDialog.tsx Outdated Show resolved Hide resolved
}

const initialUiState: UiState = {
themeKey: 'dark',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I like this too, previously this was local component state, because it was only used in two places, and passed downwards to one component. Sure adding this to the global state can be done, but local component state is better as it's simpler and easier to navigate.

These refactorings making this review much more effort as it's not just library change / upgrades, but also logic changes which aren't 100% necessary.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a lot of problems in the beginning to understand which prop is passed to which component and why
Using a global state reduces the need of props drilling which is making the componets match leaner and easier to read.

But if you prefer a global state in e.g. app.tsx, I can remove these UI related states from the global state and move it to app.tsx and pass them via props drilling to the components.
But to be honest it will be technically equal and will just make the components harder to read.

But as you prefer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer it to be as close as possible to the original implementation for now, as it makes less changes to review and less possibility of bugs, because the code already runs for some time. This includes the moving of the selected plugin state into redux.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, I will move the state/slice/action definition to the component.
But I will not remove the ui state management and will change everything back to prop drilling.
This is error prone and we will for sure just add new bugs by this. The UI state is working perfectly fine.

Copy link
Member

@jmattheis jmattheis Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is error prone and we will for sure just add new bugs by this.

How is it error prone to pass properties to sub components? TypeScript is used, so it's not like you can miss passing the props?

Rewrite all components to functional component using hooks
Upgrade react-router to 7.1.0
Use reduxjs/toolkit and react-redux for state management
Upgrade material to 6.3.0
Updated most dependencies to current versions
This caused a failure correctly forwarding the user to the login page
@mfechner mfechner force-pushed the react_scripts_to_vite branch from 6cd4b90 to cf08815 Compare January 8, 2025 12:18
Replace react-codemirror2 which is unmaintained by @uiw/react-codemirror and applied required API changes to ReactMarkdown
…container and can be accessed for the windows host.

This is required to use/test plugins with gotify
while working with the production bundled application.
…ld not happen, as the key on already rendered table does not change)
We hold now all messages in the state.
If message of one app are refresh, make sure to sort them by date into the existing messages
Axios does not need this for error handling
Except for the delete actions, as the test does not expect it there
@mfechner mfechner force-pushed the react_scripts_to_vite branch from cf08815 to 92a9608 Compare January 8, 2025 12:20
@mfechner
Copy link
Author

mfechner commented Jan 8, 2025

Failing tests seem to be related to puppeteer upgrade.
I downgraded it and I see the tests are working better.

I will work through the commits again and will maybe rebase some of them, so they match better.

@jmattheis the current implementation does not have the virtual scrolling for messages, should I include it here, ot as another PR?
Also paging is currently not implemented (which I can currently not test, so I have to create a datasource to work with paging).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

Migrate react-scripts to vite
2 participants