How JavaScript fits into Django
JavaScript ecosystem and tooling
JavaScript frontend libraries and frameworks
Despite its reputation of being a toy language, JavaScript has become a mature tool in recent years.
For bad or good, JavaScript is everywhere these days. JavaScript tooling has grown exponentially as well, with new libraries and techniques pouring fast in the ecosystem. In this chapter, we introduce the modern JavaScript scene. You will understand what JavaScript tools do, and how they fit within Django. We also take a look at the most popular frontend libraries and frameworks.
JavaScript and Django in Production
To better understand how modern JavaScript fits into Django, we should think not only of a local development environment, but first and foremost of the typical production context.
The Django project itself
A reverse proxy, such as NGINX, to serve static files, which also acts as an SSL termination
A WSGI or ASGI server, such as Gunicorn, Uvicorn, or Hypercorn (more on ASGI in the next chapter)
A Django Template Referencing a Static File
This is the most simple situation, where we have one or more Django apps, each with its own JavaScript files. This approach works well for tiny apps, where the JavaScript code for the entry point of the application fits within the 200KB limit. By entry point in this context, we mean the first JavaScript file that the browser has to download to kickstart the whole application. Since this book is about “decoupled Django” we need to think about more complex setups where the JavaScript payload served to the user could go well over 200KB. Also, the bigger a JavaScript application grows, the more we need to structure our code in a modular fashion, which leads us to talk about JavaScript ES modules and module bundlers.
The Need for Module Bundlers
Up until 2015, JavaScript didn’t have a standard module system on the frontend. Whereas Node.js always had require() from the beginning, the situation was really scattered on the frontend with different and competing approaches like AMD modules, UMD, and CommonJS.
Finally, in 2015, ES modules landed in ECMAScript. ES modules offer a standard approach to code reuse in JavaScript, while also enabling powerful patterns like dynamic import for improving performances in bigger applications. Now, the problem for a typical frontend project is that ES modules are not the only asset available to the developer. There are images, style files such as CSS or SASS, and different types of JavaScript modules to include. Let’s also not forget that ES modules are a rather new artifact, and traditional module formats are still out there. A JavaScript project might use new libraries based on ES modules, but need as well to include code distributed as CommonJS. Moreover, ES modules are not supported by older browsers.
Assemble different types of JavaScript modules into the same application
Include different types of files and assets in a JavaScript project
Improve the performance of the application with a technique known as code splitting
In brief, module bundlers offer a unified interface for collecting all the dependencies of a frontend project, assembling them, and producing one or more JavaScript files called bundles, in addition to any other asset (CSS and images) for the final application. One of the most popular module bundlers these days is webpack, which is also used in the most important CLI tools for project scaffolding in the JavaScript land (create-react-app, Vue CLI). In the next section, we explore why webpack is important for the Django developer who needs to deal with a lot of JavaScript.
Webpack Fights Django (the Need for Code Splitting)
Code splitting in JavaScript refers to the ability to serve the minimum amount possible of JavaScript to the client, while loading all the rest on-demand.
At the route level
At the component level
On user interactions (dynamic import)
Two Chunks As They Appear in the HTML
Here, chunk-vendors.468a5298.js must come before app.24e08b96.js, because chunk-vendors.468a5298.js contains one or more dependencies for the entry point. Keeping our focus on Django, you can imagine that to inject these chunks in the same exact order, we need some system for pairing the appearance order of each file with the static tag in our templates. A Django library called django-webpack-loader was meant to ease the usage of webpack within Django projects, but when webpack 4 came out with a new configuration for code splitting, splitChunks, django-webpack-loader stopped working.
The takeaway here is that JavaScript tooling moves faster than anything else, and it’s not easy for package maintainers to keep up with the latest changes. Also, messing up with the webpack configuration is a luxury not everybody can afford, not counting the risk of configuration drift and breaking changes. When in doubt, before fighting webpack or touching its configuration, use this mini-heuristic to decide what to do: if the JavaScript section of an app is over 200KB, use the appropriate CLI tooling and serve the application as a single-page app within a Django template, or as a decoupled SPA. We will explore the first approach in Chapter 5. If the JavaScript code fits within the 200KB limit instead, and the amount of interactive interactions are low, use a simple <script> tag to load what you need, or if you want to use modern JavaScript, configure a simple webpack pipeline with vendor splitting at least. Having outlined the foundations of module bundlers, let’s now continue our tour of the modern JavaScript tooling.
JavaScript tooling, and webpack in particular, are too much of a moving target to cover in a book without the risk of providing outdated instructions. For this reason, I don't cover the setup of a webpack project here. You can find a link to an example of such a setup in the resources.
Modern JavaScript, Babel, and Webpack
As developers we are quite fortunate, because most of the time we have access to fast Internet connections, powerful machines with many cores, plenty of RAM, and modern browsers.
The second example is clearly more concise, understandable, and palatable for developers. The drawback is that older browsers don’t understand Array.prototype.includes() or const. We can’t ship this code as it is.
Both caniuse.com and the compatibility tables at developer.mozilla.org are invaluable resources for understanding if a given target browser supports modern syntax.
- 1.
Webpack ingests ES modules written in modern JavaScript.
- 2.
A webpack loader passes the code through Babel.
- 3.
Babel transpiles the code.
The webpack/Babel duo is ubiquitous these days, used by create-react-app, Vue CLI, and more.
A Word on TypeScript
TypeScript is the elephant in the room for most developers.
As a statically typed declination of JavaScript, TypeScript is more similar to languages like C# or Java. It is widespread in the Angular world, and it is conquering more and more JavaScript libraries, which now ship with type definitions by default. Whether you like TypeScript or not, it is a tool to keep in consideration. In Chapters 8, 11, and 12, we work with TypeScript in React.
JavaScript Frontend Libraries and Frameworks
The JavaScript landscape has changed dramatically over the years. jQuery still owns a large market share.
React, the UI library from Facebook, which popularized (but not pioneered) a component-based approach to writing interfaces
Vue.js, the progressive UI library from Evan You, former Angular developer, which shines for its progressiveness
Angular, the battery-included framework, based on TypeScript
A state management library
A routing library
A schema validation library
A form validation library
Client-side applications fetching data from a Django REST/GraphQL API
Server-side rendered or static site generators with Django as a content source
We explore both topics in more detail later in the book. In the next section, we take a quick look at some alternatives to the traditional single-page approach.
Lightweight JavaScript UI Libraries
Other than Angular, Vue, React, and Svelte, there is a growing number of lightweight JavaScript mini-frameworks, born to ease the most mundane tasks on the frontend and to provide just enough JavaScript to get going.
AlpineJS
Hotwire
Htmx
Hotwire is a set of tooling and techniques popularized by Ruby on Rails and its creator, David Heinemeier Hansson. At the time of this writing, there is experimental work called turbo-django aiming at porting these techniques into Django. Along the same lines there is also a new Django framework called django-unicorn . All these tools offer a less JavaScript-heavy approach to building interactive interfaces. They will be worth a look once they start to gain traction in the wild.
Universal JavaScript Applications
Node.js is an environment for running JavaScript code outside of browsers. This means servers and CLI tools.
The majority of the tools we mentioned in this chapter are JavaScript-based, and since they run on the command line, they need a JavaScript environment, which Node.js provides. Now, if you pair this with frontend libraries that are capable of running on any JavaScript environment, not only browsers (like React and Vue.js), you obtain a particular breed of JavaScript tooling that is taking the scene by storm with a JavaScript-centric approach to server-side rendering.
It improves SEO for content-heavy websites
It improves performances, since the main rendering effort is pushed to the server
We already have a big client-side app and we want to improve its performances, both for the end user and for crawlers
We have a lot of common code between the frontend and the Node.js backend, and we want to reuse it
Next.js for React
Nuxt.js for Vue.js
Angular Universal for Angular
There are probably a million more tools out there. In Chapter 7, we focus on Next.js.
Static Site Generators
While the approach to server-side rendering offered by tools like Next.js and Nuxt.js is indeed interesting, static site generation should be the first choice in all those cases where search engine optimization is paramount and there is little to no JavaScript-driven interaction on certain pages (think of a blog, for example).
Gatsby
Next.js for React
Nuxt.js for Vue.js
Scully for Angular
Next.js and Nuxt.js can work in two modes: server-side rendering and static site generation. To source data from the backend, these tools offer interfaces for making plain HTTP requests to a REST API, or alternatively GraphQL. Gatsby instead makes exclusive use of GraphQL, and might not be the right tool for every team.
Testing Tooling
The whole Chapter 8 is devoted to testing Django and JavaScript applications. In this section, we briefly introduce the most popular testing tools for JavaScript. They fall into the conventional categorizations of testing.
Jest
Cypress
Puppeteer by Google
Playwright by Microsoft
For unit testing and integration testing between multiple units, Jest is the most popular tool to this date. It can test pure JavaScript code and React/Vue.js components as well. For end-to-end testing and functional testing, Cypress is the most feature-complete test runner, and plays well with Django too, with Puppeteer and Playwright gaining traction. Truth be told, Jest and Cypress can be thought more as wrappers around existing testing libraries: Jest builds on top of Jasmine, while Cypress builds on top of Mocha, as they borrow a high number of methods from these libraries. However, their popularity is sparked by the fluent testing API they provide, in contrast to more traditional tools.
Other Ancillary JavaScript Tools
I would be remiss not to mention ancillary JavaScript tools , so important for the modern JavaScript developer.
In both the Python and JavaScript land, there are code linters. For JavaScript, ESLint is the most widespread. Then we have code formatters like Prettier. At the intersection between pure JavaScript code and design systems we find Storybook, a powerful tool for building design systems. Storybook is used widely in the React and React Native community, but compatible with the most popular frontend libraries like Vue and Svelte. Together with testing tools, linters, formatters, and UI tools make a powerful arsenal for every JavaScript and Django developer.
Summary
JavaScript and Django in production
Module bundlers and code splitting
How webpack integrates into Django
JavaScript tooling as a whole
Universal JavaScript applications
In the next chapter, we introduce the asynchronous Django landscape.