In this article, I’ll try to summarize some of the things that seem to be required to launch a web app (presumably in a business context) these days. I cannot give you any guarantee on completeness, so if you see anything missing from the lists below (or have some suggestions) please use the comments.

The list is structured by using different categories for the various bullet points. Inside the categories, two groups of items are used — either they seem to be required or are just recommended from my personal point of view. The classification may be different from your point of view.

Furthermore, I tried to explain my thought process reasoning for the category (specifically, why I think its items should be considered) in the beginning and added one example as illustration.

Preparation

Before even implementing a web app, you need to think about some organizational and non-technical aspects. If the web app is developed in a team or should help to sustain a business the following list seems reasonable.

An open-source web app follows a similar pattern, even though things like backers and community acceptance are less predictable and in a slightly different ballpark.

Required

Team agreed on technology set

Licenses, cost of infrastructure etc. covered

Operating model (including SLAs) determined

Business plan worked out

Recommended

List of supported browsers is available

Example

A list of supported browsers can be specified as simple as a Browserlist rule set, e.g., “last 2 versions, IE 10”. The great thing is that this rule set can be just added to the package.json of our web app and will be picked up automatically.

The addition can be as simple as:

Several tools exist, e.g., to export the rule set to a list of matching browsers.

Infrastructure

Infrastructure has never been sexy, but it’s always necessary. You may have noticed that infrastructure complexity in a cloud-first, fully automated setup has increased. Unsurprisingly, so did the tooling. Having the right tooling makes infrastructure not only manageable but also fun and efficient.

Besides a state of the art CI/CD pipeline, we should definitely incorporate full error tracking. In the end, knowing what breaks and why is crucial for improving the web app. Being able to roll out changes rapidly helps us to become less vulnerable.

Required

Build process fully automated

Error reporting (e.g., LogRocket) included

Data backup is in place and securely stored

Recommended

Terraform (or similar) scripts available?

Scalability determined

Static resources are hosted on a CDN

Example

To include advanced error reporting we usually only need to include a script and call an init function. Sometimes more sophisticated configuration (e.g., providing user-specific metadata) is useful, however, the crucial part of the job is already handled by just calling the init function.

As an example, we look at LogRocket:

{ "browserslist" : [ "last 2 versions" , "IE 10" ] }

This is pretty much it! The rest is a (custom) mix of using the official tools to access the gathered data and the API for integration in our own tooling.

Technical Foundation

Obviously, having a solid architecture, sound business logic, and sufficient tests are required for any application to be considered stable and well-maintainable. Nevertheless, for web apps, some special rules apply.

Not only do we need to look for the smallest possible bundles of code and assets to serve (yet delivering a unique or even outstanding user experience), we also need to test our code against a variety of different browsers and screen sizes.

To make matters worse available APIs, ECMAScript specifications, and styling edge cases may be handled differently.

Required

End-to-end tests for all supported browsers available

Emitted JS is bundled and minified

Emitted CSS is bundled and minified

Emitted CSS is auto-prefixed

Recommended

Bundle structure encourages cache reuse

Emitted HTML is minified

All emitted resources can be cached (e.g., use hashed name)

Emitted HTML is minified

All emitted resources can be cached (e.g., use hashed name)

Example

How we end up from plain sources with a minified, polyfilled, intelligently split bundle that can be easily cached and contains all kinds of wanted features depends strongly on our technology set. Some frameworks already come with a bundler out of the box.

A quite generic, yet easy to understand solution is Parcel. It also works against the previously defined browserlist and is framework agnostic. Out of the box (pun intended), it delivers TypeScript support, polyfills, production (minified etc.) builds, as well as hot module reloading.

Using it is as simple as running:

import LogRocket from 'logrocket' ; LogRocket.init( 'YOUR_APP_ID' );

The default output directory is usually the wanted one (“dist”).

Accessibility and mobile

When developing a web app we face a multitude of different target platforms. A website may be consumed in a non-graphical form. A website may be consumed by large devices with very odd inputs (e.g., only being able to go forward, backward, and into) or very small screens.

Furthermore, a website may be consumed by a variety connection types — fast, slow, limited, unlimited, and so on. If our app is to be successful, we need to find a balance that allows for most users to have a great experience.

Required

A mobile-friendly view exists

Unnecessary resources are not downloaded

Recommended

PWA enhancements are included (e.g. advanced caching)

Include noscript section(s)

Optimize link texts, image descriptions, and tab orders

Verify the color palette and background to foreground color ratio

A printer-friendly view exists

Example

If we run, for example, Google Lighthouse on an SPA without any noscript element we will get a logical warning. Letting users know that the reason for not seeing anything (or not going beyond some loading spinner) can be found in missing JavaScript support is crucial for progressive web apps.

Google Lighthouse audit on a SPA without noscript.

Luckily, correcting this is as simple as adding a simple noscript message to the body such as:

Security

One of our primary concerns should be to create a secure and trustful app that does not offer any vulnerability neither to access sensitive data of our users nor entering our system.

This obviously starts with an encrypted connection but also includes a reliable authentication and authorization scheme, as well as proper validation for any input.

Ideally, regular penetration tests against our application are performed.

Required

No secrets, keys, or tokens are transmitted to the client

HTTPS is required and active for every call

Recommended

The HSTS header is used

Upload fields are protected by a virus scanner service

Place, e.g., rel="noopener" on external links

Example

Placing a noopener (or even nofollow ) relation on anchor tags is straightforward.

Privacy

Potentially, my background as a German (i.e., European) renders me especially sensitive to this topic, however, there is more to GDPR than just annoying “we use cookies” messages.

Understanding and valuing a user’s need for sufficient privacy and data protection is necessary to build a trustful environment.

Keep in mind that quite often the devil is not directly in our code, but in some component that we use for convenience.

Required

A privacy consent notification is displayed once

Links for imprint, data protection, and further legal information available

Includes information about tracking, third-party integrations, use of data, etc.

Recommended

Fine-grained control over used cookies and third-party integrations are possible

Example

A simple option for integrating a compliant cookie disclaimer is to use a handy plugin like Cookie Consent.

Performance

Web apps today are anything but lightweight. We need to transport scripts, styling, fonts, images, and potentially even audio or video. Complicated logic created for multi-target purposes with multimedia background will never be lightweight, however, that does not mean it has to be slow.

Using proper caching, lazy loading, and efficient bundle splitting can help. Only loading what the user needs and wants is desired.

Required

Lighthouse speed test (incl. different connection speeds) was conducted

Recommended

Use HTTP/2 for all resources

Pre-load secondary resources (via <link> )

) Place script as async at bottom

Example

Preloading resources can be crucial for smooth user experiences. As an example using the preload for our style and script we get (taken from MDN):

Place it in the head before any of the mentioned resources appear. Depending on the position in the document the effect may be rather small, however, especially for resources loaded via JavaScript the effect can be pretty drastic.

Web analytics

Personally, I always have strong doubts about this one. Nevertheless, we need to learn from the (average) user somehow, hence the need for some anonymous tracking.

Even more significant may be the search ranking, which encourages us to follow some guidelines for search engine optimization.

Required

A meaningful robots.txt is provided

Recommended

Production tracking code supplied and right events tracked

Page transitions (SPA) tracked properly

Metadata (e.g. user properties) set up correctly

Example

Providing a correct robots.txt can be as simple as supplying the following text file (served with text/plain as content-type ) in the root directory:

This file will allow any robot (e.g., the Google search crawler) to access (i.e., index) all files. Additionally, we could place rules to disallow certain files or whole directories if wanted.

Fancy additions

Fancy additions give our app the extra touch that is needed to hook ordinary customers and fascinate tech-savvy people. They may appear in various forms, e.g., keyboard shortcuts, fancy loading spinners, useful recommendations, etc. These additions show that we actually care about our app and try to go the extra mile to make it super enjoyable.

Required

(none)

Recommended

In-app tutorials and useful help messages

Keyboard shortcuts

Example

Things like QuestionMark.js are easy to set up yet give pro users even faster input possibilities.

QuestionMark.js integrated help dialog.

Conclusion

As mentioned already the given list does not try to be complete. It should rather be understood as a guideline to think in the right direction. Being prepared for the legal challenges, and potential problems is at least as crucial as having a sound and useful web app out there.

These links contain audits and checklists that are more complete and interactive. They certainly provide helpful checks to form a solid technical basis.

plug

LogRocket: Full visibility into your web apps LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store. In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps. Try it for free.