Package: django-svelte
Django SvelteIncorporate a Svelte frontend into a Django site with minimal impact to deployment strategy and authentication story.ScopeThis package mainly consists of a templatetags which facilitate the import of JS/CSS bundles created by Svelte/Vite/Node.js into your template. For this package to be useful you will also need the Svelte/Vite/Node.js which produces the JS/CSS bundle. Thesvelte demo projectwalks you through setting this up from scratch.CompatibilityThis package was originally written during the Svelte 3 days and was bundled by Rollup. Version 0.1.7 and prior were devoted to supporting this stack. Newer versions of this packageoughtto support that old stack, but they are untested.Version 0.2.0 and on support Svelte 4 bundled by Vite.InstallationInstall the package:pipinstalldjango-svelteAdd to INSTALLED_APPS:INSTALLED_APPS=(..."django_svelte",...)Tell Django where your Svelte JS/CSS bundles will be found (this guide assumes that you place your svelte directory beside your django project directory as shown indemo_project):STATICFILES_DIRS=[# ...BASE_DIR.parent/"svelte"/"dist"/"assets",]If you are using Vite as the bundler for Svelte then you'll also want to tell Django where to find the Vite manifest so that components can be located by hash (Vite does not generate a manifest by default, see thebuild.manifestoption):DJANGO_SVELTE_VITE_MANIFEST_PATH=BASE_DIR.parent/"svelte"/"dist"/".vite"/"manifest.json",UsageTo use a Svelte component within your Django template load thedjango_sveltetemplatetag library and use thedisplay_svelteanddisplay_svelte_csstemplatetag:{% load django_svelte %}

...

{% display_svelte_css "MySpecialComponent" %}

{% display_svelte "MySpecialComponent" %}You can optionally pass some context (specifically a JSON serializabledict) to the component:{% display_svelte "MySpecialComponent" component_props %}Versions prior to 0.2.0 required using.svelteat the end of the component name, e.g.{% display_svelte "MySpecialComponent.svelte" component_props %}This is no longer required.Lets talk about CSSThere are many ways that Svelte generates CSS bundles.
Because of the flexibility of CSS many arrangements are possible, but they'll require you to update your Django templates accordingly.
Django templates are highly variable per project, so it is difficult to provide one-sized-fits-all advice in this arena.
It is likely that one or both of the use cases described below will work for your project.If your project follows the standardbase.html -> site_base.html -> <page>.htmlparadigm then you might find it convenient to also provide asvelte_base.htmlwhich includes a block (namelysvelte_styles) in theheadwhich will allow individual page templates to inject CSS where it ought to exist:Monolithic CSSIf your project collects all its CSS into a single stylesheet, then you can make that CSS file accessible as a staticfile and use a regularlinkto incorporate it into your template as shown below. It may be convenient to put this import for your stylesheet in your base template to limit boilerplate.{% load static %}
{% load django_svelte %}

<html>
  <head>
    ...
    {% block svelte_styles %}
      {{ block.super }}
      <link href={% static "AllCssGeneratedByRollupOrViteOrWhatever.css" %}
    {% endblock %}
  <body>
    ...
    {% display_svelte "Component" %}
  </body>
</html>See also the Vitebuild optioncssCodeSplitPer Component CSSIf you includestyletags in your individual Svelte components then you'll want to include the per component stylesheets when you display your component:{% extends "svelte_base.html" %}
{% load django_svelte %}

{% block svelte_styles %}
  {{ block.super }}
  {% display_svelte_css "Component" %}
{% endblock %}


{% block main_content %}
  {# or whatever... #}
  {% display_svelte "Component" %}
{% endblock %}Note the use ofdisplay_svelte_cssto specifically inject the CSS for the named component within thesvelte_stylesblock.Recommended PatternsIn addition to thesvelte_base.htmltemplate described above, there are some other tips that have proved effective when using this package. Basic implementations of the ideas described below are included with the demo project, but due to the extreme variability of django templates in practice you'll have to provide your own implementations.Class-based Wrapper ViewIf you have many components that each get loaded as the main content of their own pages then a reusable class-based view can reduce boilerplate. Subclass theSvelteTemplateViewclass provided inviews.pyto utilize this pattern; be sure to provide your ownget_svelte_propsmethod so that your component will have data! See thesample implementationDefault Svelte TemplateOnce you havesvelte_base.htmlin place, a subsequent template likesvelte_component.htmlis a convenient template for loading in a single component. If you're using the class based view approach describe above then this template should include a{{ page_title }}as well as the use of{% display_svelte_css component_name %}in theheadof the template, and{% display_svelte component_name %}in its body. See thesample implementationin the demo project.What about Svelte!?The Svelte side of things is demonstrated in theSvelte demo projectwhich shows how a default Vite+Svelte project can be altered to output JS/CSS bundles useful for this package. It is configured to output JS/CSS bundles for several different components which can be imported independently.New Svelte, who dis?The newer versions of Svelte are defaulting to SvelteKit, because routing is important stuff. If you're here then you're probably using Django for your routing, so there is no need for SvelteKit. Fortunately, Svelte (sans-Kit) is still availableby installingvite.The config for outputting multiple bundles got a bit easier from prior versions, and I changed the conventions around entrypoints in the demo project. What used to be calledmain-<component_name>.jsis now called<ComponentName>.jsand referenced as such in thebuild.rollupOptions.inputarray.Vite, by default and with much difficulty to alter, hashes files and appends the hash to the filename; probably a good practice, but kind of annoying for integrated packages. Instruct Vite to output a manifest by setting thebuild.manifestoption. The complementary settingDJANGO_SVELTE_VITE_MANIFEST_PATHallows you to specify where in the file tree the manifest file lives. After setting this you may go about using the component name (sans hash) in the various templatetags. Alternately, it is possible to prevent Vite from putting hashes into its output filenames but you're on your own for that!NOTE:This manifest arrangementwillget bothersome during dev as you have to cause Django to reload the manifest by saving a Django file each time you save a Svelte file (and the bundle hash changes). Ifanybodyknows a way to make this more manageable, please please tell me!Depending on how you have organized your Svelte project you may have specify where your Svelte component "Entrypoints" are located (Entrypoints are the thin javascript files that first import the Svelte component, seeApp.js. In the demo project, the entrypoints are directly in thesvelte/src/directory. If you have put your entrypoints somewhere else then you'll need to say where in theDJANGO_SVELTE_ENTRYPOIN_PREFIXsetting (value needs to be relative to thesveltedirectory and do include the trailing slash, e.g. the default valuesrc/). It is necessary that your entrypoints follow the naming convention<ComponentName>.js; if your top-level Svelte component is calledMySpecialComponent.sveltethen the entrypoint needs to be calledMySpecialComponent.jsor this package will not function correctly!It may be necessary to specify theDJANGO_SVELTE_VITE_ASSETSDIRsetting. It must match the value used invite.config.jsunder the keybuild.assetsDir. The default case (valueassets/) is covered.Devops concernsSo, this package isn't magic. For this to work you will need to have Node.jssomewherein the mix. Fortunately, you won't need Node.js running in your production environment, but you will need it somewhere in your CI pipeline and probably in your dev environment. For a practical example of what this might look like for a production environment seedemo_project.ShoutoutsThis work is inspired by the sentiments ofOwais Lone's writingabout the limitations of Django's frontend.This work takes some technical direction froma blog series on cbsofyalioglu. These references were immensely helpful in fleshing out this integration.