Two days before release ā and guess what? Suddenly, all popovers with information about meeting rooms in our app broke and stopped displaying. We hadnāt even changed anything related to this functionality ā how could this happen?
Situation
It turned out that the popovers were broken in all browsers except Chrome. And after the latest Chrome update, they stopped working there too.
What happened?
Four years ago, someone decided it was fine to hide a <g> element using display: none, but still call node.getBoundingClientRect() on its child elements to calculate the popoverās position.
It worked⦠until it didnāt. Now, all modern browsers correctly return zero for the coordinates and size of any child inside a display: none element.
To be honest, I didnāt want to refactor much, so I replaced display: none with opacity: 0. In this case, the element is still invisible to the user but remains in the document flow and keeps its size.
I hadnāt parsed a JWT token on the client before, but this week our backender said that he
didnāt have time to create a new endpoint like /user, and that I should extract user information
from the JWT token in a cookie.
My first thought was: is this okay? On all projects that Iāve seen backend gave me endpoint like
/user, /me, /current ā and these endpoints were created for a reason, werenāt they?
Yes, there are reasons:
you cannot store sensitive, confidential information in JWT payload
you should be mindful of the size of the JWT (it is transmitted with cookies in every request)
For example, it is not a good idea to store in JWT permissions for user and rely on it in your
UI. Because someone can modify the token, and your application could be at risk.
However, this means you can use a JWT to store some basic user information. In my current
situation, I only need name, email and photo of the authorized user, so I started parsing JWT for
this data and backend developer took another task.
What do you need for parsing JWT on client?
JWTs are Base64 encoded and contain of three parts: header, payload, and signature. You can
write your own decoding function or use one of the ready-made solutions. I checked what is there on
the internet for handling JWT tokens on the client-side:
jsonwebtoken ā very popular library for Node.js.
It is used for generating and verifying JWTs on the server-side, can be used on the client side.
Itās a good library, but overkill for my case.
jose ā another library for implementing JWT, it provides
functionality for signing and verifying tokens and set of utility functions. Again: good, but
overkill for my case.
jwt-decode ā lightweight library only for decoding
tokens. Single-purpose, easy to use, zero dependencies ā thatās the winner for today.
Iāve been using Cursor for 3 weeks, and Iām really impressed. Of course, it is not ideal and it
doesnāt replace a human developer (for now), but it can help in a lot of ways.
My favorite uses for it are writing tests with instructions, creating TS types, and
drawing diagrams. Letās look closer at each case.
Writing tests
Not all developers love to write unit and integration tests. I personally lose my inspiration
when I need to create a lot of mocks, do some routine tasks for preparing the test environment and
try to make everything work with components or other libraries.
And thatās the place where AI shines! Of course not without a helping hand, butā¦
How I improved results of generation
created mdx files with instructions for writing tests with examples (separate files
for unit and integration tests)
described the flow: AI ought to write tests, after that run them and check results. If there are
failed tests, AI fixes them
run command write tests for ... and add relevant instructions to the context
Of course, there is still a lot of work with reviewing, but with mocks and setting up
environments it helps a lot.
Generating types
When you get a new endpoint and add it to your application, you need to describe types. In all our
projects we use TypeScript, and before starting to use AI I created types manually (there is
Swagger only on some of the projects). But now⦠I just need to give the API response to AI and
describe what it is and some constraints ā and after a few minutes I have generated types. There
is room for improvement, but it speeds me up a lot.
Diagrams
I love diagrams, and I believe that it is easier to understand processes and technical details
from diagrams and schemes, not from plain text. And I explored a whole new world for me with
this prompt: @project explain how is ___ implemented and draw a scheme of how ____ works.
I can read and have a mermaid diagram (I just copy and paste in an online mermaid editor) in front of
my eyes ā it has simplified a lot.
Iāve been refactoring our codebase, and it seems like my colleagues from the past were very fond
of the
<b> tag. Theyāve used it a lot. I am not a big fan, especially of code like this:
.componentb {
font-weight: normal;
}
But maybe there is some reason why these guys applied it everywhere? Letās research a little!
<b> now
I knew that <b> was for Bold. As I found out, now this is not the case. The HTML5 specification says:
The b element represents a span of text to which attention is being drawn for utilitarian purposes without conveying any extra importance and with no implication of an alternate voice or mood, such as key words in a document abstract, product names in a review, actionable words in interactive text-driven software, or an article lede.
And adds:
The b element should be used as a last resort when no other element is more appropriate.
For me, it is a really confusing tag now: there are some ideas about appearance (and browsers
support it), but <b> is not about appearance. Issues with this tag are presented in the W3C
article āUsing <b> and <i> elementsā.
I plan to get rid of <b> in most places of my code and try to use h1-h6, em, strong
or mark ā a pretty wide choice!
I already have had this issue and was surprised by this behaviour, but I forgot this ā
and wasted 2 hours on debugging. I suspected componentās library, checked contexts, and tried
to find problems in composition.
So, what happened? In our App.tsx:
<Routerhistory={history}>
<UuiContext.Providervalue={services}>
<Header />
<Routes />
<Footer />
</UuiContext.Provider>
</Router>
In Header.tsx ā navigation:
// it's component from library, responsible for highlighting active menu item
// use uuiContext from UuiContext.Provider and check is link active using history
And it works⦠almost. When you click on buttons in MainMenu url is updated, content is re-rendered.
But there is no highlighting for active menu item in MainMenu.
Started with MainMenu.tsx: add breakpoint in function defining is link active.
But on button clicks and changing url this function is not called. And component is not re-rendered.
Add console.log(ārenderā) in Header.tsx. So, it is also not re-rendered.
Despite updating the history object, and seeing those updates reflected in uuiContext.uuiRouter.history,
nothing was triggering a re-render.
Why donāt children of UuiContext.Provider update?
At this point, I went down a rabbit hole: tried to debug in contexts, because I thought that I have several
instances and something weird happens. Found nothing, of course.
But after all this debugging, idea occurred to me: content is re-rendered because of changing
actual Route, what if I put Header in corresponded pages?
It worked, but in this case Header unmounted and mounted each time route changes. Itās not good
user experience.
And then finally I asked right thing: how React and React Router define, what should be re-rendered?
Results of answering on this question:
we update history
history object is stable reference, so you cannot track changes with useEffect and history.location
dependency
but useLocation and useParams watch changes location, and when we use them ā our component
re-renders after changes
So I just added to Header.tsx:
useLocation();
//...same code
The most annoying thing about that I already have solved problem like this,
but remembered about it only when I found solution again. Writing it down this time so Iāll remember š¤Ŗ