loading...

Fixing Dev.to's scrollbar bug with a single line of code

almenon profile image Almenon ใƒป14 min read

So many articles are written after the fact, and the author either forgets or takes for granted the jumps in logic they made. This article was written as I solved the problem, before I even knew I could solve the problem. I hope this gives you a better insight into the bug fixing process, from the very beginning to the very end. Without further ado:

=====================================

I was editing my article when I noticed an extremely annoying thing - each character I typed caused a scrollbar to appear and dissapear. My first instinct was to open up the dev console to inspect it, whereupon I was greeted by this:

-oooooooo/-      .+ooooooooo:  +ooo+        oooo/
+MMMMMMMMMMm+   -NMMMMMMMMMMs  +MMMM:      /MMMM/
+MMMNyyydMMMMy  /MMMMyyyyyyy/   mMMMd      mMMMd
+MMMm    :MMMM. /MMMN           /MMMM/    /MMMM:
+MMMm    .MMMM- /MMMN            dMMMm    mMMMh
+MMMm    .MMMM- /MMMMyyyy+       :MMMM/  +MMMM-
+MMMm    .MMMM- /MMMMMMMMy        hMMMm  NMMMy
+MMMm    .MMMM- /MMMMoooo:        -MMMM+oMMMM-
+MMMm    .MMMM- /MMMN              yMMMmNMMMy
+MMMm    +MMMM. /MMMN              .MMMMMMMM.
+MMMMdddNMMMMo  /MMMMddddddd+       sMMMMMMs
+MMMMMMMMMNh:   .mMMMMMMMMMMs        yMMMMs
.///////:-        -/////////-         .::.

Hey there! Interested in the code behind dev.to? Well you're in luck - we're open source! Come say hi, tell us what you're debugging, or even lend a hand in our repo - https://github.com/thepracticaldev/dev.to
Did you find a bug or vulnerability? Check out our bug bounty info here: https://dev.to/security

I was pleasantly surprised they had a security bug bounty. I proceeded to get sidetracked looking into the bounty program. Then I remembered I had a issue to solve.

I opened up the repo and searched "scrollbar" in their issues. I came across https://github.com/thepracticaldev/dev.to/issues/3330 which described the exact issue I experienced. Oddly enough it only had one user who reported it - it must be somewhat rare. Or people don't know to go to github to report the issue. My experience with creating AREPL has taught me that for every issue people bother to report, according to telemetry it's probably happened multiple times already.

After confirming that it's a reported issue (with a help wanted label!) I went back to the dev tools. I noticed that the textarea's height style was changing each time I typed.

Before: (no scrollbar)

<textarea style="height: 968px;" class="articleform__body" id="article_body_markdown" placeholder="Body Markdown" name="body_markdown" ></textarea>

After: (scrollbar)

<textarea style="height: 924px;" class="articleform__body" id="article_body_markdown" placeholder="Body Markdown" name="body_markdown"></textarea>

This makes sense - the scrollbar only appears when there's not enough height to display everything. But why was the height changing? I wasn't entering a new line, I was just adding a character to an existing line. Odd.

In the middle of this I had a sudden realization - I could write an article about this! It would serve as a good way to track my thoughts as I solved the issue. The downside is there's no turning back now - If I fail to solve this I'll have a ...

WAIT! Holy crap - I just got the exact same bug:

demo of error
horrible yellow courtesy of flux

I'm forced to resort to writing this on notepad for the time being. I guess the silver lining is that I can reproduce the issue. I took the following paragraph and pasted it into a new draft. And ... huh. Problem didn't appear there. Then I remembered that according to the issue report it only happens when there is a certain amount of lines. So I added 21 lines before it and I got the problem again ๐Ÿ›!

demo of error

The next question is if it happens after a certain number of lines why doesn't everyone run into this issue? Is there a unspoken agreement among dev.to writers not to go above 21 lines ala twitter's character limit? I highly doubt it. There must be something I'm missing. Maybe something related to the text I'm typing.

After playing around with the text for a bit, I found out that if I delete "I'll have a " on the line The downside is there's no turning back now - If I fail to solve this I'll have a then the problem doesn't appear anymore. The problem only appears when the line goes over the width of the draft.

Now I should be able to create a minimal reproducible example. I opened up a new draft, typed out aaa.... untill it overflowed the line, then added 21 lines. No error ๐Ÿค”.

I fiddled around with the end a bit more and discovered that the error ONLY happens in the very specific scenario where you go over the draft width with space. Any normal character will simply go onto the next line, but you can add as many spaces to an existing line as you wish.

So now I can reproduce it, which is half the battle. Time for debugging!

But before that I want to check something - I noticed in the settings that I am using the V1 editor. Will the problem still appear in the V2 editor?

No. The problem does not appear there.
And it's worse than I thought - new users default to the v2 editor, so this problem only affects old farts like me, and only a subset of grandpas at that.

Well, this was a waste of time. :|

On the bright side I can comment in the issue with the solution (switch to v2 editor), so that should help some folks out. And just for the sake of my pride, I'll spend 10 minutes trying to see how I could fix the issue. Starting now.

Eleven minutes later

So it turns out the issue STILL happens with the v2 editor, so it's a good thing I checked again. It's just that in the v2 editor when your spaces go over the draft width your cursor stays at the same spot, so it looks like everything is working. But with some fiddling you can still reproduce the error.

So now let's get to debugging.
Finally, you say!

I set a breakpoint for attribute modifications of the textarea element. I edited the element, which caused the height change, which caused the code to stop on the breakpoint. Unfortunately the file was blank, so I couldn't see the code it was stopped at. But I looked at the stacktrace and could see that in there was a file called TextareaAutosize.js, in a folder called preact-textarea-autosize, inside node_modules. So dev.to is using a preact (variant of react) package for their textarea implementation. Googling it led me to https://github.com/DisplaySweet/preact-textarea-autosize which 404's.

sigh

So I went to the next link - the npm package:

https://www.npmjs.com/package/preact-textarea-autosize

The repository link leads to https://github.com/evenius/react-textarea-autosize, which hasn't been updated in over two years and has no section for issues. Great. However, it is forked from a more popular repo that does have issues and a demo site. I searched the issues but didn't find my scrollbar problem reported there. I went to the demo site, and HOW ABOUT THAT, you can reproduce the problem in their demo site! So the issue might not be with dev.to code - it could be with how they are calling the library or an internal library issue.

At this point it's 1am so I went to bed. Sleep is healthy, y'all.

Me, ready to sleep:
Pugs, somehow both the cutest and ugliest animals on earth:

The next day I finished a long day of work at 15Five, read about 100 pages of Scythe, and got back to work. I wrote up what I did yesterday, and in the process found another react textarea package called react-autosize-textarea. (not to be confused with react-textarea-autosize). HOW MANY OF THEM ARE THERE?? Even though the textarea script on dev.to was showing up blank, I noticed it was source-mapped from a bundled file, so I clicked on the tiny {} in the bottom left to pretty print it, searched for code matching a recent commit in the library, and confirmed that I was looking at the right one. Whew. It's been a hour, but now I can finally start debugging.

Weren't you going to do that already?

errr, yeah. Anyways:

I started off with trying to debug the bundled minified code, which was a absolute nightmare. I quickly did the sensible thing - gave up, cloned the repo, and made a reproducible example with code I could easily debug.

Or at least that's what I should have done. I went back to trying to debug the bundled code for the next hour.

Yikes

Fun fact: see that line where the breakpoint is, m=1/0? That corresponds to this line:

let maxHeight = Infinity;

You read that correctly, in Javascript 1/0 evaluates to infinity! And if you really want to be baffled, try executing this line in the console (press f12 to access):

"b" + "a" + +"a" + "a"

The output is baNaNa. I mean, duh. What else were you expectingโธฎ. But anyways, Javascript WTF's is a entire book of it's own1. Let's get back on track.

I assumed the code was setting the height every other character, but it appears to be something else. When calculateNodeHeight is executed the textarea already has a different height. I'm guessing it's something to do in combination with how the native textarea works and the constraining html. The mystery deepens...

I tried comparing the two textarea objects in Winmerge but didn't notice anything fishy.

If this is a html issue it's time to get educated. I read through https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight. Then I had a realization: why even bother with scrollbars in the first place? The browser already has a scrollbar at the edge of the screen. react-textarea-autosize already expands the textarea to a infinite length2. The scrollbar is entirely unnecessary.

So I googled for "disable scrollbar" and came across this forumn post which reccomended the css style overflow:hidden. hidden disables scrollbars - you can read more about overflow options here. Applying it to the textarea style got rid of the issue! ๐ŸŽ‰

Next I experimented with different page layouts - does it still work with half-window width? Quarter window? Mobile? Ipad? The answer was yes, yes, yes, and yes.


Thanks to this lovely feature of the chrome devtools I was able to test all the mobile layouts from my laptop without even needing a phone.

Now comes different browsers. I put it in Internet Explorer and to my horror the page didn't have any scrollbars, meaning the textarea had to have scrollbars! My plan was ruined! CURSE YOU IE!3

But then I noticed that the page didn't even have a "save changes" button - it was already totally broken and I didn't have to worry about supporting IE. Bullet dodged.

Then I tried edge. I entered in about 19 lines, but then the vertical scrollbar started flashing randomly when I typed in new lines. Woah. You could also type inside the footer on the bottom - you can even see the cursor in there. So edge is already pretty buggy (why am I not surprised). Adding overflow:hidden fixed the vertical scrollbar problem and didn't cause any other problems to pop up elsewhere.

Finally I tried Firefox. The problem didn't even appear in firefox without the fix, way to go Firefox!

Now that I confirmed the fix worked I created a PR. No need to even open a editor for this - I just went to https://github.com/thepracticaldev/dev.to/blob/master/app/assets/stylesheets/preact/article-form.scss, clicked on the edit pencil, made my change, and commited it. Github automatically created the forked repo - from there I clicked Create Pull request, filled in a short template describing the change, and I was done!

woman spinning in joy

Well, not quite. The reviewer had a comment (reviewers always do) requesting before/after images. With ShareX this was quite simple to provide. A couple days later, my PR was merged!

You can check it out yourself - create a new article, right click the textarea and click inspect elemnt, and under .articleform__body there's a single line of css, overflow: hidden that prevents the scrollbar from appearing ๐ŸŽ‰

So, what can we take from this?

  1. Bugs can be solved in surprising ways. You should keep your eyes open for workarounds, shortcuts, and other novel ways to entirely bypass the problem. This is NOT an excuse for dirty unreadable hacks. (lookin at you regex, love you honey but you got some problems) Remember that premature optimization is the root of all evil and that you will be reading your own code far more than writing it.
  2. You don't need any fancy knowledge of algorithms or expensive macbooks to get into open source. All you need is a web browser. With the advances of software like repl.it and others practically everything can be done in the cloud. You can use all your free hardware space for sexy pictures of cucumbers (no judgement)
  3. More companies should open-source their code. You get free contributions and free PR. In some cases contributors can become employees, saving you thousands in hiring costs. Finally open-sourcing gets rid of the false sense of security created by "security through obscurity"4 - by open-sourcing you HAVE to keep secure for fear of someone seeing your code. Even though in practice only a few people will bother looking for vulnerabilities and most of them will probably be security researchers or bounty hunters. You DO have a security bounty, right?
  4. Most of the work in fixing a bug comes from reproducing it, finding out why it's happening, finding a fix, and testing the fix. Coding is a suprisingly small part.
  5. When you run into a problem, try to find an associated github repo and report the problem to the maintainers. Just by including detailed reproduction steps you're doing them a massive favor5, and sometimes the mere act of researching the problem leads you to discover a workaround or solution (or that you're a idiot doing something stupid). Last of all, if the code is open source, fixing it is a possibility! It just takes some hard work ๐Ÿ”จ.

  1. see https://github.com/denysdovhan/wtfjsย โ†ฉ

  2. If you wana get technical, you'll "only" be able to go down a couple billion lines before you run out of memory. With utf-8 encoding each ASCII character is a byte so 4 gigabytes of ram is enough to hold 4 billion characters. The more you know! ~~~ โญย โ†ฉ

  3. I was trying to find a picture for this and came across this glorious vintage meme. It was so wonderfully terrible I almost had to include it.ย โ†ฉ

  4. Note that obscurity is fine as a defense in depth measure, you just shouldn't rely on it.ย โ†ฉ

  5. A good bug report has 5 parts: A. summary B. reproduction steps C. expected result D. actual result E. current settings (ex: windows,chrome) and if you're really going for gold F. pictures/video of the problem. A report like this will make developers sing your praises to the high heavens ๐Ÿ˜‡. Most issues only have a badly written part A. and it can be frustrating to even understand what's going on.ย โ†ฉ

Posted on by:

almenon profile

Almenon

@almenon

I write from time to time. Views expressed are my own and may not represent the opinions of any entity with which I have been, am now, or will be affiliated.

Discussion

markdown guide
 

You don't need any fancy knowledge of algorithms or expensive macbooks to get into open source

Here I am having some knowledge of algorithms and an expensive macbook, but not really getting into open source, I feel ashamed. ๐Ÿ˜…

 

This was an excellent post!! Kept me wanting to read more as I went on, especially since I missed your PR being merged. ๐Ÿ˜…

Small tip, you can use the meta tag instead of devto; more visibility that way.

Looking forward to your next post!

 

Thanks for the tip! I've changed the tag, every bit of extra SEO counts. I may also be guilty of obsessively looking over dev.to/daolf/-what-is-the-best-tim... to determine the best time to post this haha.

 

This was a great description of what real world web development problem solving looks like.

It's not a straightforward process, it's not pretty, but it's effective.

I think your creativity in problem solving, perseverance, and also knowing when to step back (to get some sleep) are all things new and experiences devs should take note of.

Thanks for the post!

 

"expensive macbooks"

YUP! Indeed MacOs disables visual scrollbars by default so it's likely the devs with fancy macbooks who built the site never noticed the issue (just like it never affected me..).

Sometimes building and designing on top of the line hardware can blind us to some issues (same thing happens when designers have 27" apple cinema displays and forget that other people don't, or forget that most people's smartphones process javascript like 5x slower than flagship devices).

Which is to say.. sometimes not having an expensive macbook makes you more valuable as a developer or designer ๐Ÿ‘

Which is to say.. fuck yeah diversity!

 

I've gotten the odd problem of things working great for me, then finding out there's a bug that only affects top-of-the-line, high-resolution, ginormous screens. My font-sizes adjusted as per my CSS @media responsive rules which were based on screen width. The problem was that by adjusting, the last few letters in two of my menu items would be cut off if the extension icon was too close to the end of the browser's toolbar. It was an easy fix, but I would have never known if I hadn't been told about it. Who knew odd screen ratios could screw up a menu?

 

Well, so right! I got a small resolution screen notebook at home, I have shopping carts at online shops where I am not being able to reach the submit button, because the shopping carts height is higher than my screen is able to show...

On the other hand, I had a bug on a client's website where the logo graphic was inverted. Took me hours to figure out, that the graphic was in the wrong color scheme... CMYK instead of RGB, so the macbook inverted it and the default windows user wouldn't ever noticed this ;)

 

I use my phone to try and write, but every time the keyboard got focus, it scrolls out of view of the text cursor.

It's quite difficult to write this way! Hopefully the scrolling gets priority for getting fixed.

 

That sucks! :( Unless someone reports it they won't know there's a problem to be fixed - I suggest making a issue on their github page:

github.com/thepracticaldev/dev.to/...

You can use a screen recording app to make it clear what's happening.

Or you can write out a report by following tip #5:

A good bug report has 5 parts: A. summary B. reproduction steps C. expected result D. actual result E. current settings (ex: windows,chrome) and if you're really going for gold F. pictures/video of the problem. A report like this will make developers sing your praises to the high heavens ๐Ÿ˜‡. Most issues only have a badly written part A. and it can be frustrating to even understand what's going on.

 

Maybe you can update the link to the screen recording app, because it is broken :) Thanks.

 

Thanks for fixing this bug and such a great story, I really enjoyed hearing how you tackled it step by step

Most of the work in fixing a bug comes from reproducing it, finding out why it's happening, finding a fix, and testing the fix. Coding is a suprisingly small part.

 

A fun read, thanks for posting! :)

 

This is a great post @almenon , thanks for walking us through your process of eliminations, the discoveries and the solution.

Really loved reading it :)

HOW MANY OF THEM ARE THERE??

There are so many it's not funny anymore ๐Ÿ‘€

Well, not quite. The reviewer had a comment (reviewers always do)

Hahaha that would have been me :P

 

I enjoyed reading this because of your storytelling

 

Great post! I love the idea of documenting your process of debugging and solving the issue to make this post. It is a great play by play of your whole process. Great stuff!

 

Great job on the bug hunt. Now the real question is, why is a 3rd party package required in order to implement an auto-sizing textarea?

 

My rule of thumb is if the package fits your use case, is more than a couple lines, and has been updated sometime recently, it's probably best to re-use it instead of writing your own code. If you try re-writing the code on your own you will probably discover the situation is more complex than it appears and end up spending more time than you allocated. In this case react-textarea-autosize is two files of code, so I can understand why they used a package.

On the other hand it hasn't been kept up to date, last commit in 2016 and it's 166 commits behind the original repo. I'm not a preact developer so I'm not sure how hard it would be to adapt the original repo for preact. I'm guesing I would just stick with the old preact version. ยฏ\(ใƒ„)/ยฏ