Package: django-importmap
django-importmapHeavily inspired byrails/importmap-rails,
this app adds a simple process for integratingimport mapsinto Django.This is a new project and it hasn't been used in production yet.
But if you're looking to use import maps with Django, give it a try and tell us how it goes.
The structure (and code) is pretty simple.
Contributions are welcome!How to use itYou'll need to do four things to use django-importmap.The TL;DR is:Add "importmap" toINSTALLED_APPSCreate animportmap.tomlRunpython manage.py importmap_generateUse{% importmap_scripts %}in your template1. Install itDo the equivalent ofpip install django-importmapand add it to yourINSTALLED_APPSlist in yoursettings.pyfile.# settings.pyINSTALLED_APPS=[..."importmap",]2. Configuring an import mapYou JavaScript dependencies are conveniently located in yourpyproject.tomlfile.They are listed under[tool.importmap.dependencies]and you can add them there. The format isname = "version",
similar to how you would add a dependency to yourpackage.jsonfile.# pyproject.toml[tool.importmap.dependencies]react="17.0.2"react-dom="17.0.2"jspm.org generatoris used lock and serve the dependencies,
but is basically just like installing them vianpm i <npm package>@<version>.3. Runimportmap_generateTo resolve the import map, you'll need to runpython manage.py importmap_generate.This will createimportmap.lock(which you should save and commit to your repo) that contains the actual import map JSON (both for development and production).You don't need to look at this file yourself, but here is an example of what it will contain:{"config_hash":"09d6237cdd891aad07de60f54689d130","importmap":{"imports":{"react":"https://ga.jspm.io/npm:react@17.0.2/index.js"},"scopes":{"https://ga.jspm.io/":{"object-assign":"https://ga.jspm.io/npm:object-assign@4.1.1/index.js"}}},"importmap_dev":{"imports":{"react":"https://ga.jspm.io/npm:react@17.0.2/dev.index.js"},"scopes":{"https://ga.jspm.io/":{"object-assign":"https://ga.jspm.io/npm:object-assign@4.1.1/index.js"}}}}4. Add the scripts to your templateThe import map itself gets added by using{% load importmap %}and then{% importmap_scripts %}in the head of your HTML. This will include thees-module-shim.After that, you can include your own JavaScript!
This could be inline or fromstatic.
Just be sure to usetype="module"and the "name" you provided when doing your JS imports (i.e. "react").{% load importmap %}<!DOCTYPE html><htmllang="en"><head>{% importmap_scripts %}<scripttype="module">importReactfrom"react"console.log(React);</script></head><body></body></html>When it renders you should get something like this:<!DOCTYPE html><htmllang="en"><head><scriptasyncsrc="https://ga.jspm.io/npm:es-module-shims@1.3.6/dist/es-module-shims.js"></script><scripttype="importmap">{"imports":{"react":"https://ga.jspm.io/npm:react@17.0.2/dev.index.js"},"scopes":{"https://ga.jspm.io/":{"object-assign":"https://ga.jspm.io/npm:object-assign@4.1.1/index.js"}}}</script><scripttype="module">importReactfrom"react"console.log(React);</script></head><body></body></html>Adding static files to import mapsYou can include your own static files in the import map by passing kwargs to the{% importmap_scripts %}tag.
You can actually use this to include any additional imports, but by using{% static "name" as name_static %}you can get the URL to the static file.{% load importmap static %}<!DOCTYPE html><htmllang="en"><head>{% static "my-script.js" as my_script_static %}
    {% importmap_scripts myscript=my_script_static %}<scripttype="module">importMyScriptfrom"myscript"</script></head><body></body></html>Using Jinja2To use django-importmap with Jinja2 templates,
you can addimportmapto a customized Jinja environment.TEMPLATES=[{"BACKEND":"django.template.backends.jinja2.Jinja2",..."OPTIONS":{"environment":"app.jinja2.environment",...},}]Then inapp/jinja2.py:fromdjango.confimportsettingsfromjinja2importEnvironmentfromimportmapimportImportmapdefenvironment(**options):env=Environment(**options)env.globals.update({"importmap":Importmap.json(development=settings.DEBUG)})returnenvThen in your Jinja templates you can include a module shim and output theimportmapvariable like this:<!DOCTYPE html><htmllang="en"><head><scriptasyncsrc="https://ga.jspm.io/npm:es-module-shims@1.3.6/dist/es-module-shims.js"></script><scripttype="importmap">{{importmap|safe}}</script><scripttype="module">importReactfrom"react"console.log(React);</script></head><body></body></html>To include your own static files in the import map,
you can pass a dictionary of names and URLs to theImportmap.jsonmethod:fromdjango.confimportsettingsfromdjango.templatetags.staticimportstaticfromjinja2importEnvironmentfromimportmapimportImportmapdefenvironment(**options):env=Environment(**options)env.globals.update({"importmap":Importmap.json(development=settings.DEBUG,extra_imports={"myjs":static("myjs.js")})})returnenvProject statusThis is partly an experiment,
but honestly it's so simple that I don't think there can be much wrong with how it works currently.Here's a list of things that would be nice to do (PRs welcome):Command to add new importmap dependency (use^version automatically?)Django check for comparing lock and config (at deploy time, etc.)Usedepsto update shim versionPreload optionVendoring option (including shim)More complete error handling (custom exceptions, etc.)