Django Single File Templates
============================
[![image](https://badge.fury.io/py/django-sft.svg)](https://badge.fury.io/py/django-sft.svg)
[![Python 3.x](https://img.shields.io/pypi/pyversions/django-sft.svg?logo=python&logoColor=white)](https://pypi.org/project/django-sft/)
Django Single File Templates \-- inspired by Vue's Single file
components
Make your Django templates more organized by holding your HTML and all the related CSS and JavaScript in a sensible way.
`example.sft`
```html
<template>
{% extends 'example/base.sft' %}}
{% block main %}
<h1>This is index page</h1>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit eaque obcaecati maxime eos inventore tenetur, debitis atque quaerat modi, et illum id error quisquam consequatur reprehenderit, laboriosam exercitationem, provident aut.</p>
<h2 id="time"></h2>
{% endblock %}
</template>
<script>
document.getElementById('time').innerHTML = new Date();
</script>
<style>
p {
width: 50%;
background-color: white;
margin: auto;
}
</style>
```
> Disclaimer: This package serves as a proof of concept rather than a production-ready solution!
Motivation
----------
From Vue\'s documentation:
> One important thing to note is that separation of concerns is not
> equal to separation of file types. In modern UI development, we have
> found that instead of dividing the codebase into three huge layers
> that interweave with one another, it makes much more sense to divide
> them into loosely-coupled components and compose them. Inside a
> component, its template, logic and styles are inherently coupled, and
> collocating them actually makes the component more cohesive and
> maintainable.
Similar logic could be applied to Django's templates. HTML, JavaScript
and CSS are inherently coupled so it makes sense to put them together.
Introducing **Django Single File Templates (SFT)**.
Quickstart
----------
Install Django Single File Templates:
pip install django-sft
Add it to your `INSTALLED_APPS`:
```python
INSTALLED_APPS = (
...
'django_sft',
...
)
```
Add SFT Template loader (in your settings.py):
```python
TEMPLATES = [
{
...
'OPTIONS': {
'loaders': [
'django_sft.template.SFTLoader',
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
],
...
}
}
]
```
You can now start using Single file templates as your templates.
Usage
-----
Add a new SFT by adding a `.sft` file to your `templates` folder (either
in your apps or root templates folder). SFT should include at least HTML
(you can use Django\'s template language), but it can also include
script and style tags:
```html
<template>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example Website</title>
</head>
<body>
<header>
<nav>
<a href="/">Home</a>
<a href="/page" id="page">Page</a>
</nav>
</header>
{% block main %}
<h1>This is where the content will go</h1>
{% endblock %}
</body>
</html>
</template>
<script>
const page = document.getElementById('page');
page.addEventListener('click', (ev) => {
ev.preventDefault();
alert('You clicked the page');
});
</script>
<style>
body {
background-color: gray;
}
</style>
```
In your views you can render this template directly and SFT Template
loader will get the right template for you.
```python
def view(request):
return render('my-template.sft')
```
Single file templates can also extend other STFs.
```html
<template>
{% extends 'example/base.sft' %}}
{% block main %}
<h1>This is index page</h1>
<h2>Update</h2>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit eaque obcaecati maxime eos inventore tenetur, debitis atque quaerat modi, et illum id error quisquam consequatur reprehenderit, laboriosam exercitationem, provident aut.</p>
<h2 id="time"></h2>
{% endblock %}
</template>
<script>
document.getElementById('time').innerHTML = new Date();
</script>
<style>
p {
width: 50%;
background-color: white;
margin: auto;
}
</style>
```
It can also include external scripts and styles (bootstrap example):
```html
<template>
...
</template>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
const page = document.getElementById('page');
page.addEventListener('click', (ev) => {
ev.preventDefault();
alert('You clicked the page');
});
</script>
<style src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"></style>
<style>
body {
background-color: gray;
}
</style>
```
Single file templates will automatically be parsed and compiled when you
`manage.py runserver` if `DEBUG = True`. You can also run
`manage.py compile_sft` to compile manually.
How does it work?
-----------------
When SFT is compiled (on `runserver` or manually), django-sft will grab
the SFT file and produce appropriate `.js`, `.css` and `.html` files.
They will be created in `sft` directory (under `static` and `templates`
directories respectively). The html files will be automatically injected
with references to the static files. When a view will try to render
`.sft` template, the SFT Template Loader will look for resulting `.html`
file instead and return that.
The current implementation is quite simple and serves as a proof of
concept rather than a production-ready solution.
Look for a working example under [tests folder](tests).
Features
--------
- TODO
Running Tests
-------------
- TODO: no tests written yet
Does the code actually work?
source <YOURVIRTUALENV>/bin/activate
(myenv) $ pip install tox
(myenv) $ tox
Credits
-------
Tools used in rendering this package:
- [Cookiecutter](https://github.com/audreyr/cookiecutter)
- [cookiecutter-djangopackage](https://github.com/pydanny/cookiecutter-djangopackage)
History
-------
0.1.2 (2020-11-20)
++++++++++++++++++
* Enable external scripts and styles
* Enable multiple scripts and styles per file
0.1.1 (2020-11-16)
++++++++++++++++++
* Bug fixes
0.1.0 (2020-11-12)
++++++++++++++++++
* First release on PyPI.