-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Replace inline script for critical JS with standalone script #21429
Conversation
The new script utilizes requestAnimationFrame to run DOM transformations as soon as possible. In my testing, this method is equivalent of a synchronous inline script. On Firefox, the callback sometimes fires too early and if that happens we register for another frame. I had 100% sucess within 2 frames in Firefox.
Although I approved the previous PRs, that's because of I think there are other valuable changes, but not because I consider using hacky methods and inline scripts to avoid flicker is the proper way. Using hacky methods and inline scripts to avoid every flicker is the wrong way IMO. In the end, not every flicker can be avoided, because there could always be something rendered again after the page gets loaded. The hacky methods only make code harder to understand. Take GitHub as an example, it also flicks on many pages. I can not see the value of using hacky methods to avoid every flicker. See GitHub pages: And one more thing, instead of using these inline scripts, I recalled that we have discussed about that moving the Clone URLs into a dropdown menu, then there will be no flicker problem anymore. |
I will also move all stuff in formatting.js into this script as well. These are all critical replacements. |
Hmm, I am still not convinced that it's the proper way. Why
I wouldn't consider as they are sloppiness. Sometimes when the backend (tmpl) and frontend (like vue) rendered HTML are mixed together, it's very difficult (nearly impossible) to have a clear way to avoid all flickers. |
After reading the code of Even if you move the <script init.js>
<time id=time1>
<!--
very long content, which need a few seconds to transfer,
then browser will partially render the content above,
while the remaining content will be rendered a few seconds later.
-->
<time id=time2>
<script index.js> How could you handle such case? |
That will work as-is. It's going by the assumption that if |
That's just a last-resort way to run the init function in case we never find the script tag. Fast browsers usually complete in 1 attempt, but depending on connection speed, it might take a few couple of attempts to find the element in the DOM. |
How could it work properly? For example: |
I think behaviour of |
So assuming |
But the code reads like : Then back to the demo case: at the beginning, a page is partially rendered, then after 100th animation, |
Right, anything that happens after |
If a user's network is a little slow, they spends more than 1 seconds to fully load the page, then the |
Yes, the |
However, I am still not convinced that it's the proper way. The methods used are too hacky and do not seem to be easily tested or maintained.
|
It seems better than inline scripts which we should eliminate in an case because those are often forbidden via CSP. |
|
The final solution to clone states will be a backend user setting, than we can just render the right stuff into HTML, no JavaScript involved. |
Yup, there could be better solutions than hacking the JS&DOM loading |
Yeah, but the date formatting unfortunately has no server-side solution, so it will need this mutation mechanism even after clone states are properly fixed, so I consider this effort unavoidable :) |
The only challenge for date/time formatting is timezone. Timezone-based date formatting could also have a server-side solution, eg:
Personally, I think it's better to tolerate the slight flicker for timezone-based date formatting by JS instead of making the problem too complex. |
Personally, I can't tolerate flicker/layout shift during load, it's a sign of low-quality to me. |
I can make a flawless (nearly 😁 ) solution for "or even more: automatically save the browsers timezone to session and refresh the current page ", if you do not mind. Then the backend can get the browser's locale and timezone, and users can get consistent rendered result by backend and by frontend. It could be the best solution for Gitea at the moment because Gitea's frontend mixes a lot of things together. |
I made a simple demo: |
…mplates (#22861) This PR follows: * #21986 * #22831 This PR also introduce customized HTML elements, which would also help problems like: * #17760 * #21429 * #21440 With customized HTML elements, there won't be any load-search-replace operations, and it can avoid page flicking (which @silverwind cares a lot). Browser support: https://developer.mozilla.org/en-US/docs/Web/API/Window/customElements # FAQ ## Why the component has the prefix? As usual, I would strongly suggest to add prefixes for our own/private names. The dedicated prefix will avoid conflicts in the future, and it makes it easier to introduce various 3rd components, like GitHub's `relative-time` component. If there is no prefix, it's impossible to introduce another public component with the same name in the future. ## Why the `custcomp.js` is loaded before HTML body? The `index.js` is after HTML body. Customized components must be registered before the content loading. Otherwise there would be still some flicking. `custcomp.js` should have its own dependencies and should be very light, so it won't affect the page loading time too much. ## Why use `data-url` attribute but not use the `textContent`? According to the standard, the `connectedCallback` occurs on the tag-opening moment. The element's children are not ready yet. ## Why not use `{{.GuessCurrentOrigin $.ctx ...}}` to let backend decide the absolute URL? It's difficult for backend to guess the correct protocol(scheme) correctly with zero configuration. Generating the absolute URL from frontend can guarantee that the URL is 100% correct -- since the user is visiting it. # Screenshot <details> ![image](https://user-images.githubusercontent.com/2114189/218256757-a267c8ba-3108-4755-9ae5-329f1b08f615.png) </details>
Would still like to eventually have a script like this as not all things can be done in webcomponents and I'd like to remove all the inline scripts eventually. Maybe there is a solution without As for this PR, it's no longer needed. |
I will try to refactor the The "Clone" popup could be resolved by #23231 |
See if you can use https://github.com/github/relative-time-element for time. I was referring to the recent inline JS added in #23553. Those should really be in |
|
…ion on pages. (#23861) Follow #21429 & #22861 Use `<gitea-locale-number>` instead of backend `PrettyNumber`. All old `PrettyNumber` related functions are removed. A lot of code could be simplified. And some functions haven't been used for long time (dead code), so they are also removed by the way (eg: `SplitStringAtRuneN`, `Dedent`) This PR only tries to improve the `PrettyNumber` rendering problem, it doesn't touch the "plural" problem. Screenshot: ![image](https://user-images.githubusercontent.com/2114189/229290804-1f63db65-1e34-4a54-84ba-e00b44331b17.png) ![image](https://user-images.githubusercontent.com/2114189/229290911-c88dea00-b11d-48dd-accb-9f52edd73ce4.png)
The new script utilizes requestAnimationFrame to run DOM transformations as soon as possible. In my testing, this method is equivalent of a synchronous inline script in terms of outcome (no content flashes).
On Firefox, the callback sometimes fires too early and if that happens we register for another frame. I had 100% sucess within 2 frames in Firefox.