I primarily use ReactJS.
We used a domain-driven pattern. Although there is still that component parent hierarchy thing going on.
TDD (tech design doc), write the code, linter, unit tests (Jest/Enzyme eg. render part of component take code snapshot, assert stuff) and then WDIO for visual regression testing (image diffs). It is a time consuming thing to setup but when you have like 600tests it's nice/assuring. Then it runs on a pipeline (Jenkins) for about an hour before it gets released to some domain.
Personally I am still in the get it done/MVP stage. The above is ideal case when you're established/dealing with many other people changing code.
I am going with a Selenium/functional test though personally for the thing I'm working on now (2-way real time interactive app).
There's different ways to test stuff depends what your thing is. The TAs I worked with use Eggplant.
The main thing though about separation of concerns is important when possible just to reduce cognitive load for the next stuff you add.
If you want to know what you can do to prevent your projects from sinking into chaos:
1) Use a framework, even if it isn’t “Perfect” it is at least documented which is something you seldom have time for when you are working on your own. (I’ve never worked on an in house framework that was documented, I’ve worked on a lot of of in house frameworks)
Edit: Angular, Ember.js and maybe even Next.js are frameworks. Vue and React are not. You need more than presentation.
2) Settle on something for forms authentication eminently and make sore to keep to it. Doesn’t mater if it is frontend only, backend only or a mix. If you use a lib or if you do your own. This is one of the places where things can quickly become a mess so knock it out from the beginning.
3) Put as much of your logic into utility functions, service objects and so on as possible. Make sure you don’t pass huge “magic” objects into any of these functions and look into making them small, self explanatory and testable. You will need to reuse functionality a hell of a lot more than you think and having it mixed in with your presentation layer, or data layer will make it less testable and less reusable.
Edit: Also utility functions and service objects are easier to test than testing the same functionality in the UI.
4) Your presentation layer will turn into something ugly quickly especially if all you do is your work so:
a) Try do do small refactoring along the way and if things still get bad fight for the time for a larger refactoring so you spare yourself the rewrite.
b) Your first draft of the code will do the job but to get to a simple and clear version takes work, even if it doesn’t look like it so try to check the “simple” version in to git and not the “working” version.