Frontend Development Environment Checklist (2023)

2023. 3. 31.

Frontend Development Environment Checklist (2023)
image by Andrea Piacquadio

Every time I start a frontend project, there are things that need to be decided. Defining the development environment and stack, choosing a version control tool (usually Git), deciding how to manage branches, determining the versioning strategy, and so on. Starting a new project always involves checking or newly defining many things. Of course, a well-established team might leverage existing practices, but because there were always issues encountered in previous projects, I don't think we ever used the exact same methods and tools. There were always slight differences. For companies with short project cycles, the degree of change might be small, but for companies with many long-term projects, new projects start occasionally, leading to the question, "Where do I even begin?"

In particular, setting up new dependencies and configurations is a recurring task. At the very least, versions get updated. Updating versions often makes it no different from dealing with new dependencies :( Ultimately, it always feels new. I've never just reused an existing environment as is. Because of this, I've occasionally written posts about how to set up a development environment to avoid forgetting things. Those posts had short lifespans too. Just updating the major version of a single environment configuration tool required tweaking various settings. For tools that need to integrate, significant time had to be spent responding to changes caused by updates in other required tools. While basic tools might be similar across projects, how they are combined leads to a truly diverse range of configuration methods. Tools with many dependencies are particularly troublesome. I think things are gradually getting better these days.

Since the actual setup details, which have a short shelf life, aren't too difficult to follow just by checking the official documentation, I thought it would be good to manage a checklist of tools to decide on when starting a project. I could add newly emerged or interesting tools to this list, making it easier to decide by tackling them one by one later. I've often suffered due to forgetting things or procrastination when starting projects. It seems beneficial to pre-organize a list of things to decide and potential candidates, review them one by one, reflect on previously used tools, and discuss them with colleagues.

Source Code Version Control Tool

Unless there's a special reason, Git is the standard version control tool. You'll need to choose a remote repository, but unless there's a special reason, GitHub is the likely choice. Depending on the situation, other options exist. GitLab is the next most famous service after GitHub, and there's also Bitbucket, offered by Atlassian, known for Jira. In most cases, GitHub is probably the best bet.

If you've created a local Git repository with git init, the very first thing to do is create a .gitignore file. If you have one you already use, you can just copy and paste it. If you need to create a new one, I recommend using a service like gitignore.io rather than creating it from scratch.

image

By adding tags with keywords relevant to your environment like this, it generates a clean .gitignore file tailored to your needs. If it seems a bit excessive, you can always edit it directly since it's just text.

Package Manager

Specifically, Node.js Package Manager. If Deno becomes mainstream later, the role of the package manager might become ambiguous, but even then, a similar tool will likely be needed. Currently, package managers play a crucial role in frontend projects, enabling the installation and management of dependencies. It used to be just npm. There was also the unconventional bower, but I'll exclude it as it's not commonly used nowadays. Now, besides npm, there are a few more options: yarn and pnpm. Compared to npm, which has the advantage of being a built-in Node tool, yarn and pnpm each have their own distinct features and benefits. Lately, it feels like yarn, pnpm, and npm are all becoming similar, leading to a leveling-up effect. This kind of competition is good. Until a few years ago, yarn was considered for monorepos, but the workspace feature needed back then is now sufficiently supported by all tools.

My personal opinion is that unless there's a specific reason, just using npm should be fine. Speed issues might only affect deployment time, but nowadays, this can be compensated for using caching methods. The bundling speed seems more concerning than the package installation speed, and this is also being improved through various methods.

Static Analysis Tools

Static analysis tools analyze source code as plain text to provide useful features.

There used to be a wide variety of tools. In a way, the JavaScript development environment seems to have started with the evolution of static analysis tools. Many diverse tools emerged. After various developments, the two tools most commonly used among static analysis tools are the ones listed above.

ESLint, which is exceptional at catching code smells and maintaining project conventions, and Prettier, which neatly formats code with a single save after writing syntactically correct code. These are now indispensable tools for coding. Prettier, in particular, has completely eliminated the time developers spend manually formatting code indentation. It feels like the most frequently used shortcut key used to be the one for tidying indentation, but now it's rarely needed. When using other languages, the absence of Prettier highlights its value.

There's no real choice here. Install both as essential tools and configure them according to the methods provided by your editor or IDE.

Bundler

Bundlers have evolved significantly, starting from task runners like grunt and gulp. They progressed from automating the build process with task runners to integrating module bundlers and task runners. If the modern frontend development environment began with static analysis tools, it truly blossomed through the development of bundlers, which served to integrate all the tools. Among the many bundlers, the undisputed star that seized the throne is Webpack. It maintained a top position for a while, but many competitors challenging its reign have emerged, armed with various strengths.

Here's a list of bundlers worth considering:

Excluding Webpack, the ones that feel stable enough to try out given the chance are esbuild, Vite, and Parcel. The others are good tools too, but I considered ecosystem and compatibility. Among these, I plan to try esbuild in a project soon because of its speed. I heard from colleagues who tried it that there were several-fold speed improvements. The background likely involves the built-in transpiler, which internally covered what Babel did, offering more room for performance optimization. The advantages of the Go language probably also play a role. If I were starting a new project, I would try using esbuild.

Transpiler

Often called compiler, though transpiler is the more accurate term. Until recently, it was the era of Babel dominance. If Webpack was the top bundler, Babel was the top transpiler. Initially, it enabled the use of the latest JavaScript specifications not yet supported by browsers and converted modern specs for older browsers. However, Babel itself provides a foundation for extending JavaScript syntax, so it also handles tasks like transforming JSX or TypeScript. This allows adding new syntax or features to the language. I remember looking at Babel-transformed code once and being impressed seeing Async/Await implemented with a switch statement.

Then, a remarkable new tool called swc appeared, and since esbuild also supports transpilation, some competition has emerged. I recently used swc in a personal toy project, and it worked perfectly well with Webpack, Storybook, etc., without any missing features. Although experimental, React-Fresh also works. Even though it's experimental, it works quite well. It seemed particularly good when using the testing tool Jest. The configuration was very concise and clean. (https://swc.rs/docs/usage/jest). TypeScript operates with two parts: the type checker (tsserver) and the compiler (tsc), which are independent. swc only covers the compiler part. While swc uses its own configuration file, .swcrc, you also need to create tsconfig.json for the type checker to ensure consistent behavior in editors or IDEs.

All are good tools, so choosing any of them shouldn't be a problem. The crucial factor seems to be compatibility with other tools needed for the project.

Testing

Testing tools for the frontend seem to have stabilized considerably now. While there are some choices to ponder, they are all good tools. From unit tests to E2E tests, integrating tests into a project is now really easy. Testing tools can be categorized in several ways, but here's a list of what I currently consider the most ideal tools, regardless of category:

First, Jest seems essential for unit testing. It can also cover E2E testing by integrating with Puppeteer or Playwright. However, for E2E, using Cypress is probably the most convenient option. Cypress is a bit heavy, so I tried covering both unit and E2E tests with Jest integrated with Puppeteer or Playwright a few times, but it felt inconvenient and lacking. In many aspects, the conclusion was Cypress.

Cypress can also run unit tests, but since it fundamentally runs tests with a browser instance open, it's heavy. The best developer experience seemed to be running unit tests frequently with Jest and selectively running E2E tests with Cypress.

When selecting an E2E tool, you can be a little less sensitive about browser support. Test cases aren't written to track down unexpected cross-browser issues. The test cases we write are for testing normal behavior that developers know and can predict. The goal is to quickly identify developer mistakes, not browser mistakes. Besides, it's impossible to write test cases with cross-browser issues in mind every time. It might catch something occasionally, but it's not very useful. At best, it catches errors from using APIs that shouldn't be used. These are better tested manually. Testing design errors like pixel misalignments with code is even worse. Not only are the test cases hard to read, but it's also not easy to intuitively identify the problem when it breaks. It's not useful. If such tests are absolutely necessary, consider automated image comparison.

Framework

Frameworks have undergone many changes, both large and small. Various frameworks embodying different philosophies and implementations have appeared and disappeared. While the scene isn't as overheated as before, new frameworks still emerge occasionally. Currently, React, Vue, and Angular maintain a three-kingdoms-like balance. Of course, in terms of market share, it's not an even split. React's share consistently exceeds half in any survey. Vue once rapidly gained ground, fiercely chasing React, but its momentum seems to have waned recently. Projects that chose Vue back then are gradually switching back to React.

I've used all three frameworks in production projects, and my personal preference leans towards React. I tread carefully because some people identify strongly with their framework (Framework === Self), much like those who identify with their programming language (Language === Self), but I believe the React community has always been at the forefront of initiating change or noticeable improvements, both then and now. I think Vue was able to catch up quickly because it rapidly absorbed React's concepts. Vue's reactivity system was excellent. Despite its name, Vue is more reactive than React. However, Vue didn't seem to offer much beyond that (personal opinion). React can become as reactive as Vue by utilizing MobX.

There have always been many choices for frameworks, and more will likely emerge. If your team is already proficient with a particular framework, using that seems appropriate. If team members are familiar with different frameworks or if it's a completely new project, I would still recommend React without hesitation. The first reason is the community, and the second is its purity. The framework's intended code itself pursues the purity of functional programming, and it's so pure that there's almost no magic involved. It's just JavaScript. This makes it flexible for combining various things to meet different requirements and situations.

Svelte initially impressed me with its demo ("Wow!"), but I'm hesitant about using it in production. Since then, I've only run some simple code to check the results, but for me, I'd feel uncomfortable using Svelte until I understand its internal workings to some extent. It's problematic if it doesn't work, but even more unsettling if I don't know why it works.

Until a few years ago, I was very interested in new frameworks. Whenever something new came out, I'd install it and experiment. I was curious about new ideas and philosophies, and it was just fun. But recently, nothing particularly striking has emerged, and I don't pay much attention anymore. For the time being, React seems sufficient until a prominent and stable newcomer appears.

State Management Tool

There often isn't much choice for state management tools, so there's not much to cover. If you're using Vue, you use Vuex. For React, it's still largely Redux. Nowadays, Redux Toolkit seems to be becoming the standard, often used in combination with React Query.

Other useful state management tools include MobX and XState, which are versatile across frameworks.

I developed a project using the React + MobX combination, and it was quite good. It required looking at the store differently than usual, which caused some confusion about how to structure it, but I think I could do better if I did it again. Comparing it to the RTK (Redux Toolkit) combination, it's more a matter of preference than one being definitively better. However, considering community power, RTK seems preferable. My feeling is that MobX's momentum has also slightly declined recently. It's a shame; it might be used more if modules could be created in a functional style instead of classes.

Recoil is also worth considering, but for some reason, I haven't been drawn to it and haven't looked into it properly yet.

XState is a JavaScript implementation of FSM (Finite State Machines) capable of implementing complex state machines. While its built-in features make it suitable as a state management tool, it can also be used selectively for controlling large or small structures. Therefore, you can use Redux for the main store while locally utilizing XState in UI components with complex states to keep the control structure concise. I haven't applied it in a production project, only experimented with it while studying. Although I'm generally very conservative about adding external dependencies, I felt that even if used in just one component, its value would be significant if applied appropriately. It fundamentally aims for a functional approach and thoroughly considers unit testing. I'm eagerly looking for an opportunity to use it in practice. Of course, I need to carefully weigh whether it offers advantages over simply implementing a simple FSM directly, as simple cases can be adequately handled with predefined states and branches.

Zustand

There are also next-generation state management tools like Zustand and Jotai. Looking at Zustand's implementation code, it was remarkably simple. It reminded me of examining the early Redux code, which was nice. Tools whose workings can be easily understood like this are reassuring and somehow endearing. Also, seeing Zustand's bear image reinforces the importance of branding, even in open source :)

CSS Tools

I struggled with what to name this category and settled on CSS Tools. The landscape of CSS-related tools has changed somewhat. Initially, preprocessor tools extending CSS like Sass, Less, and Stylus were dominant. Recently, however, tools that handle CSS within JavaScript have become mainstream. Examples include Styled-components, CSS-in-JS, and Tailwind CSS. In this area, Styled-components was the leader but is now passing the baton to Tailwind. Tools that extended the limitations of CSS with another language seem to be fading in popularity as CSS itself evolves. Key features like CSS Variables and Nesting are now standard. Relatedly, PostCSS, while closer to a preprocessor, is widely used. Considered the Babel of CSS, it allows using the latest CSS syntax in the codebase and transforms it during the build process for compatibility with browsers that don't support it. The combination of Tailwind and PostCSS is commonly used.

I've used both Styled-components and Tailwind in production. Both have pros and cons. Both aim to modularize CSS within JavaScript components, but their methods differ slightly. To put it briefly, the downsides are that Styled-components leads to too many components, while Tailwind results in very long class attributes. Review them and choose the tool that suits your team's preference.

Storybook

No need for a separate category here; it's still unparalleled. Storybook is such a useful tool that it can be considered a blessing for FE developers. Instead of needing to start a server and navigate to test components every time, you can easily open isolated components and perform various visual checks. It's useful both when developing individual components and when viewing developed components comprehensively. You can also integrate Storybook with E2E testing tools like Cypress to run component tests.

It's useful not only for FE developers but also for sharing completed components with planners or designers and exchanging feedback. Especially for projects adopting a design system, Storybook is a tool positioned at both the beginning and the end of the process.

However, being a rather heavy tool, it often conflicts with internal environment dependencies. Updating something can cause it to fail. Still, it has become much more flexible compared to the past. You can even change the internal bundler now. I expect it to continue improving. Recently, when integrating it with swc, I was worried, but the setup was completed faster than expected.

Conclusion

As outlined, the tools for configuring an FE project's development environment are numerous, with many alternatives for each type. Useful tools will likely continue to emerge, perhaps even new categories of tools. The emergence of better tools or improvements in existing ones always leads to much deliberation when starting a new project. We need to accommodate diverse team opinions for each category to establish the right development environment suited for the team and the project.

♥ Support writer ♥
with kakaopay

Creative Commons LicenseThis work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.

shiren • © 2025Sungho Kim