AnswerDotAI / AnswerDotAI/fasthtml
[BUG] ScriptableJS() requires presence of Script(type='module')
- Dominant language
- Jupyter Notebook
- Stars
- 7k
- Forks
- 319
- Avg merge
- 28m
- Merged PRs (30d)
- 3
Description
**Describe the bug**
SortableJS() requires presence of Script(type='module')
**Minimal Reproducible Example**
External scripts can be included through the `fast_html()` wrapper, like so:
```python
app, rt = fast_app(
hdrs=(SortableJS())
)
```
...but this results in:
```html
Botifython / Another / Home
:root { --pico-font-size: 100%; }
import {Sortable} from 'https://cdn.jsdelivr.net/npm/sortablejs/+esm';
proc_htmx('.sortable', Sortable.create);
(function() {
var socket = new WebSocket(`ws://${window.location.host}/live-reload`);
var maxReloadAttempts = 1;
var reloadInterval = 1000; // time between reload attempts in ms
socket.onclose = function() {
let reloadAttempts = 0;
const intervalFn = setInterval(function(){
window.location.reload();
reloadAttempts++;
if (reloadAttempts === maxReloadAttempts) clearInterval(intervalFn);
}, reloadInterval);
}
})();
```
...which if you look close you will see that the JavaScript import is not
wrapped in a `` tag resulting in `<head>`-leakage. In
experimenting, I find that this will fix it:
```python
app, rt = fast_app(
hdrs=(SortableJS(), Script(type="module"))
)
```
...because even though it ends up with an empty script module tag, it also wraps
the SortableJS one properly:
```html
<!doctype html>
<html>
<head>
<title>Botifython / Another / Home </title> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<script src="https://unpkg.com/htmx.org@next/dist/htmx.min.js">
:root { --pico-font-size: 100%; }
import {Sortable} from 'https://cdn.jsdelivr.net/npm/sortablejs/+esm';
proc_htmx('.sortable', Sortable.create);
(function() {
var socket = new WebSocket(`ws://${window.location.host}/live-reload`);
var maxReloadAttempts = 1;
var reloadInterval = 1000; // time between reload attempts in ms
socket.onclose = function() {
let reloadAttempts = 0;
const intervalFn = setInterval(function(){
window.location.reload();
reloadAttempts++;
if (reloadAttempts === maxReloadAttempts) clearInterval(intervalFn);
}, reloadInterval);
}
})();
```
It's a hack.
**Expected behavior**
```python
app, rt = fast_app(
hdrs=(SortableJS())
)
```
...should result in:
```html
import {Sortable} from 'https://cdn.jsdelivr.net/npm/sortablejs/+esm';
proc_htmx('.sortable', Sortable.create);
```
**Environment Information**
- fasthtml version: 0.6.9
**Confirmation**
Please confirm the following:
- [✅] I have read the FAQ (https://docs.fastht.ml/explains/faq.html)
- [👨🎨] I have provided a minimal reproducible example
- [💯] I have included the versions of fastlite, fastcore, and fasthtml
- [🔥] I understand that this is a volunteer open source project with no commercial support.
Contributor guide
Research direction
Start by reproducing fast_app(hdrs=(SortableJS(),)) with fasthtml 0.6.9 and compare the generated head with the documented workaround using Script(type="module"). Trace how SortableJS() content is inserted into the head; done means the expected usage emits the import inside a single script type="module" tag without requiring an empty Script tag.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, python
- Domain
- frontend, web-dev
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100