Qwik City

Qwik City Review and Features

Written by Mojtaba Seyedi

Last update: 6/11/2024

In the landscape of meta frameworks, the focus on server-side rendering and client-side interactivity has taken various forms. First-generation meta frameworks like Next.js aimed to transform server-rendered HTML into fully functional applications on the client side. Newer frameworks like Astro or SvelteKit have shifted towards partial hydration or even defaulting to rendering only HTML and CSS, with JavaScript interactivity requiring explicit opt-in.

In this dynamic landscape, Qwik City was born, a framework that shines with its lightweight nature and performance-oriented design. It shares some similarities with Astro but stands out by providing a greater level of interactivity compared to Astro's default output.

What is Qwik City?

Qwik City is a meta-framework built on top of Qwik, a framework for creating interactive web applications. Qwik City enhances the core functionality of Qwik by adding additional features and capabilities to further improve the development experience.

Qwik, the core framework, focuses on resumability and optimizes rendering by eliminating the need for hydration. It loads only necessary JavaScript and defers execution until required, resulting in faster application loading times and extremely fast Time To Interactive (TTI). As described by the creator of Qwik, Miško Hevery, Qwik combines React-like developer experience with resumability. It's as if React itself was designed with server-side rendering (SSR) as a primary consideration right from the start.

Qwik City builds upon the powerful features of Qwik and introduces additional functionalities that enhance the development experience. These features include:

  • File-based routing
  • Nested layouts
  • Data fetching
  • Bundle optimization
  • Prefetching
  • Interoperability with edge function providers
  • Content authoring with .tsx or .mdx file formats
  • Seamless integration with popular libraries like React and Tailwind

Qwik City’s named and nested layouts are inspired by Sveltekit, and Next.js inspires Its grouped layouts.

While these common features are essential for a meta framework, what sets Qwik City apart is not merely slight differences in features. Instead, its uniqueness lies in how it leverages the power of the underlying Qwik framework itself. Now, let’s see how Qwik City is actually different from other meta frameworks.

Resumibiity

Qwik is different from other frameworks because it does not require hydration on the client. Not requiring hydration is what makes the Qwik application startup instantaneous. All other frameworks’ hydration replays all the application logic in the client. Qwik instead pauses execution in the server and resumes execution in the client.

The resumability feature in Qwik is different from hydration, which is a common technique used in front-end frameworks. Hydration involves taking the HTML generated on the server and attaching event handlers to the client-side components. It allows the server-rendered content to be interactive on the client side without requiring a full page reload. Hydration makes rendering happens twice, once on a server and once on a client.

Resumability recovers the framework’s state as a result of interaction, whereas Hydration must run before interaction. Resumability is about pausing execution in the server and resuming execution in the client without having to replay and download all of the application logic.

You can find more detail about this topic in the Qwik City documentation, which is the source of the following image.

The resumability feature makes Qwik unique and powerful and has several benefits, including:

  • Instant interactivity. Resumable applications are immediately interactive, even when they are first loaded. This is because the application state and component tree are already present on the client.
  • Improved performance. Resumable applications are typically faster because they do not require the client to hydrate the application state and component tree.

Active Prefetching

One of the powerful features of Qwik City is its active prefetching. While lazy loading on demand often introduces latency issues, Qwik City tackles this problem by actively prefetching what is possible. This means only the modules needed for the next potential interaction are prefetched, resulting in optimized performance without unnecessary overhead.

This feature is based on the concept of speculative module fetching. Speculative module fetching is a technique that involves fetching modules that are likely to be needed in the future, even if the user has not yet interacted with them. This can help to improve the performance of an application by reducing the number of times that the browser has to make requests to the server.

Qwik City takes a strategic approach to prefetching. Instead of prefetching a large portion of the application, it focuses on prefetching precisely what is required. For instance, if the only user interaction available is clicking a button, Qwik City will prefetch only the module related to that specific interaction. And all this happens in the background using a service worker.

File structure

A basic Qwik project looks like this:

qwik-app-demo
├── README.md
├── package.json
├── public
│   └── favicon.svg
├── src
│   ├── components
│   │   └── router-head
│   │       └── router-head.tsx
│   ├── entry.ssr.tsx
│   ├── global.css
│   ├── root.tsx
│   └── routes
│       ├── flower
│       │   ├── flower.css
│       │   └── index.tsx
│       ├── index.tsx
│       ├── layout.tsx
│       └── service-worker.ts
├── tsconfig.json
└── vite.config.ts
  • public: This folder contains static assets such as images, fonts, etc. When you build your app, these files will be copied to the dist/ directory and served at the root.
  • routes: The src/routes/ directory is where you define all your routes. Qwik City looks for your pages here. Folders and files inside this directory have a special meaning, and they will be mapped to the URL of your app.
  • routes/index.tsx: This is the homepage of your app.
  • routes/layout.tsx: This is the root layout of your application. All pages will be rendered inside this layout.
  • components: The src/components/ directory is where you should put your components. All Qwik starters will have this directory, but you can change it if you want.
  • entry.ssr.tsx: This is the entry point when the application is rendered outside the browser such as Server (express, cloudflare...), or when you start or build your application using the CLI.
  • root.tsx: The src/root.tsx file is the entry point for the application tree and is the first component that will be rendered since it’s the root of the tree.
  • global.css: This is where you write your global CSS used in multiple places in your app. The root component (src/root.tsx) imports this file by default.
  • tsconfig.json: The standard TypeScript configuration file.
  • vite.config.ts: This is the standard configuration file for Vite which Qwik uses to build the project.

Ecosystem

Qwik City is part of the Qwik web framework, which means that developers who use Qwik City have access to all of the resources and support available to the Qwik community. This includes documentation, tutorials, and examples, as well as a network of other developers who can help answer questions and provide support.

The Qwik ecosystem of libraries and tools are designed to work seamlessly with Qwik City and provide additional functionality and features that can help developers build even more powerful web applications.

You can also find support and resources through the Qwik community discussion forums on GitHub. These forums provide a space for developers to ask questions, share ideas, and collaborate on projects. Additionally, Qwik City developers can connect with others in the community through the Qwik Discord server.

Showcase

[@portabletext/react] Unknown block type "showcase", specify a component for it in the `components.types` prop

How to get started with Qwik City?

With the Qwik CLI and your preferred package manager, it's possible to create a Qwik application by executing any of the following commands:

npm create qwik@latest

pnpm create qwik@latest

yarn create qwik@latest

To set up your project, you have the option of selecting any of the following starters:

  • Basic App: Demo App with Routing built-in.
  • Empty App: App with Routing built-in ready to create your app.
  • Documentation site: Basic start point to build a docs site with Qwik.
  • Component library: Create a reusable Qwik component library.

Next, you can go to your app directory:

cd my-basic-qwik-app

And install your dependencies:

npm install

Finally, you can start the development server with any of the following commands:

npm start

pnpm start

yarn start

Now your application is going to be live at http://localhost:5173.

The Qwik documentation has a useful guide that can help you get started with the framework.

Deploying Qwik City

Once you've finished building your Qwik application, it's time to deploy it. But don't worry; Qwik makes the deployment process a breeze with its built-in integrations.

Qwik supports the following platforms:

You can add any integration by running the following command:

npm run qwik add

For example, to deploy on Netlify, you can run the following command:

npm run qwik add netlify-edge

Run the following command to build your app:

npm run build

And finally, the following command will deploy your application:

npm run deploy

Final thoughts

Qwik City is all about speed and performance. It ensures that websites load quickly and efficiently, delivering an outstanding experience for visitors. By leveraging resumability and optimizing JavaScript downloads, Qwik City achieves a fast Time To Interactive (TTI), enabling developers to achieve a perfect Lighthouse score. Additionally, Qwik City's integration with React allows developers to work with React components, enhancing the development experience for React enthusiasts.

[@portabletext/react] Unknown block type "prosCons", specify a component for it in the `components.types` prop