Passage de webpack à vite.dev

This commit is contained in:
Antoine Bartuccio 2024-11-19 01:56:55 +01:00 committed by Bartuccio Antoine
parent 7b41051d0d
commit 8a8851847c
28 changed files with 1565 additions and 2818 deletions

View File

@ -1,15 +0,0 @@
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
}
}
]
]
}

View File

@ -3,7 +3,7 @@
<head> <head>
<title>{% trans %}Slideshow{% endtrans %}</title> <title>{% trans %}Slideshow{% endtrans %}</title>
<link href="{{ static('css/slideshow.scss') }}" rel="stylesheet" type="text/css" /> <link href="{{ static('css/slideshow.scss') }}" rel="stylesheet" type="text/css" />
<script src="{{ static('bundled/jquery-index.js') }}"></script> <script type="module" src="{{ static('bundled/jquery-index.js') }}"></script>
<script src="{{ static('com/js/slideshow.js') }}"></script> <script src="{{ static('com/js/slideshow.js') }}"></script>
</head> </head>
<body> <body>

View File

@ -1 +1 @@
require("@fortawesome/fontawesome-free/css/all.css"); import "@fortawesome/fontawesome-free/css/all.css";

View File

@ -1 +1,3 @@
window.htmx = require("htmx.org"); import htmx from "htmx.org";
Object.assign(window, { htmx });

View File

@ -1,25 +0,0 @@
import $ from "jquery";
import "jquery.shorten/src/jquery.shorten.min.js";
// We ship jquery-ui with jquery because when standalone with webpack
// JQuery is also included in the jquery-ui package. We do gain space by doing this
// We require jquery-ui components manually and not in a loop
// Otherwise it increases the output files by a x2 factor !
require("jquery-ui/ui/widgets/accordion.js");
require("jquery-ui/ui/widgets/autocomplete.js");
require("jquery-ui/ui/widgets/button.js");
require("jquery-ui/ui/widgets/dialog.js");
require("jquery-ui/ui/widgets/tabs.js");
require("jquery-ui/themes/base/all.css");
/**
* Simple wrapper to solve shorten not being able on legacy pages
* @param {string} selector to be passed to jQuery
* @param {Object} options object to pass to the shorten function
**/
function shorten(selector, options) {
$(selector).shorten(options);
}
window.shorten = shorten;

View File

@ -0,0 +1,2 @@
// This is only used to import jquery-ui css files
import "jquery-ui/themes/base/all.css";

View File

@ -14,18 +14,19 @@
{% block jquery_css %} {% block jquery_css %}
{# Thile file is quite heavy (around 250kb), so declaring it in a block allows easy removal #} {# Thile file is quite heavy (around 250kb), so declaring it in a block allows easy removal #}
<link rel="stylesheet" href="{{ static('bundled/jquery-index.css') }}"> <link rel="stylesheet" href="{{ static('bundled/jquery-ui-index.css') }}">
{% endblock %} {% endblock %}
<link rel="preload" as="style" href="{{ static('bundled/fontawesome-index.css') }}" onload="this.onload=null;this.rel='stylesheet'"> <link rel="preload" as="style" href="{{ static('bundled/fontawesome-index.css') }}" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="{{ static('bundled/fontawesome-index.css') }}"></noscript> <noscript><link rel="stylesheet" href="{{ static('bundled/fontawesome-index.css') }}"></noscript>
<script src="{{ url('javascript-catalog') }}"></script> <script src="{{ url('javascript-catalog') }}"></script>
<script src={{ static("bundled/core/components/include-index.ts") }}></script> <script type="module" src={{ static("bundled/core/components/include-index.ts") }}></script>
<script src="{{ static('bundled/alpine-index.js') }}" defer></script> <script type="module" src="{{ static('bundled/alpine-index.js') }}"></script>
<script src="{{ static('bundled/htmx-index.js') }}" defer></script> <script type="module" src="{{ static('bundled/htmx-index.js') }}"></script>
<!-- Jquery declared here to be accessible in every django widgets -->
<script src="{{ static('bundled/jquery-index.js') }}"></script> <!-- Jquery declared here to be accessible in every django widgets -->
<!-- Put here to always have access to those functions on django widgets --> <script src="{{ static('bundled/vendored/jquery.min.js') }}"></script>
<script src="{{ static('bundled/vendored/jquery-ui.min.js') }}"></script>
<script src="{{ static('core/js/script.js') }}"></script> <script src="{{ static('core/js/script.js') }}"></script>

View File

@ -7,7 +7,7 @@
{%- endblock -%} {%- endblock -%}
{% block additional_js %} {% block additional_js %}
<script src="{{ static("bundled/user/family-graph-index.js") }}" defer></script> <script type="module" src="{{ static("bundled/user/family-graph-index.js") }}" defer></script>
{% endblock %} {% endblock %}
{% block title %} {% block title %}

View File

@ -5,7 +5,7 @@
{%- endblock -%} {%- endblock -%}
{% block additional_js %} {% block additional_js %}
<script src="{{ static('bundled/user/pictures-index.js') }}" defer></script> <script type="module" src="{{ static('bundled/user/pictures-index.js') }}" defer></script>
{% endblock %} {% endblock %}
{% block title %} {% block title %}

View File

@ -1,5 +1,5 @@
{% for js in statics.js %} {% for js in statics.js %}
<script-once src="{{ js }}" defer></script-once> <script-once type="module" src="{{ js }}" defer></script-once>
{% endfor %} {% endfor %}
{% for css in statics.css %} {% for css in statics.css %}
<link-once rel="stylesheet" type="text/css" href="{{ css }}" defer></link-once> <link-once rel="stylesheet" type="text/css" href="{{ css }}" defer></link-once>

View File

@ -1,5 +1,5 @@
<div> <div>
<script-once src="{{ statics.js }}" defer></script-once> <script-once type="module" src="{{ statics.js }}" defer></script-once>
<link-once rel="stylesheet" type="text/css" href="{{ statics.css }}" defer></link-once> <link-once rel="stylesheet" type="text/css" href="{{ statics.css }}" defer></link-once>
<markdown-input name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>{% if widget.value %}{{ widget.value }}{% endif %}</markdown-input> <markdown-input name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>{% if widget.value %}{{ widget.value }}{% endif %}</markdown-input>

View File

@ -1,4 +1,4 @@
<script-once src="{{ statics.js }}" defer></script-once> <script-once type="module" src="{{ statics.js }}" defer></script-once>
<link-once rel="stylesheet" type="text/css" href="{{ statics.css }}" defer></link-once> <link-once rel="stylesheet" type="text/css" href="{{ statics.css }}" defer></link-once>
<span> <span>

View File

@ -10,6 +10,6 @@ class MarkdownInput(Textarea):
context["statics"] = { context["statics"] = {
"js": staticfiles_storage.url("bundled/core/components/easymde-index.ts"), "js": staticfiles_storage.url("bundled/core/components/easymde-index.ts"),
"css": staticfiles_storage.url("bundled/core/components/easymde-index.css"), "css": staticfiles_storage.url("bundled/easymde-index.css"),
} }
return context return context

View File

@ -22,7 +22,7 @@ class AutoCompleteSelectMixin:
"bundled/core/components/ajax-select-index.ts", "bundled/core/components/ajax-select-index.ts",
] ]
css = [ css = [
"bundled/core/components/ajax-select-index.css", "bundled/ajax-select-index.css",
"core/components/ajax-select.scss", "core/components/ajax-select.scss",
] ]

View File

@ -401,24 +401,16 @@ Npm possède, tout comme Poetry, la capacité de locker les dépendances au moye
Nous l'utilisons ici pour gérer les dépendances JavaScript. Celle-ci sont déclarées dans le fichier `package.json` situé à la racine du projet. Nous l'utilisons ici pour gérer les dépendances JavaScript. Celle-ci sont déclarées dans le fichier `package.json` situé à la racine du projet.
### Webpack ### Vite
[Utiliser webpack](https://webpack.js.org/concepts/) [Utiliser vite](https://vite.dev)
Webpack est un bundler de fichiers static. Il nous sert ici à mettre à disposition les dépendances frontend gérées par npm. Vite est un bundler de fichiers static. Il nous sert ici à mettre à disposition les dépendances frontend gérées par npm.
Il sert également à intégrer les autres outils JavaScript au workflow du Sith de manière transparente. Il sert également à intégrer les autres outils JavaScript au workflow du Sith de manière transparente.
Webpack a été choisi pour sa versatilité et sa popularité. C'est un des plus anciens bundler et il est là pour rester. Vite a été choisi pour sa versatilité et sa popularité. Il est moderne et très rapide avec un fort soutien de la communauté.
Le logiciel se configure au moyen du fichier `webpack.config.js` à la racine du projet. Il intègre aussi tout le nécessaire pour la rétro-compatibilité et le Typescript.
### Babel Le logiciel se configure au moyen du fichier `vite.config.mts` à la racine du projet.
[Babel](https://babeljs.io/)
Babel est un outil qui offre la promesse de convertir le code JavaScript moderne en code JavaScript plus ancien sans action de la part du développeur. Il permet de ne pas se soucier de la compatibilité avec les navigateurs et de coder comme si on était toujours sur la dernière version du langage.
Babel est intégré dans Webpack et tout code bundlé par celui-ci est automatiquement converti.
Le logiciel se configure au moyen du fichier `babel.config.json` à la racine du projet.

View File

@ -11,7 +11,7 @@
{% block additional_js %} {% block additional_js %}
{# This script contains the code to perform requests to manipulate the {# This script contains the code to perform requests to manipulate the
user basket without having to reload the page #} user basket without having to reload the page #}
<script src="{{ static('bundled/eboutic/eboutic-index.ts') }}"></script> <script type="module" src="{{ static('bundled/eboutic/eboutic-index.ts') }}"></script>
{% endblock %} {% endblock %}
{% block additional_css %} {% block additional_css %}

View File

@ -9,6 +9,10 @@
<link rel="stylesheet" href="{{ static('election/css/election.scss') }}"> <link rel="stylesheet" href="{{ static('election/css/election.scss') }}">
{%- endblock %} {%- endblock %}
{% block additional_css %}
<script src="{{ static('bundled/vendored/jquery.shorten.min.js') }}"></script>
{% endblock %}
{% block content %} {% block content %}
<h3 class="election__title">{{ election.title }}</h3> <h3 class="election__title">{{ election.title }}</h3>
<p class="election__description">{{ election.description }}</p> <p class="election__description">{{ election.description }}</p>
@ -197,12 +201,12 @@
{% block script %} {% block script %}
{{ super() }} {{ super() }}
<script type="text/javascript"> <script type="text/javascript">
shorten('.role_description', { $('.role_description').shorten({
moreText: "{% trans %}Show more{% endtrans %}", moreText: "{% trans %}Show more{% endtrans %}",
lessText: "{% trans %}Show less{% endtrans %}", lessText: "{% trans %}Show less{% endtrans %}",
showChars: 50 showChars: 50
}); });
shorten('.candidate_program', { $('.candidate_program').shorten({
moreText: "{% trans %}Show more{% endtrans %}", moreText: "{% trans %}Show more{% endtrans %}",
lessText: "{% trans %}Show less{% endtrans %}", lessText: "{% trans %}Show less{% endtrans %}",
showChars: 200 showChars: 200

View File

@ -5,7 +5,7 @@
{% endblock %} {% endblock %}
{% block additional_js %} {% block additional_js %}
<script src="{{ static('bundled/galaxy/galaxy-index.js') }}" defer></script> <script type="module" src="{{ static('bundled/galaxy/galaxy-index.js') }}" defer></script>
{% endblock %} {% endblock %}

4030
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -4,11 +4,11 @@
"description": "Le web Sith de l'AE", "description": "Le web Sith de l'AE",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"compile": "webpack --mode production", "compile": "vite build --mode production",
"compile-dev": "webpack --mode development", "compile-dev": "vite build --mode development",
"serve": "webpack --mode development --watch", "serve": "vite build --mode development --watch",
"analyse-dev": "webpack --config webpack.analyze.config.js --mode development", "analyse-dev": "vite-bundle-visualizer --mode development",
"analyse-prod": "webpack --config webpack.analyze.config.js --mode production", "analyse-prod": "vite-bundle-visualizer --mode production",
"check": "biome check --write" "check": "biome check --write"
}, },
"keywords": [], "keywords": [],
@ -25,20 +25,12 @@
"@babel/preset-env": "^7.25.4", "@babel/preset-env": "^7.25.4",
"@biomejs/biome": "1.9.3", "@biomejs/biome": "1.9.3",
"@hey-api/openapi-ts": "^0.53.8", "@hey-api/openapi-ts": "^0.53.8",
"@rollup/plugin-inject": "^5.0.5",
"@types/alpinejs": "^3.13.10", "@types/alpinejs": "^3.13.10",
"@types/jquery": "^3.5.31", "@types/jquery": "^3.5.31",
"babel-loader": "^9.2.1", "vite": "^5.4.11",
"css-loader": "^7.1.2", "vite-bundle-visualizer": "^1.2.1",
"css-minimizer-webpack-plugin": "^7.0.0", "vite-plugin-static-copy": "^2.1.0"
"expose-loader": "^5.0.0",
"mini-css-extract-plugin": "^2.9.1",
"source-map-loader": "^5.0.0",
"terser-webpack-plugin": "^5.3.10",
"ts-loader": "^9.5.1",
"typescript": "^5.6.3",
"webpack": "^5.94.0",
"webpack-bundle-analyzer": "^4.10.2",
"webpack-cli": "^5.1.4"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^6.6.0", "@fortawesome/fontawesome-free": "^6.6.0",

View File

@ -10,7 +10,7 @@
{% endblock %} {% endblock %}
{% block additional_js %} {% block additional_js %}
<script src="{{ static('bundled/pedagogy/guide-index.js') }}" defer></script> <script type="module" src="{{ static('bundled/pedagogy/guide-index.js') }}" defer></script>
{% endblock %} {% endblock %}
{% block head %} {% block head %}

View File

@ -6,7 +6,7 @@
{%- endblock -%} {%- endblock -%}
{%- block additional_js -%} {%- block additional_js -%}
<script src="{{ static('bundled/sas/album-index.js') }}" defer></script> <script type="module" src="{{ static('bundled/sas/album-index.js') }}" defer></script>
{%- endblock -%} {%- endblock -%}
{% block title %} {% block title %}

View File

@ -1,14 +1,14 @@
{% extends "core/base.jinja" %} {% extends "core/base.jinja" %}
{%- block additional_css -%} {%- block additional_css -%}
<link defer rel="stylesheet" href="{{ static('bundled/core/components/ajax-select-index.css') }}"> <link defer rel="stylesheet" href="{{ static('bundled/ajax-select-index.css') }}">
<link defer rel="stylesheet" href="{{ static('core/components/ajax-select.scss') }}"> <link defer rel="stylesheet" href="{{ static('core/components/ajax-select.scss') }}">
<link defer rel="stylesheet" href="{{ static('sas/css/picture.scss') }}"> <link defer rel="stylesheet" href="{{ static('sas/css/picture.scss') }}">
{%- endblock -%} {%- endblock -%}
{%- block additional_js -%} {%- block additional_js -%}
<script defer src="{{ static('bundled/core/components/ajax-select-index.ts') }}"></script> <script type="module" defer src="{{ static('bundled/core/components/ajax-select-index.ts') }}"></script>
<script defer src="{{ static("bundled/sas/viewer-index.ts") }}"></script> <script type="module" defer src="{{ static("bundled/sas/viewer-index.ts") }}"></script>
{%- endblock -%} {%- endblock -%}
{% block title %} {% block title %}

View File

@ -6,7 +6,7 @@
{% block head %} {% block head %}
{{ super() }} {{ super() }}
<script src="{{ static('bundled/subscription/stats-index.ts') }}" defer></script> <script type="module" src="{{ static('bundled/subscription/stats-index.ts') }}" defer></script>
{% endblock %} {% endblock %}
{% block content %} {% block content %}

View File

@ -10,6 +10,7 @@
"experimentalDecorators": true, "experimentalDecorators": true,
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"esModuleInterop": true, "esModuleInterop": true,
"resolveJsonModule": true,
"types": ["jquery", "alpinejs"], "types": ["jquery", "alpinejs"],
"paths": { "paths": {
"#openapi": ["./staticfiles/generated/openapi/index.ts"], "#openapi": ["./staticfiles/generated/openapi/index.ts"],

85
vite.config.mts Normal file
View File

@ -0,0 +1,85 @@
// biome-ignore lint/correctness/noNodejsModules: this is backend side
import { parse, resolve } from "node:path";
import inject from "@rollup/plugin-inject";
import { glob } from "glob";
import type { AliasOptions, UserConfig } from "vite";
import { viteStaticCopy } from "vite-plugin-static-copy";
import tsconfig from "./tsconfig.json";
const outDir = resolve(__dirname, "./staticfiles/generated/bundled");
const vendored = resolve(outDir, "vendored");
const nodeModules = resolve(__dirname, "node_modules");
function getAliases(): AliasOptions {
const aliases: AliasOptions = {};
for (const [key, value] of Object.entries(tsconfig.compilerOptions.paths)) {
aliases[key] = resolve(__dirname, value[0]);
}
return aliases;
}
type IndexPath = { [find: string]: string };
// biome-ignore lint/style/noDefaultExport: this is recommended by documentation
export default {
base: "/static/bundled/",
appType: "custom",
build: {
outDir: outDir,
modulePreload: false, // would require `import 'vite/modulepreload-polyfill'` to always be injected
emptyOutDir: true,
rollupOptions: {
input: glob
.sync("./!(static)/static/bundled/**/*?(-)index.?(m)[j|t]s?(x)")
.reduce((obj: IndexPath, el) => {
// We include the path inside the bundled folder in the name
let relativePath: string[] = [];
const fullPath = parse(el);
for (const dir of fullPath.dir.split("/").reverse()) {
if (dir === "bundled") {
break;
}
relativePath.push(dir);
}
// We collected folders in reverse order, we put them back in the original order
relativePath = relativePath.reverse();
relativePath.push(fullPath.name);
obj[relativePath.join("/")] = `./${el}`;
return obj;
}, {}),
output: {
entryFileNames: "[name].js",
assetFileNames: "[name].[ext]",
},
},
},
resolve: {
alias: getAliases(),
},
plugins: [
inject({
// biome-ignore lint/style/useNamingConvention: that's how it's called
Alpine: "alpinejs",
}),
viteStaticCopy({
targets: [
{
src: resolve(nodeModules, "jquery/dist/jquery.min.js"),
dest: vendored,
},
{
src: resolve(nodeModules, "jquery-ui/dist/jquery-ui.min.js"),
dest: vendored,
},
{
src: resolve(nodeModules, "jquery.shorten/src/jquery.shorten.min.js"),
dest: vendored,
},
],
}),
],
optimizeDeps: {
include: ["jquery"],
},
} satisfies UserConfig;

View File

@ -1,7 +0,0 @@
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const config = require("./webpack.config.js");
module.exports = {
...config,
plugins: [...config.plugins, new BundleAnalyzerPlugin()],
};

View File

@ -1,111 +0,0 @@
const glob = require("glob");
// biome-ignore lint/correctness/noNodejsModules: this is backend side
const path = require("node:path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
entry: glob
.sync("./!(static)/static/bundled/**/*?(-)index.[j|t]s?(x)")
.reduce((obj, el) => {
// We include the path inside the bundled folder in the name
let relativePath = [];
const fullPath = path.parse(el);
for (const dir of fullPath.dir.split("/").reverse()) {
if (dir === "bundled") {
break;
}
relativePath.push(dir);
}
// We collected folders in reverse order, we put them back in the original order
relativePath = relativePath.reverse();
relativePath.push(fullPath.name);
obj[relativePath.join("/")] = `./${el}`;
return obj;
}, {}),
cache: {
type: "filesystem", // This reduces typescript compilation time like crazy when you restart the server
},
output: {
filename: "[name].js",
path: path.resolve(__dirname, "./staticfiles/generated/bundled"),
clean: true,
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
},
plugins: [new MiniCssExtractPlugin()],
optimization: {
minimizer: [
"...",
new CssMinimizerPlugin({
parallel: true,
}),
new TerserPlugin({
parallel: true,
terserOptions: {
mangle: true,
compress: {
// biome-ignore lint/style/useNamingConvention: this is how the underlying library wants it
drop_console: true,
},
},
}),
],
},
module: {
rules: [
{
test: /\.css$/,
sideEffects: true,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
{
test: /\.(jpe?g|png|gif)$/i,
type: "asset/resource",
},
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
cacheDirectory: true,
},
},
},
{
test: /\.js$/,
enforce: "pre",
use: ["source-map-loader"],
},
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
{
test: require.resolve("jquery"),
loader: "expose-loader",
options: {
exposes: [
{
globalName: ["$"],
override: true,
},
{
globalName: ["jQuery"],
override: true,
},
{
globalName: ["window.jQuery"],
override: true,
},
],
},
},
],
},
};