uiCommands/pythonLoader.js

import { loadScript } from 'src/kernel/dom.js'

let pendingPromise

const type = 'application/javascript'
// retourne la promesse de chargement du js sous forme de blob
const getLoadedPromise = (module) => {
  const blob = new Blob([module.default], { type })
  const url = URL.createObjectURL(blob)
  // une fois le script exécuté on devrait pouvoir faire du
  return loadScript(url, { type }).then(() => {
    URL.revokeObjectURL(url)
  })
}

/**
 * Charge les js brython et résoud la promesse retournée
 * @returns {Promise<unknown>}
 */
export async function addBrythonScripts () {
  // si on a déjà été appelé dans ce dom (possible avec plusieurs appels de mtgLoad pour plusieurs figures) on ne fait rien
  if (!pendingPromise) {
    const contentPromises = [
      import('./brython/scripts/brython.min.js?raw'),
      // on ne peut pas trop se passer de ça, notre runner.py utilise des trucs qui sont dedans
      // (et les élèves comprendraient pas de ne pas avoir les modules python de base)
      import('./brython/scripts/brython_stdlib.js?raw'),
      import('./brython/scripts/mathgraph.brython.js?raw')
    ]

    pendingPromise = new Promise((resolve, reject) => {
      // timeout déjà géré par loadScript, pas besoin d'en ajouter un ici
      Promise.all(contentPromises)
        .then(([main, stdLib, mtgLib]) => {
          // il faut charger en séquentiel, brython puis stdlib puis mtgLib
          getLoadedPromise(main)
            .then(() => getLoadedPromise(stdLib))
            .then(() => getLoadedPromise(mtgLib))
            .then(resolve)
        })
        .catch(reject)
    })
  }

  return pendingPromise
}

/*
HISTORIQUE

Ce fichier a un historique assez chargé, avec pas mal de tentatives infructueuses.

1) Chargement de brython.min.js + brython_stdlib.js sur le site de mathgraph via
   insertion de <script src="…">, avec du src = getBaseUrl() + 'externals/brython/…
=> ça oblige à mettre ces fichiers manuellement dans le dossier js/ du site, en
   espérant que ça fonctionne pour charger ensuite runner.py et mathgraph.py
   (qui eux doivent être à la racine du site), mais on est pas très sûr que ça
   fonctionne bien en cross-domain (avec un mtgLoad.js chargé depuis un domaine
   quelconque)
(cf avant 2024-04-04, par ex commit 87b0e258)

2) commit 1f5d5d8e
Pour régler le pb des fichiers *.py à la racine, on construit un package brython
 qui les contient (cf src/uiCommands/brython/README.md), et on importe les 3 js
 ici avec du ?url (pour récupérer l'url construite au build), .
=> Ça fonctionne bien avec un vrai build, mais pas avec un pnpm start (car dans
 ce cas il faut que les js concernés soient des modules js, ce qui n'est pas le
  cas ici). Tentative pour modifier les js afin qu'il puissent être chargés avec
   du <script type="module"> infructueuse (bcp trop de modifs à faire, à cause
    notamment de bcp de fcts redéfinies plusieurs fois suivant le contexte)

3) commit aa972346
On tente un import avec du ?raw (pour récupérer le contenu du js), que l'on
 injecte dans un tag script sans src.
- il faut bricoler un truc pour savoir quand les scripts sont interprétés
  (ce n'est pas le cas lorsque le appendChild rend la main, on ajoute en fin de
   script l'incrément d'une var globale pour le savoir)
- il faut bricoler un truc pour feinter brython, qui init des trucs d'après le
  src= de son tag <script>, ça fonctionne avec mise en global préalable de
  `window.__BRYTHON__ = { brython_path: getBaseUrl() }`
=> ça marche au build comme au pnpm start, mais la stacktrace affichée en console
   en cas d'erreur dans le script python devient inintelligible

4) Idem 3, mais avec du src= et du Blob
 */