Content uploaded by Joel Hassan
Author content
All content in this area was uploaded by Joel Hassan on May 04, 2024
Content may be subject to copyright.
The Effects of Architectural Design
Decisions on Framework Adoption: A
Comparative Evaluation of
Meta-Frameworks in Modern Web
Development
Joel Hassan Noor
Computer, Communication and Information Sciences (CCIS)
Thesis submitted for examination for the degree of Master of
Science in Technology.
Espoo 23.04.2024
Thesis supervisor:
Senior University Lecturer Arto Hellas
Thesis advisor:
Doctoral Researcher Juho Vepsäläinen
aalto university
school of science
abstract of the
master’s thesis
Author: Joel Hassan Noor
Title:
The Effects of Architectural Design Decisions on Framework Adoption: A
Comparative Evaluation of Meta-Frameworks in Modern Web
Development
Date: 23.04.2024 Language: English Number of pages: 6+83
Supervisor: Senior University Lecturer Arto Hellas
Advisor: Doctoral Researcher Juho Vepsäläinen
The rise of JavaScript meta-frameworks has transformed the development of web ap-
plications in recent years. Alongside established frameworks, such as Next.js, more
recent entrants, such as Astro and Qwik City have introduced novel approaches cen-
tred on simplifying developer experience and improving the perceived performance
of applications for users. The competitive nature of the meta-framework space and
the long-term impact of framework choice on projects calls for an understanding of
the factors that drive framework adoption.
This research first delineates extensibility, ease of migration and updates as a set
of adoption factors based on prior research and their relevance to modern meta-
frameworks. The factors form a basis of evaluating three meta-frameworks—Next.js,
Astro, and Qwik City—selected based on their popularity, design, and phase on
the innovation curve. A developer survey is conducted to complement the analysis,
gathering insights from developers on the value they associate with architectural
aspects and their personal experiences with the selected frameworks.
The findings substantiate previous research that identified learnability and exten-
sibility as primary adoption drivers. The main risks driving unadoption involve
complexity associated with a high degree of configurability and the perceived frame-
work lock-in due to an abundance of framework-specific concepts. Despite shared
authoring experiences across evaluated meta-frameworks, the analysis indicates
that newer frameworks are showing potential to considerably enhance user and
developer experiences by focusing on a simplified authoring experience, addressing
issues related to the transmission of application logic from the server to the client
and providing more fine-grained approaches to managing client-side JavaScript.
Keywords:
Adoption, Architecture, Astro, JavaScript, Meta-frameworks, Next.js,
Performance, Qwik, Qwik City, React.js, Rendering, UI frameworks,
Web Applications, www
iii
Preface
I am deeply grateful to Doctoral Researcher Juho Vepsäläinen and Senior University
Lecturer Arto Hellas for offering me the opportunity to conduct this research and
providing invaluable guidance and support throughout the process. I also express
my appreciation to all the individuals who generously volunteered their time to
participate in the survey. Finally, I thank my wife for the continuous encouragement
and patience she graced me with throughout this research and the rest of my studies.
Otaniemi, April 5th, 2024
Joel Hassan Noor
iv
Contents
Abstract ii
Preface iii
Contents iv
Abbreviations vi
1 Introduction 1
1.1 The emergence of client-side rendering and single page applications . 1
1.2 Meta-frameworks and the rise of isomorphic javascript applications . 2
1.3 Related work ............................... 3
1.4 Research questions and scope ...................... 4
1.5 Structure of the thesis .......................... 4
2 Research material and methods 5
2.1 Literature review of research on JavaScript framework adoption . . . 5
2.2 Subjectively evaluated factors ...................... 7
2.2.1 Extensibility ............................ 8
2.2.2 Ease of migration ......................... 11
2.2.3 Updates .............................. 12
2.3 Survey ................................... 13
2.3.1 Design ............................... 14
2.3.2 Analysis .............................. 15
3 Comparison 16
3.1 Next.js ................................... 16
3.1.1 Architectural overview ...................... 16
3.1.2 Extensibility ............................ 18
3.1.3 Ease of migration ......................... 23
3.1.4 Updates .............................. 24
3.2 Astro .................................... 27
3.2.1 Architectural overview ...................... 27
3.2.2 Extensibility ............................ 29
3.2.3 Ease of migration ......................... 34
3.2.4 Updates .............................. 36
3.3 Qwik City ................................. 39
3.3.1 Architectural overview ...................... 40
3.3.2 Extensibility ............................ 42
3.3.3 Ease of migration ......................... 45
3.3.4 Updates .............................. 46
3.4 Summary ................................. 48
3.4.1 Key differences .......................... 48
3.4.2 Extensibility ............................ 49
v
3.4.3 Ease of migration ......................... 49
3.4.4 Updates .............................. 50
4 Survey results 51
4.1 Respondent profile ............................ 51
4.2 Extensibility ................................ 51
4.3 Ease of migration ............................. 52
4.4 Updates .................................. 53
4.5 Meta-frameworks ............................. 55
4.5.1 Next.js ............................... 55
4.5.2 Astro ................................ 57
4.5.3 Qwik City ............................. 57
4.6 Ranking of adoption factors ....................... 57
4.7 Summary ................................. 59
5 Discussion 61
5.1 Meta-frameworks share foundations and features ............ 61
5.2 Extensibility drives adaptability ..................... 61
5.3
Innovation should be balanced with developer experience for widespread
adoption .................................. 62
5.4 Configurability runs the risk of excess complexity ........... 62
5.5 Concerns of perceived framework lock-in need addressing ....... 63
5.6 Learnability is supported by prioritising web fundamentals ...... 63
5.7 Stability and communication are essential in change management . . 63
5.8 Limitations ................................ 64
5.8.1 Subjective comparison ...................... 64
5.8.2 Survey reliability and validity .................. 65
6 Conclusion 67
References 69
A Appendix 76
vi
Abbreviations
API Application Programming Interface
CLI Command-Line Interface
CSR Client-Side Rendering
CSS Cascading Style Sheets
DSL Domain Specific Language
DX Developer Experience
FCP First Contentful Paint
HTML HyperText Markup Language
HTTP HyperText Transfer Protocol
IDE Integrated Development Environment
ISR Incremental Static Regeneration
JSON JavaScript Object Notation
LCP Largest Contentful Paint
MPA Multi Page Application
RSC React Server Components
SEO Search Engine Optimisation
SPA Single Page Application
SSG Static Site Generation
SSR Server-Side Rendering
TTFB Time to First Byte
TTI Time to Interactive
UX User Experience
WWW World Wide Web
1
1 Introduction
1.1
The emergence of client-side rendering and single page
applications
In the traditional client-server model for web sites and applications, servers generate
and serve HTML in response to client requests, which clients then render for users
[
32
]. This paradigm, known as Server-Side Rendering (SSR), prevailed throughout
the web’s history when static content dominated, and browser capabilities were
limited. The web applications built on this models are referred to as Multi-Page
Applications (MPAs) [79].
As interactivity demands grew and browser capabilities advanced, the web devel-
opment industry shifted towards Client-Side Rendering (CSR) in the late 1990s and
early 2000s [
39
], with Flash
1
technology gaining significant popularity [
87
]. The con-
tinued development of open web standards, particularly the advent of Asynchronous
JavaScript and XML (AJAX), eventually rendered many of Flash’s benefits obsolete
[
40
]. It also paved the path for a new trend in the late 2000s and early 2010s: the
development of Single-Page Applications (SPAs).
With SPAs, instead of the client receiving ready, server-generated, HTML on
demand, it executes a JavaScript bundle to render a HTML tree and any associated
interactivity as the application is loaded. In contrast with traditional MPAs, SPAs
can update HTML views in response to data changes without performing a full page
refresh.
The transition to CSR applications was accelerated by the advent of various
JavaScript UI frameworks2, such as Angular, React.js, and Vue.js.
These UI frameworks streamlined application development by offering templates,
structure conventions, and reducing manual Document Object Model (DOM)
3
manip-
ulation. Moreover, the frameworks or their ecosystems typically include built-in tools
and libraries for common tasks like routing, state management, and data fetching,
enhancing developer productivity and efficiency. Common characteristics among
popular UI frameworks include component-oriented architecture, markup templating
solutions, and reliance on client-side hydration for loading application interactivity
[78].
While CSR streamlined the development of highly interactive applications, it
also presented drawbacks that have led to renewed interest in Server-Side Rendering
(SSR) within the JavaScript ecosystem. Specifically, purely client-rendered sites and
applications have faced challenges with Search Engine Optimisation (SEO)
4
[
41
,
44
].
1
Flash is a now-deprecated multimedia software platform developed by Adobe, used to create
animations and applications using text and graphics.
2
UI frameworks are also commonly referred to as libraries. Although the terms are often used
interchangeably, frameworks can be defined as tools that invoke application code, whereas libraries
are invoked within application code [33].
3The DOM is a data representation of the objects comprising a website or application.
4
SEO involves building websites and applications to make them recognisable and understandable
by search engines, thus increasing the likelihood of users finding the service in response to search
queries.
2
This is because the indexing of sites by Google’s web crawlers has historically relied
on server-rendered HTML, whereas client-side rendered sites generate content at
runtime through JavaScript.
Additionally, CSR can result in poor perceived performance for users, particularly
on application start-up as its JavaScript needs to be loaded and executed for it to be
ready to use. This challenge becomes more pronounced as the application grows in
size unless carefully mitigated through optimisation techniques [49].
1.2
Meta-frameworks and the rise of isomorphic javascript
applications
Meta-frameworks, or rendering frameworks, augment the capabilities of existing UI
frameworks, simplifying the addition of server-rendering capabilities to applications.
A primary objective of meta-frameworks has been to combine the advantages of
both MPAs and SPAs by leveraging the same JavaScript code on the server and the
client, a concept referred to as universal or isomorphic JavaScript [
41
]. The initial
page is server-rendered ensuring faster initial content load times and subsequent
user interactions are handled via client-side JavaScript to provide an application-like
experience for end users.
The increasing popularity and widespread adoption of meta-frameworks have led
to a proliferation of options in the market. According to the latest Stack Overflow
survey from 2023, meta-frameworks constitute over a fifth of total web framework
usage [
59
]. The 2022 State of JavaScript survey, on the other hand, shows steady
year-on-year usage growth of the most popular meta-frameworks. For instance, the
usage of Next.js has grown from 9.8% to 44.9% between the years 2018 and 2022
[
31
]. As the number and usage of meta-frameworks continue to rise, developers
confront a dilemma similar to choosing a UI framework: determining the most
suitable meta-framework for a given project.
Given the potential impact of choosing a meta-framework on various project
aspects, such as development time, scalability, performance, and long-term main-
tainability, it becomes crucial to understand the factors that influence framework
adoption. Ultimately, the aim in many product and consultancy companies is to
meet user or customer requirements as cost-efficiently as possible with time spent
often being the most considerable expense [51].
Understanding adoption factors enables developers to make more informed deci-
sions when selecting the meta-framework that best aligns with their project’s needs
and objectives. Effectively, it helps developers navigate the “jungle of JavaScript
frameworks” [
30
]. Conversely, framework authors can use this knowledge to cre-
ate solutions that are more likely to meet developer requirements and preferences,
ultimately leading to higher adoption rates.
3
1.3 Related work
As JavaScript has risen to become the world’s most popular programming language
[
69
,
42
], recent research has started to explore modern JavaScript web frameworks and
their adoption factors. However, many of these studies have primarily concentrated
on technical aspects, such as performance [
54
,
29
,
45
,
50
,
26
], while largely neglecting
more subjective factors that relate to developer preferences and experience [60].
For instance, a study from 2012 [
29
] conducted a comparative evaluation of popular
JavaScript framework’s of the day, such as Dojo, JQuery and MooTools. The study
found differences between the frameworks concerning their quality, performance and
validation tests through the use of measurements such as lines of code, maintainability
and overall complexity. A later study extended these factors by proposing an
evaluation model, which also includes documentation, community and pragmatics
[30].
A later qualitative interpretive study [
61
] sought to arrive at a holistic under-
standing of adoption factors, instead of using pre-defined technical metrics that
the authors saw as having little use for practitioners. The implications regarding
adoption factors presented by the study spanned several behavioural constructs,
ranging from performance to learnability and community responsiveness — these
implications will be further explored in 2.1.
Another survey study conducted in 2021 [24] on UI framework adoption factors
sought to extend earlier work on the subject [
61
] in response to developments in
the web development scene, such as the growing popularity of a new breed of
frameworks, including React.js, Vue.js and Angular. The study found overlap in the
adoption factors that surfaced in earlier research [
61
], while identifying additional
ones, including architecture and expertise.
A further separate study [
51
] substantiated the findings of the previously men-
tioned research, revealing that non-technical factors, particularly popularity, com-
munity, and learnability, were considered more critical than technical factors by the
interviewed developers. Among the technical factors, maintainability was the most
frequently mentioned alongside complexity, security, and performance.
Researchers have emphasised the need for further research into adoption factors
identified in previous research [
61
,
51
,
7
]. Additionally, researchers have expressed an
interest in exploring and documenting key design and architectural patterns employed
by framework architectures [
24
]. Also, no research so far has specifically explored the
adoption factors related to JavaScript meta-frameworks. This study aims to address
this research gap.
4
1.4 Research questions and scope
This thesis addresses the research gap introduced in the preceding section by further
investigating how the architectural differences of modern meta-frameworks affect their
adoption. The aim is to understand how these frameworks differ in their architecture,
how those differences affect key technical adoption factors, and the relative value that
developers working with the frameworks place on each of the factors. The research
questions explored in this study are the following:
RQ1:
What are the key architectural factors that influence developers’
adoption of JavaScript meta-frameworks?
RQ2:
In what ways do the architectures of JavaScript meta-frameworks
differ in terms of these factors?
RQ3:
How do developers perceive the relative importance of these factors?
The study answers these questions by assessing adoption factors concerning
JavaScript meta-frameworks through the focus lens of Astro, Next.js, and Qwik
City. The study is scoped to these frameworks due to their relative popularity
[
76
,
31
] and the fact that they are all open sourced. While these meta-frameworks
share commonalities, they also showcase fundamentally distinct approaches to web
application development and are at different stages in their adoption and maturity
life cycles.
Moreover, these selected meta-frameworks can be classified through the per-
spective of innovation diffusion [
56
]
5
. In this context, Next.js can be regarded as
being adopted by early and late majorities as it is the most widely used and ma-
ture framework out of the three [
84
]. Astro seems to have witnessed substantial
growth, particularly among early adopters. The emerging Qwik City proposes a
novel and innovative paradigm, which likely draws attraction from early adopters
and innovators.
While the study concentrates on JavaScript meta-frameworks, examining the
motives and priorities of developers within this domain can provide valuable insights
applicable to the adoption of other web technologies.
1.5 Structure of the thesis
Section 2presents the architectural adoption factors that will form the basis for
the evaluation, and outlines how the comparison and the developer survey will be
conducted. The results of the subjective comparison are presented in Section 3and
the survey results in Section 4, both of which are subsequently discussed in Section
5. Lastly, conclusions and suggestions for further research are laid out in Section 6.
5
Diffusion of Innovation is a sociological theory that aims to explain how, why, and at what rate
new ideas, technologies, or practices spread [56].
5
2 Research material and methods
In the following subsection, existing research on JavaScript framework adoption
factors is reviewed to address RQ1, What are the key architectural factors that
influence developers’ adoption of JavaScript meta-frameworks?. The review will
inform the selection of key architectural adoption factors that will form the basis of
comparison for three selected meta-frameworks: Next.js, Astro and Qwik City.
Each factor will be described and quantified. The factors will form the basis for
the subjective comparison of the meta-frameworks, which seeks to answer RQ2, In
what ways do the architectures of JavaScript meta-frameworks differ in terms of these
factors?. The subjective comparison will also contribute to answering RQ3: How
do developers perceive the relative importance of these factors?. Finally, a developer
survey designed to contribute to answering the first and third research questions is
also presented.
2.1
Literature review of research on JavaScript framework
adoption
Section 1.3 introduced research studies related to adoption factors in the context
of JavaScript frameworks. The first of these studies [
61
] was a survey conducted in
2014 that looked at both technical and non-technical adoption factors to derive a
set of practical implications for both framework authors and decision-makers. The
categorisation of the factors was based on the Unified Theory of Acceptance and Use of
Technology (UTAUT) [
77
]
6
. The desirable attributes of JavaScript frameworks were
grouped into the five areas of the UTAUT model, namely performance expectancy,
effort expectancy, social influence, facilitating conditions and price value. The study
further grouped the coded survey responses into subcategories for each one of the
original categories specified by UTAUT.
Facilitating conditions are of particular relevance in exploring JavaScript meta-
frameworks from the perspective of architectural adoption factors. These were defined
as “the degree to which an individual believes that an organisational and technical
infrastructure exists to support the use of the system” [
77
]. The definition has
been contextualised to JavaScript frameworks by defining these conditions as the
characteristics that suit current requirements and provide integration potential [
61
].
Table 1lists the study’s implications relating to architectural factors.
6
UTAUT is a framework for understanding and predicting how people adopt and use technology
[77].
6
Table 1: Implications for architectural factors derived from [61].
Category Implication
Performance Expectancy The number of lines of code of the applications
created by means of the framework should be as
low as possible.
A framework should enable the development of
clear code.
Effort Expectancy The code that implements a framework should be
easy to read and understand.
A framework should enable the development of
clear code.
Suitability Simple tasks such as event handling, DOM
manipulation, and real-time component updates
should be automatised.
Applications created through a framework should
run in different browsers.
Modularity A framework should be modular; changing a
module should not affect others.
Libraries that come with a framework should
enable the achievement of basic and advanced
functionalities at any development stage.
Extensibility A framework should allow external libraries to be
imported without having to adapt them.
A framework should enable the development of
clear code.
A more recent survey study [
24
] conducted in 2021 researched both JavaScript
framework adoption and unadoption factors, to validate and expand upon the earlier
study [
61
]. The study found substantial overlap with the factors identified in earlier
research and revealed that architecture was a crucial factor influencing framework
adoption. A suboptimal architecture, in contrast, was one of the primary reasons for
migrating away from a framework. The interviewed respondents also noted specific
factors that they considered strengths and weaknesses in the frameworks they had
worked with. Table 2provides a list of these factors.
7
Table 2: List of strength and weakness adoption factors related to JavaScript front-
end frameworks ordered by the number of mentions by respondents [24].
Strength Factors Weakness Factors
Popularity Incompatibility of versions
Learnability Complexity
Architecture Suboptimal architecture
Expertise Lack of experts
Community Difficult to maintain
Performance Lack of TypeScript Support
To gain experience Poor performance
Documentation Security issues
Sponsorship
A closer look at the survey responses [
24
] enables more specific factors to be
distilled. In the context of maintainability, the readability of the code written with a
framework was particularly influential as an adoption factor. Similarly, respondents
described the struggles associated with working with monolithic codebases, especially
in the context of migration efforts [
24
]. Although perceived complexity can be
subjective, codebases that spread logic across several places were seen to cause
complexity. In addition, composability, reusability and a small API surface were
seen as positive characteristics of frameworks.
A separate study [
51
] into JavaScript framework adoption factors also found that
non-technical factors, including the popularity and maturity of the frameworks, took
precedence over technical factors for the surveyed developers. Of the technical factors,
maintainability was deemed most important, along with performance, security, degree
of complexity and the availability of integrations.
Moreover, a study involving a literature review and a survey of 47 software practi-
tioners concluded that the most important qualities in a JavaScript framework were
(1) Documentation (2) Ease of use (3) Updated (4) Community. Particular emphasis
was placed on the quality, accessibility, and comprehensiveness of documentation.
Ease of use was evaluated based on the framework’s learnability and maintainability,
while an updated framework was defined as one that undergoes continuous mainte-
nance through regular updates. Lastly, the community of a framework was assessed
by its popularity, size, and level of activity.
2.2 Subjectively evaluated factors
This section draws upon the preceding literature review and preliminary research
into JavaScript meta-frameworks to deduce adoption factors relating to architectural
8
design decisions. These factors will serve as the foundation for the forthcoming
comparison in Section 3. The factors chosen for evaluation in this study are: 1. Ex-
tensibility 2. Ease of migration 3. Updates.
These factors were chosen because they cover many technical aspects identified in
previous research and have implications for non-technical facets. Table 3summarises
the evaluated factors and lists their corresponding subfactors.
Table 3: Evaluation factors and subfactors
Factor Description Subfactors
Extensibility The effort involved in
accommodating changes in
application requirements.
Rendering Strategies,
Ecosystem, Integrations
Ease of
Migration
The effort involved in moving
parts or the entirety of an
application to or from another
framework or environment.
Framework-specific concepts,
Cross-framework component
support, Deployment and
Hosting Options,
Micro-frontend Support, Web
Platform Divergence
Updates The degree to which a
framework receives continual
updates in alignment with
changes in technologies and
trends.
Release Cadence and Nature,
Stability, Ease of contribution
Although the development of open-source meta-frameworks relies heavily on
community contributions to the framework and its ecosystem, the factors evaluated
in this study will primarily concern the architecture of application code generated with
the meta-frameworks and the APIs they provide, not the code of the meta-frameworks
themselves.
The reason for focusing on application code is based on the assumption that the
significant majority of framework users are more concerned with working with a
framework compared with working on the framework — the assumption is supported
by the fact that the ratio of contributors to users in frameworks is low. In addition,
most of the implications that surfaced in the literature review pertain to application
code, not framework code. The following subsection contains a detailed discussion of
the three evaluated factors outlined in Table 3.
2.2.1 Extensibility
Definition Software application requirements typically evolve considerably during
a project’s lifetime in response to changes in user and developer needs, and the
availability of new technologies and patterns. Given the unforeseeable direction of
9
changes and the decentralised nature of requirements engineering process [
36
], one
of the key design goals for software architecture is to be designed and engineered
to accommodate for variability in requirements [
11
] and to be adaptable to meet
any future changes in demand or scale [
61
]. Consequently, extensibility has been
described as the holy grail of system design [13].
Aspects of extensibility Extensibility is an ambiguous concept, which is also
influenced by subjective factors, including those relating to subjective developer
preferences. Established measures, such as size, complexity, and maintainability have
been employed to quantify the technical state of codebases [
29
]. Perceived perfor-
mance, which also impacts extensibility, can be evaluated, for example, through Core
Web Vitals [
46
]. Web Vitals, initiated by Google, are user-centric performance metrics
used for understanding and improving the experience of websites and applications
[85].
However, more subjective factors also impact extensibility. For instance, the
patterns and conventions used by a given framework may more closely align with
the preferences and mental models of one developer over another, thus creating
a discrepancy in the perceived complexity and, by extension, extensibility of the
framework. Also, prior experiences with the framework or its philosophies may be a
key driver in adoption [51].
Modularity and integrations There are some general aspects to frameworks
and, by extension, meta-frameworks that may facilitate or hinder extensibility as
highlighted in Section 2.1. One such aspect is the modularity of the architec-
ture, characterised by its ability to support integrations through the plug-and-play
characteristics it exhibits [
13
]. For JavaScript meta-frameworks, this includes the
integrability of custom or third-party tools to the framework or the application code.
The integrability of Open Source Software (OSS) is particularly important since
virtually all websites and applications rely on third-party scripts, libraries and
packages, often downloaded from Content Delivery Networks (CDN)
7
or from popular
package repositories, such as npm. Further, developers would also rather be able
to integrate existing libraries per their needs without having to modify them as
implied in Table 1. It can be laborious and costly to modify source code written by
other developers while simultaneously dealing with the constraints of the framework
used. As such, a higher degree of extensibility reduces costs and shortens the time
to market during feature development [11].
Flexibility The degree of flexibility afforded by a meta-framework should be bal-
anced with complexity concerns as highlighted by developer concerns over complexity
in Section 2.1. The meta-framework should be extensible enough to cover a broad
range of use cases without sacrificing ease of use and learnability [
24
]. A philosophy
7
CDNs are geographically distributed groups of servers, which cache content close to end users
[8].
10
of convention over configuration
8
should be flexible without being too restrictive or
encouraging excessive lock-in.
Other possible anti-patterns for flexibility include over-reliance on plugins which
increases the fragility of a system, particularly if the integrations are not well
maintained. However, bundling too much functionality into a framework to cover a
wide range of potential scenarios may lead to perceptions of complexity or framework
lock-in.
Assessing extensibility In assessing extensibility, the focus is on the factors
believed to most likely impact the ability of developers to solve common problems
relating to extensibility. As listed in Table 3, these include the rendering strategies
provided by the framework, its ecosystem of tools and libraries, and the possibility
to add integrations.
The choice of rendering strategies impacts the performance of applications, par-
ticularly at scale, and their ability to support different categories of web applications,
or holotypes9.
We will be exploring the support of the meta-frameworks for the following:
•
Static Site Generation (SSG) is the process of generating static HTML
pages during build time. These pre-generated pages are then served directly to
users upon request [16].
•
Server-Side Rendering (SSR) is a technique where HTML pages are gener-
ated on the server in response to client requests. The generated HTML and
any required data is then sent to the client for display [32].
•
Client-Side Rendering (CSR) involves rendering HTML pages directly in
the user’s browser using JavaScript. In this case, the server primarily serves
the initial JavaScript, CSS, and minimal HTML, while subsequent rendering
and data manipulation occurs on the client [32].
•Hybrid rendering (SSG & SSR): This approach combines both SSG and
SSS techniques. Some pages are pre-generated during build time (SSG) while
others are generated on-demand on the server (SSR).
•
Server-fetched data revalidation: This refers to validating cached data
on the server to ensure it is still up-to-date and accurate. Stale data may be
updated or re-fetched from the original source.
•
Incremental data streaming: Incremental data streaming involves sending
HTML in small, incremental chunks from the server to the client as it becomes
8
Convention over configuration is a software design paradigm used by software frameworks that
attempts to decrease the number of decisions that a developer using the framework is required to
make without necessarily losing flexibility and “don’t repeat yourself” (DRY) principles [88].
9
Holotypes, such as storefronts or social media applications, are rough classifications of ap-
plications based on common features and constraints to facilitate architectural decision making
[48]
11
available, rather than waiting for the entire HTML document to be ready before
sending it to the client10.
The ecosystem and integrations are fundamental aspects of framework extensibility
as 94% of websites [
91
] utilise third-party scripts and virtually all leverage custom
tooling and integrations, often in the form of open-source packages [
36
]. Some other
categories for third-party integrations include analytics, hosting, and CDN usage
[91].
2.2.2 Ease of migration
The migration of an application from one framework to another is a potential part
of a web application’s life cycle, especially for long-lived projects which may undergo
migration more than once. In one of the studies on adoption factors [
24
], one in four
developers had plans to migrate to another framework in the future and one in five
had either already completed a migration or were planning one.
Framework options and trends evolve at a fast pace as indicated by the latest State
of JavaScript and Stack Overflow surveys from 2022 and 2023, respectively [
31
,
59
].
As a consequence, teams that have adopted frameworks that were at yesterday’s
bleeding edge could find themselves in a situation wherein their framework of choice
does not support certain features available in other frameworks [
34
], is no longer
supported, or suffers from a lack of available experts [24].
Besides the ability to leverage new technologies and trends, subjective developer
experience in working with a framework plays a significant role when choosing to
migrate to or away from a framework [
24
]. As such, it’s crucial that developers are
not locked into whatever framework they initially choose, but can react to changing
requirements as needed [34].
In addition to inter-framework migrations, complex applications with numerous
third-party dependencies frequently require intra-framework version upgrades. As
well as providing access to the latest functionality offered by a framework, these
upgrades may be essential for non-feature improvements and fixes [68, 28].
Migration strategies Framework migration strategies can be broadly categorized
into single-step (big bang) and incremental (phased) approaches [
47
,
83
,
57
]. In single-
step migrations, the entire application is replaced instantaneously upon completion
of the new system, such as rewriting the whole UI with a new framework and
deploying it to production while decommissioning the old UI. On the other hand,
incremental migration involves breaking down the system into smaller components
and replacing them individually, allowing the old system to continue functioning
during the transition process. This approach can facilitate a smoother migration for
complex systems as problems are tackled piecemeal and disruption to the working of
the existing system is minimised.
10
Streaming can happen in two ways: in-order and out-of-order. In-order streaming sends HTML
in the sequence defined by the markup. With out-of-order streaming, HTML transmission and UI
rendering can commence even when resources used by the markup are unavailable. The order and
structure of the document are preserved in the client-rendered HTML [38].
12
Assessing ease of migration The support for incremental migrations is a key
factor that will be evaluated as they are generally favoured over single-step migrations
due to their flexibility and reduced risk [
57
,
83
]. Framework modularity, including
cross-framework component support, plays a crucial role in facilitating incremental
migrations, as it simplifies the process of migrating components across projects with-
out needing to change the meta-framework. Moreover, supporting micro-frontends
11
can be beneficial, as it allows each micro-frontend to be migrated independently,
offering further flexibility and efficiency during the migration process.
Another assessment criterion is the degree of divergence by the meta-framework
from the web as a platform. This can happen as a result of frameworks providing high-
level abstractions on top of standard web APIs or outright monkey patching
12
of them.
Although abstractions are one of the primary reasons developers use frameworks
[
61
,
24
], they also carry the risk of instilling framework-specific mental models and
ways of working that do not easily transfer beyond that framework. Consequently,
developers—especially those with less experience—may acquire in-depth knowledge
of a particular framework, which could impede their ability to transition efficiently
to alternative frameworks or framework-less development.
In addition to application logic, framework lock-in can also impact developers
during hosting and deployment, presenting several challenges. These include limited
compatibility with hosting providers, constraints on framework functionality when
deployed outside the default hosting environment, and reduced availability of tooling,
resources, and documentation for alternative platforms.
A crucial factor for migrations is the flexibility developers have in choosing
the environment where the framework-generated application code will run. Some
meta-frameworks are developed by companies offering their own managed hosting
solution as the default (or preferred) option for code written with the framework. A
framework with fewer proprietary components in its code and configuration enables
easier migration of an application between hosting or deployment environments.
2.2.3 Updates
Definition As indicated by research [
61
,
7
] reviewed in Section 2.1 and highlighted
in Table 1, a framework should be continually maintained and updated. A controlled
laboratory experiment [
28
] on the effects of software updates on the continuance
intentions of users categorised updates into feature and non-feature updates. Feature
updates involve modifications to the core software functionality through additions or
removals. Conversely, non-feature updates generally deliver technical enhancements
or address stability, security, or performance without altering the core functionality.
The study [
28
] found that feature updates correlated positively and significantly
with users’ intentions to continue using software, whereas non-feature updates had
no such effect. It also concluded that users prefer frequent and incremental updates
11
A micro-frontend architecture comprises multiple, independently deployable frontend applica-
tions combined at runtime, often divided along business service lines [25].
12
Monkeypatching is a technique used to dynamically update the behaviour of a piece of code at
run-time [89].
13
over larger ones that bundle changes together. The assumption that the frequency
and type of updates are important can be thus extended to meta-frameworks in
considering the impact of updates on adoption.
Conversely, large updates with breaking changes are a significant factor in frame-
work unadoption [
24
,
28
]. These updates often require substantial code rewrites,
which can be further complicated by inadequate documentation for new features
compared to existing ones. When the burden of these changes becomes too heavy,
developers may choose to switch to another framework with more manageable update
processes.
Assessing updates In addition to the frequency of updates, the nature of the
updates a framework receives will also be evaluated. Other factors that directly impact
the likelihood of update continuance will also be looked at, including popularity
and community size [
61
,
24
,
7
]. The growth in the number of downloads for each
framework will be used as a proxy for measuring both popularity and size.
Additionally, an evaluation of adherence to semantic versioning practices will
be conducted to assess how a framework manages breaking changes
13
. Although
commitment to semantic versioning can assist developers in assessing version com-
patibility, its taxonomy is limited as it classifies any given update into one of three
possible version categories [
43
]. This constraint makes it difficult for developers
to discern whether an update is relevant to their work based solely on the version
number, as the only indication they receive is the presence or absence of breaking
changes. Consequently, the framework’s communication about changes and the
availability of tools, such as update scripts, to manage updates will also be examined
to provide a more comprehensive understanding of how a framework handles updates
and supports developers in maintaining their projects over time.
Another factor to take into account is the external support a framework receives.
Frameworks supported by companies or organisations are more likely to survive
maintainer turnover than those without financial backing. Furthermore, a larger
number of contributors and a well-balanced distribution of maintenance work between
core and community contributors help minimise the risk of project stagnation.
2.3 Survey
This section outlines the design of a developer survey focusing on architectural
adoption factors in JavaScript meta-frameworks. First, the rationale behind the
survey design and content is explained, followed by a description of the data analysis
methods applied to the resulting data.
13
Semantic versioning, or semver, policy is a set of rules and requirements that dictate how
version numbers are assigned and incremented [
63
]. Version numbers in semantic versioning consist
of three parts in the form MAJOR.MINOR.PATCH. Each part denotes a different level of change
within the release. For instance, if version 2.0.0 exists, then version 3.0.0 would signify a major
release involving significant changes or new features.
14
2.3.1 Design
To help answer RQ3, How do developers perceive the relative importance of each
(adoption) factor?, a survey was designed consisting of both closed and open-ended
questions. The survey was estimated to take between five to ten minutes to complete,
allowing for a sufficient number of closed and open questions without being excessively
time-consuming for respondents. The Webropol survey and reporting platform
14
was
used for designing and distributing the survey, which can be found in its entirety in
Appendix 6.
The survey’s initial page focused on questions related to respondents’ professional
backgrounds to enable potential categorisation. The first question asked whether they
used JavaScript web frameworks, as a negative response would render subsequent
survey questions irrelevant. Respondents who did not use JavaScript web frameworks
were automatically directed to the survey’s final page where they were asked to
provide their reasons for not using frameworks.
The remainder of the survey comprised of questions grouped into sections that
corresponded with the architectural factors focused on in the study and discussed in
2.2. Namely, extensibility, ease of migration, and updates. Each section contained a
set of closed questions with at least one optional open-ended question at the end of
the section.
All the closed questions were marked as mandatory to answer, whereas the open-
ended questions were left optional to achieve a high survey response rate. Closed
questions gauging the subjective opinion of the respondent used a 4-point Likert
scale — neutral options were intentionally omitted to derive more meaningful data
points and to avoid statistical disturbances [52].
The majority of the closed questions gauged the degree of importance that the
respondent attached to a given factor and were framed as: “How important is X
to you”. The answer options were given on a scale ranging from a strong negation
to a strong affirmation, typically in the format: (1) Not important (2) Somewhat
important (3) Important (4) Very important. Some survey questions appeared
conditionally based on an answer to a previous question. For instance, a ‘no’ answer
to the question: “Do you use JavaScript web frameworks?” would show a further
question that asks the respondent to expand on their reasoning as to why they
answered no. Finally, the survey asked the participants whether they would be open
to further discussions on the topic or would like to be informed of the survey results
when done.
The chosen sampling method for the survey was convenience sampling, which
involved making the survey accessible to any developer who came across it in the
chosen distribution channels. In this case, the survey was distributed through a
public link on social media channels and online developer communities. The online
communities included the r/astrojs
15
and r/nextjs
16
subreddits, and the official Qwik
14https://webropol.com/. [Accessed 21-04-2024].
15https://www.reddit.com/r/astrojs/. [Accessed 21-04-2024].
16https://www.reddit.com/r/nextjs/. [Accessed 21-04-2024].
15
Discord channel. The survey was also shared in Koodikliniikka’s
17
Slack community
and by the thesis supervisor and author on LinkedIn.
Convenience sampling was chosen for this survey because it allowed for a quick
and easy way to reach many developers likely to have experience with JavaScript
web frameworks. Additionally, using popular online developer communities allowed
for a wider reach and potential to gather responses from developers with different
backgrounds and experiences.
2.3.2 Analysis
The survey data was analysed through descriptive and inferential statistical methods.
Insights from descriptive statistics are used to make sense of the responses to the
closed, Likert-scale questions. This includes extracting features such as answer
counts, averages, standard deviations, and correlations. Data insights provided by
the Webropol platform are also leveraged to draw inferences. Visualisations such as
bar charts are used to illustrate the results.
A thematic analysis was conducted for open-ended questions to identify common
themes and patterns in the responses [
12
]. Thematic analysis was chosen due to its
flexibility, ease of use and ability to produce unanticipated insights. The process
involved reviewing and coding the responses based on common themes and concepts.
Word frequency analysis across responses was also used to support the thematic
analysis.
Correlations between variables were explored to help identify relationships between
the answers on adoption factors. Potential limitations and biases of the data and
methods will be considered and presented in Section 6. Finally, a synthesis of the
analysis across all the survey questions is compared with the results of the subjective
comparisons, to look for both convergence and divergence on the identified adoption
factors.
17Koodikliniikka is Finland’s largest Slack community for software hobbyists and professionals.
16
3 Comparison
This section offers a detailed subjective comparison of popular JavaScript meta-
frameworks, namely Next.js, Remix, and Qwik City, based on the adoption factors
investigated in Section 2. Sections 3.1 to 3.3 provide in-depth analyses of individual
meta-frameworks, while Section 3.4 consolidates the key findings. Readers who prefer
a high-level overview of the comparison results can proceed directly to Section 3.4.
3.1 Next.js
Open-sourced in late 2016, Next.js is a React-based framework developed by Vercel
18
for building full-stack web applications [
82
]. The 2022 State of JavaScript survey
indicates that Next.js is the most well-known and widely used JavaScript meta-
framework [
76
]. Moreover, the most recent Stack Overflow survey from 2023 ranks
Next.js as the most admired and sought-after meta-framework among those listed
[59].
Next.js positions itself as the go-to React.js framework for web development,
enabling the creation of production-ready, full-stack web applications. It is the first
framework recommended in the React.js starter guide for building production-grade
apps [
73
]. Key features of Next.js include tooling for server and client rendering,
HTML streaming, route handlers, routing, Node.js and edge runtime integration,
and support for the latest React.js features.
3.1.1 Architectural overview
Project structure The command
create-next-app@14.0.0
allows a developer
to create a new Next.js project by prompting them with the following options:
1. Would you like to use TypeScript? (No/Yes)
2. Would you like to use ESLint? (No/Yes)
3. Would you like to use Tailwind CSS (No/Yes)
4. Would you like to use ‘src/‘ directory? (No/Yes)
5. Would you like to use App Router? (recommended) (No/Yes)
6. Would you like to customize the default import alias (@/*)? (No/Yes)
It is also possible to set up a project non-interactively by directly passing in a
set of options to the
create-next-app@14.0.0
command [
82
]. In particular, the
-e
options enable projects to be bootstrapped from existing starters and examples,
such as the ones available on the Next.js GitHub repository
19
. Opting for the default
selections results in the project structure shown in Listing 1.
18
Vercel, formerly known as Zeit and now.sh, is a cloud platform for deploying and hosting web
applications [81].
19https://github.com/vercel/next.js/tree/canary/examples. [Accessed 21-04-2024].
17
.
README.md
app
favicon.ico
globals.css
layout.tsx
page.tsx
next-env.d.ts
next.config.js
package-lock.json
package.json
postcss.config.js
public
next.svg
vercel.svg
tailwind.config.ts
tsconfig.json
Listing 1: The project structure of a Next.js application with default configuration
options selected.
The
app
directory is important as it defines routing, server-side data-fetching
logic, and rendering strategies for Next.js applications. It also includes components
used for shared layouts and error handling. Next.js utilises several configuration files,
including
next.config.*
for customising the build process and
tsconfig.json
for
TypeScript support. The
tailwind.config.*
and
postcss.config.*
files provide
out-of-the-box support for Tailwind CSS
20
. The
public
directory is used for storing
static assets such as images, fonts, and videos, which are processed by Next.js during
build time and served to the application.
Runtime architecture The runtime architecture of a Next.js application depends
on the features used and the hosting provider’s infrastructure. A statically exported
Next.js application can be deployed to any server that supports static assets, which
enables the entire application to be cacheable in a CDN [
82
]. However, if a Next.js
application leverages runtime server-side functionality, such as dynamic server compo-
nents, API handlers or middleware, a Node.js server is deployed with the application
to respond to server-side requests.
The execution environment for the Node.js server-side logic depends on the
hosting provider. Vercel, for example, deploys API route files as serverless functions,
whereas other providers, such as fly.io and Render, use Node.js servers.
20
Tailwind CSS is a CSS framework that provides pre-defined utility classes for styling directly
through HTML markup [86].
18
Regardless of the architecture decisions, a Next.js application needs to hydrate
on the client for interactivity — this involves sending a JavaScript bundle to the
client to be parsed and executed.
3.1.2 Extensibility
Ecosystem As the most popular JavaScript meta-framework [
59
,
31
], Next.js has
fostered an active ecosystem of third-party packages. The GitHub repository of
Next.js has been starred over 115,000 times and lists over 2,000,000 dependent projects
and over 9,000 dependent packages
21
with popular third-party OSS packages like
next-auth
and
next-seo
receiving weekly download counts of 730,000 and 400,000,
respectively
22
. As Next.js is built on top of React.js, client-side React components
should work in Next.js without modification, providing Next.js applications access
to the entire ecosystem of one the most popular UI libraries [71].
Rendering strategies Next.js provides two routing approaches for applications
that impact how components are rendered. The traditional
pages
router is a file-
system-based router where files directly represent routes. Components specified in
route files are rendered as client components by default. The
pages
router supports
client-side data fetching within regular React.js components, while build-time data
fetching and SSR happen on the file level through utility functions.
The
app
router introduced in version 13 supersedes the
pages
router [
55
]. The key
conceptual difference between the two is that the
app
router is built on top of React
Server Components (RSC)
23
and is thereby more server-oriented as components are
rendered server-side by default. It also supports nested routing, loading states and
error handling. The main difference in supported rendering strategies is that the
app
router supports HTML streaming as a feature of RSC as shown in Table 5.
The two routing methods exhibit more distinct differences in their syntax. As
app
router components are built upon RSCs, they enable static and dynamic data
fetching within the component. Conversely, components in the
pages
router rely on
getStaticProps
and
getServerSideProps
utility functions for data fetching. The
example snippets in Listing 2and Listing 3highlight the differences in how the two
approaches enable different data fetching approaches.
21
Data retrieved from
https://github.com/vercel/next.js/network/dependents
[Accessed
20-01-2024].
22Data retrieved from https://www.npmjs.com/ [Accessed 18-01-2024].
23
Server components are rendered exclusively on the server ahead of time and are excluded from
client-side JavaScript bundles [66].
19
// E.g. app/page.tsx.
export async function generateStaticParams() {
const params =data // build-time data
return params
}
export default async function Page({ data }) {
// This request should be cached until manually invalidated.
// Similar to `getStaticProps`.
// `force-cache`is the default and can be omitted.
const staticData =await fetch(`https://...`, { cache:'force-cache'})
// This request should be refetched on every request.
// Similar to `getServerSideProps`.
const dynamicData =await fetch(`https://...`, { cache:'no-store'})
// This request should be cached with a lifetime of 10 seconds.
// Similar to `getStaticProps`with the `revalidate`option.
const revalidatedData =await fetch(`https://...`, {
next:{ revalidate:10 },
})
// Returned JSX.
}
Listing 2: A contrived example illustrating how data can be fetched on a page level
using the
app
directory in Next.js. The
fetch
API is an adaptation of the native
Fetch API [
21
], and functions as a unified API for fetching static and dynamic data
on the server, both at application build and runtime.
20
// E.g. pages/page.js.
export async function getStaticPaths() {
const params =data // build-time
return {
paths:[{ params }],
}
}
// Only runs during build.
export async function getStaticProps() {
const staticData =await fetch(`https://.../posts`)
return {
props:{ staticData },
// Incremental static regeneration
revalidate:10,// Cached for 10 seconds.
}
}
// Only runs during runtime (SSR).
export async function getServerSideProps() {
const dynamicData =await fetch(`https://...`)
return { props:{ dynamicData } }
}
export default function Page({ data }) {
// Returned JSX.
}
Listing 3: A contrived example illustrating different ways to fetch data in a route
file using the
pages
directory in Next.js. In contrast with the
app
router approach,
Next.js provides dedicated
getStaticProps
and
getServerSideProps
functions for
fetching data at build time and runtime, respectively. With this approach, all server-
fetched data must be passed down to the
Page
component instead of being fetched
within the component itself.
The default behaviour for both approaches is for Next.js to pre-render UI compo-
nents and any data fetched to static HTML during build time [
82
]. The ability to
statically pre-render and dynamically generate components gives developers flexibility
in meeting application requirements. The default behaviour of statically generating
HTML particularly benefits mostly static applications that rely on the benefits that
static HTML yields, such as content-heavy sites or storefronts (application holotypes
were explored in 2.2.1). HTML can be stored and cached in a CDN at build time,
which enables the HTML to be shared between various clients, thus eliminating the
21
need for regeneration for each request[82].
Integrations Currently, the rudimentary plugin architecture in Next.js is managed
at the root level in the
next.config.*
file, which provides a set of customisation
options for various aspects of an application ranging from bundling and runtime
configurations to image optimisations [
82
]. The file is empty by default as Next.js
initialises the configuration to default values to enable developers to get up and
running without any manual configuration. Custom configurations are added and
modified through keys in the exported object of the file. For instance, setting up
internationalisation involves configuring the value for the
i8n
key in the file as shown
in Listing 4.
// next.config.js
module.exports ={
i18n:{
// Internationalisation configuration.
},
}
Listing 4: An illustration of how internationalisation is configured for a Next.js app
in the next.config.js file.
A common extension target is the module bundler to handle any needs not covered
by default, such as parsing unsupported file types. The
next.config.*
file affords
developers the ability to eject from the default Webpack configuration [
82
] by defining
a function for the key as shown in Listing 5.
module.exports ={
webpack:(
config,
{ buildId, dev, isServer, defaultLoaders, nextRuntime, webpack }
) => {
// Custom configuration.
return config
},
}
Listing 5: A code snippet demonstrating how to eject from the default Wepback
configuration in a Next.js application.
22
Some common Webpack plugins, such as
@next/mdx24
and
@next/bundle-analyzer25
are offered as plugins by Next.js that can be composed as shown in Listing 6.
// next.config.js.
const withPlugins =require('next-compose-plugins')
const withBundleAnalyzer =require('@next/bundle-analyzer')({
enabled:process.env.ANALYZE === 'true',
})
module.exports =withPlugins([
[withBundleAnalyzer],
// Other plugins are added here.
])
Listing 6: A code snippet showing how Next.js Webpack plugins can be composed in
anext.config.* file.
For loading third-party scripts, Next.js recommends their own built-in
Script
component [
82
] that can be loaded on specific pages or across the application. The
component provides multiple strategies for adjusting the rendering behaviour and has
recently added experimental support for offloading scripts to web workers to prevent
scripts from blocking the main thread. Opting out of the abstraction is at best
discouraged as regular script tags are unsupported metadata in Next.js [
82
], resulting
in an error if used as a child of an HTML head tag. From an extensibility perspective,
this can be troublesome as users have less granular control over their scripts, and
need to rely on the utility to function correctly and be thoroughly documented.
In addition to the
Script
utility, Next.js is also developing an experimental
@next/third-parties
package
26
— a collection of components to handle some of the
more common use cases, such as embedding YouTube videos or integrating Google
Tag Managers. As the functionality does not seem to replace the
Script
utility
but would be built on top of it, users would retain the ability to drop down an
abstraction level when needed. Discussions on the development of a more general
plugin architecture system have also been ongoing in the form of RFCs
27
with nothing
concrete in plans yet.
Next.js is also developing Turbopack — a proposed successor of Webpack that
enables incremental and adaptable bundling, and integrating it into the Next.js
framework [
82
]
28
. Although the proclaimed performance improvements could improve
24https://github.com/vercel/next.js/tree/canary/packages/next-mdx
. [Accessed
24-04-2024].
25https://github.com/vercel/next.js/tree/canary/packages/next-bundle-analyzer
.
[Accessed 24-04-2024].
26https://github.com/vercel/next.js/tree/canary/packages/third- parties#experim
ental-nextthird-parties. [Accessed 20-01-2024].
27https://github.com/vercel/next.js/discussions/9133. [Accessed 20-01-2024].
28
The readiness status of Turbopack can be followed at
https://areweturboyet.com/
[Accessed
27-04-2024], which shows the ratio of passing and failing tests for next dev and next build.
23
// next.config.*.
const withPreact =require('next-plugin-preact');
module.exports =withPreact({
/* Regular next.js config options are added here. */
});
Listing 7: An illustration of how Preact.js can be supported in Next.js through the
next.config.* file.
developer experience, especially as the application size grows, it may take a long
time for Turbopack to support all the various ways in which developers have been
configuring their Webpack options.
3.1.3 Ease of migration
Next.js is exclusively React-based, meaning it does not directly support other com-
ponents from other UI libraries. An exception to this before v12 was Preact.js
29
for
which compatibility was provided by a third-party
next-plugin-preact
library.
This enabled React.js to be swapped with Preact.js through the
next.config.*
configuration file as shown in Listing 7.
However, with the introduction of the app directory workflow in v13 of Next.js,
Preact.js compatibility seems to be broken
30,31
due to a mismatch in the React server
rendering implementation between Preact.js and Next.js. Consequently, migrating
Preact.js applications to Next.js or vice-versa has become more challenging.
Next.js is also incompatible with web components, at least out of the box
32
, and
they are not mentioned in the official documentation. As a client-side rendering
library, React.js itself supports the use of web components with some caveats
33
.
However, Next.js is primarily an SSR library and supporting web components is
not trivial as web components are primarily a browser technology [
23
]. Nonetheless,
efforts are ongoing to make web component libraries compatible with Next.js34.
Although components authored in Next.js are React components, they may
incorporate Next.js-specific components or functions for data fetching. For example,
Next.js provides a
Link
component for client-side view navigations and an Image
component for image optimisations. In addition, Next.js provides data fetching
functions, such as
getServerSideProps
, the results of which are passed into page
29Preact.js is a smaller alternative to React.js with an almost identical API [62].
30https://github.com/vercel/next.js/issues/42530. [Accessed 20-01-2024].
31https://github.com/preactjs/preact-render-to-string/pull/259
. [Accessed 20-01-
2024].
32https://github.com/vercel/next.js/discussions/49537. [Accessed 20-01-2024].
33
The caveats are mentioned in the old React.js documentation found at
https://legacy.rea
ctjs.org/docs/web-components.html. [Accessed 20-01-2024].
34https://lit.dev/docs/ssr/overview/. [Accessed 20-01-2024].
24
components. The use of these tools in any component means that their transfer to
other React environments is not possible without the conversion of any Next.js-specific
utilities to a compatible format.
Next.js applications can be self-hosted or deployed to a managed host [
82
]. The
Next.js documentation recommends Vercel as the fastest way to deploy an app,
while also providing a host of optimisations through its infrastructure, such as the
deployment of API routes and middleware as serverless cloud functions. With the
Build API, Next.js applications can also be self-hosted on any provider that supports
Node.js or Docker workflows.
Although all Next.js features are self-hostable according to Vercel, deploying
infrastructure components may differ from one hosting provider to another. For
example, when using Vercel, the API routes of a Next.js app are deployed as serverless
functions on AWS Lambda, and they can be configured to use Vercel’s edge runtime
as well. Any middleware is also automatically deployed on the edge. Further, Vercel
handles the infrastructure for optimising images without the developer needing to do
this manually via a CDN or otherwise. As there can be deployment and runtime
differences between providers, users migrating from one environment may run into
unexpected behaviour in another environment
35,36
. To address some of these issues,
projects such as OpenNext have been developed to offer a more uniform experience
when deploying Next.js to any Functions as a service (FAAS) platform37.
To support incremental migrations, the
next.config.*
file enables new or old
Next.js applications to be accessible through a sub-path to which a proxy server
can direct traffic to [
82
]. Rewrites are also configurable in the same
next.config.*
file for controlling request proxying and can also be used to create multi-zones [53],
whereby multiple, independently managed and deployed micro-frontends can be
mounted on the same host albeit with the caveat that JavaScript cannot be shared
between the different applications. However, Next.js uses Webpack for bundling
which makes using the more module federation feature of Webpack for micro-frontend
management a possibility through the module-federation/nextjs-mf plugin38.
3.1.4 Updates
Next.js currently releases updates through two channels: stable and canary
39
. Stable
updates are those made available to all Next.js users and the releases adhere to
semantic versioning. Canary updates, on the other hand, are used for phased update
rollouts and their installation requires explicitly appending the installation command
with @canary.
The changelog for all Next.js updates, including both stable and canary, is
35https://answers.netlify.com/t/next-js-serverless-function-crash-on-unknown-r
oute/94627. [Accessed 20-01-2024].
36https://community.fly.io/t/connect-external-vercel-nextjs-13-prisma-applicati
on-to-fly-io- postgres-with-ipv6/14524. [Accessed 20-01-2024].
37https://open-next.js.org/. [Accessed 20-01-2024].
38https://github.com/module-federation/universe/tree/main.[Accessed 27-04-2024].
39https://github.com/vercel/next.js/blob/9bb9f07e82357eeb4a15f9c1f5ecb21d600dd
433/contributing/repository/release-channels-publishing.md. [Accessed 27-04-2024].
25
available on GitHub
40
. The release notes summarise the changes in list form, as
well as providing credit to all contributors to the release in question. Alongside the
GitHub changelog, Next.js announces minor and major releases on its blog with
more explanatory and higher-level descriptions, placing the changes in the broader
context of the framework’s development [
82
]. The blog also contains content related
to updates, such as previewing new features and improvements and guides to help
migrate from one version to another.
Next.js has received updates on a regular cadence since its initial release. At the
time of writing, pre-releases are often made daily, with minor versions released every
couple of weeks as can be seen in Figure 1.
04/16
10/16
05/17
11/17
06/18
01/19
07/19
02/20
08/20
03/21
09/21
04/22
11/22
05/23
12/23
06/24
0
2
4
6
8
10
12
14
Release Date
Version Number
Major
Minor
Patch
Figure 1: Timeline of Next major, minor and patch releases starting from version
1.0.0
In addition to the release frequency, there are over 3,000 unique contributors to
Next.js. Figure 2breaks down the share of commits among the top contributors.
40https://github.com/vercel/next.js/releases. [Accessed 27-04-2024].
26
JJ (13.76%)
Tim (11.51%)
Joe (5.99%)
Jiachi (3.82%)
Tobias (3.30%)
Other Contributors (including bots) (61.62%)
Figure 2: Relative share of commits to Next.js by the top five contributors, excluding
bots. Data was retrieved on 14.01.2024 from the Next.js GitHub repository.
Further, the Next.js project, including its core team of developers, is funded by
Vercel
41
, providing impetus for the continuation of the project and thereby lessening
the risk of abandonment. Next.js is also officially endorsed by the React team
42
and
is the most popular React.js framework [
76
,
59
]. The download rates for Next.js have
been increasing fast, growing ∼54% during 2023 as shown by figure 3.
12/22
01/23
02/23
03/23
04/23
05/23
06/23
07/23
08/23
09/23
10/23
11/23
14 M
16 M
18 M
20 M
22 M
Month
Downloads
Figure 3: Downloads per month for the Next package from Jan 2023 to Dec 2023.
Data has been sourced from [84].
Next.js only announces breaking changes in major version releases per semantic
41https://vercel.com/. [Accessed 27-04-2024].
42https://react.dev/learn/start-a-new- react-project#nextjs. [Accessed 27-04-2024].
27
versioning conventions. The releases of v14 listed five breaking changes, whereas
v13 had eight [
82
]. To facilitate upgrades, Next.js provides migrations guides and
scripts to automate as many code changes as possible [
82
], such as modifying updated
imports from the framework.
However, breaking changes in and of themselves, do not always capture the
challenge in version upgrades. For instance, Next.js introduced its new
app
router
paradigm in v13, with continued support for the existing
pages
router. Although
upgrading to use the app router is optional, it is recommended by Next.js, causing a
cascade of issues for some users as it promotes a starkly different approach to routing
and data fetching, while functioning on top of React Server Components (RSC). As
such, many existing guides and resources no longer apply, and official documentation
needs to evolve in line with adoption and usage. There are many open issues and
discussions in GitHub concerning upgrading to the new app router paradigm.
Since its inception in 2016, Next.js has experienced significant growth and has
consistently been at the forefront of the JavaScript web framework landscape. It
has pioneered numerous features like out-of-the-box support for hybrid client-server
rendering, API routes, and file-based routing.
In recent years, particularly since v12, updates have focused on more granular
rendering approaches, such as adding middleware, edge rendering and Incremental
Static Regeneration (ISR) [
82
]. Next.js also added first-class support for RSC in v13,
being the first JavaScript web framework to do so. Through its updates, Next.js
has been able to progressively cater for an ever-increasing set of potential use cases,
particularly in server-side rendering. Next.js also collects community feedback and
ideas in RFC format through the repository’s GitHub discussion section43.
3.2 Astro
Originally developed as a Static Site Generator (SSG) in 2022 [
75
], Astro has
morphed into a server-first framework capable of building both static and dynamic
web applications, with a particular focus on content-heavy websites [
18
]. Astro’s key
features include sending no JavaScript to clients by default, partial hydration, and the
ability to Bring Your Own Framework (BYOF) as a feature of its islands architecture.
Astro also has a custom component-based HTML-like syntax, file-based routing,
asset handling, build process, bundling, built-in optimisations, and data-fetching
[18].
3.2.1 Architectural overview
Project structure Bootstrapping an Astro project created with
create astro@4.1.0 prompts the developer with the following options:
1.
How would you like to start your new project? (Include sample files (recom-
mended)/Use blog template/Empty)
43https://github.com/vercel/next.js/discussions/categories/rfc
. [Accessed 27-04-
2024].
28
2. Install dependencies? (Yes/No)
3. Do you plan to write TypeScript? (Yes/No)
4. How strict should TypeScript be? (Strict/Strictest/Relaxed)
5. Initialize a new git repository? (Yes/No)
Out of these configuration options, the ones related to TypeScript are the only
customisation options in the setup process. Going with the recommended defaults
and opting into TypeScript yields the structure depicted in Listing 8.
.
README.md
astro.config.mjs
package-lock.json
package.json
public
favicon.svg
src
components
Card.astro
env.d.ts
layouts
Layout.astro
pages
index.astro
tsconfig.json
Listing 8: The project structure of an Astro application with default configuration
options selected.
In comparison with Next.js, Astro comes with a
astro.config.*
for project-level
configuration, which is analogous to the
next.config.*
file that Next.js provides.
The installation process does not, however, prompt the developer to install Tailwind
CSS. In addition, the project also comes with a
public
folder for storing static
access, such as images and fonts. However, the main source code for an Astro project
lives under the
src
directory in contrast with the
app
or
pages
directory for Next.js.
In addition to dealing with Astro components, layouts and pages, the
src
directory
also hosts components from other UI frameworks, such as React.js [
3
]. The naming
of most subdirectories under
src
is up to the developer as only
src/pages
and
src/content are reserved by Astro.
Astro files also come with their own
.astro
file extension to support Astro’s own
components as opposed to the
.jsx
or
.tsx
extensions used by Next.js for using
29
JSX with React. This potentially introduces extra work for code transformers and
Integrated Development Environment (IDE)
44
tooling to support Astro syntax. For
instance, IDEs need to accommodate Astro’s custom files in features such as syntax
highlighting, code navigation, formatting, linting, autocomplete, and debugging.
Runtime architecture The runtime architecture of an Astro application is gov-
erned by three factors: the rendering approach selected, the use of JavaScript
framework components, and the use of interactivity in components. With a static
build, only the HTML and JavaScript bundle are outputted from the build process
and deployed to the hosting provider to be served to the client [
3
]. With both full and
hybrid server-side rendering, Astro’s build process uses a provider-specific adapter to
produce a JavaScript server able to generate and serve HTML in response to runtime
requests.
The supported runtimes for the server include Node.js, Bun and Deno [
18
]
45
.
Figure 4provides a high-level depiction of the possible outputs from the build process.
SSR Adapter
Figure 4: Overview of Astro’s build pipeline. The JavaScript bundle and runtime
node server are optional. The figure is adapted from [18].
In addition to standard Node.js-compatible servers, server-side Astro code can
also run on some serverless and edge runtimes through adapters, such as the Netlify
adapter [3, 53].
3.2.2 Extensibility
The primary ways in which Astro provides extensibility is through its UI-agnostic
islands architecture, community-driven plugin ecosystem, adapters and support for
various rendering strategies [
3
] — aspects which will be explored in detail in this
section.
44
An integrated development environment (IDE) is a software application that helps programmers
develop software code efficiently through features, such as editing, building, testing, and packaging
[10].
45
At the time of writing, the Node.js adapter is an official integration, whereas the adapters for
Bun and Deno are community managed.
30
Rendering strategies A key feature of the Astro framework is the concept of
islands architecture [
58
]. With Astro islands, UI views are rendered server-side
to static HTML by default, and developers can opt-in