date: “2021-10-13T16:00:00+02:00” title: “Guidelines for Frontend Development” slug: “guidelines-frontend” sidebar_position: 30 toc: false draft: false aliases:
Gitea uses Fomantic-UI (based on jQuery) and Vue3 for its frontend.
The HTML pages are rendered by Go HTML Template.
The source files can be found in the following directories:
web_src/css/
web_src/js/
web_src/js/components/
templates/
We recommend Google HTML/CSS Style Guide and Google JavaScript Style Guide
js-
prefix for classes that are only used in JavaScript.helpers.less
could be helpful.ctx.PageData["myModuleData"] = map[]{}
, but do not expose whole models to the frontend to avoid leaking sensitive data.elem.disabled = true
instead of elem.setAttribute('disabled', 'anything')
, prefer $el.prop('checked', var === 'yes')
instead of $el.prop('checked', var)
.<button class="ui button">
instead of <div class="ui button">
.!important
in CSS, add comments to explain why it’s necessary if it can’t be avoided.ce-
prefix.gt-
prefix (gt-relative
), while Gitea’s own private framework-level CSS classes use g-
prefix (g-modal-confirm
).In history, Gitea heavily uses Fomantic UI which is not an accessibility-friendly framework.
Gitea uses some patches to make Fomantic UI more accessible (see the aria.js
and aria.md
),
but there are still many problems which need a lot of work and time to fix.
Mixing different frameworks together is discouraged, it makes the code difficult to be maintained. A JavaScript module should follow one major framework and follow the framework’s best practice.
Recommended implementations:
Discouraged implementations:
To make UI consistent, Vue components can use Fomantic-UI CSS classes. Although mixing different frameworks is discouraged, it should also work if the mixing is necessary and the code is well-designed and maintainable.
async
FunctionsOnly mark a function as async
if and only if there are await
calls
or Promise
returns inside the function.
It’s not recommended to use async
event listeners, which may lead to problems.
The reason is that the code after await is executed outside the event dispatch.
Reference: https://github.com/github/eslint-plugin-github/blob/main/docs/rules/async-preventdefault.md
If an event listener must be async
, the e.preventDefault()
should be before any await
,
it’s recommended to put it at the beginning of the function.
If we want to call an async
function in a non-async context,
it’s recommended to use const _promise = asyncFoo()
to tell readers
that this is done by purpose, we want to call the async function and ignore the Promise.
Some lint rules and IDEs also have warnings if the returned Promise is not handled.
dataset
The usage of dataset
is forbidden, its camel-casing behaviour makes it hard to grep for attributes.
However, there are still some special cases, so the current guideline is:
For legacy code:
$.data()
should be refactored to $.attr()
.$.data()
can be used to bind some non-string data to elements in rare cases, but it is highly discouraged.For new code:
node.dataset
should not be used, use node.getAttribute
instead.v-if
and v-show
to show/hide elements..gt-hidden
and showElem()/hideElem()/toggleElem()
, see more details in .gt-hidden
’s comment.It’s recommended to use:
<div class="gt-name1 gt-name2 {{if .IsFoo}}gt-foo{{end}}" {{if .IsFoo}}data-foo{{end}}></div>
instead of:
<div class="gt-name1 gt-name2{{if .IsFoo}} gt-foo{{end}}"{{if .IsFoo}} data-foo{{end}}></div>
to make the code more readable.
A lot of legacy code already existed before this document’s written. It’s recommended to refactor legacy code to follow the guidelines.
Gitea is using Vue3 now. We decided not to introduce JSX to keep the HTML and the JavaScript code separated.