mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 08:09:18 +02:00
Add biome + rolldown + lightningcss build pipeline for JS/CSS bundling & minification
- package.json with biome, rolldown, lightningcss devDependencies
- biome.json: add CSS formatter support
- scripts/build-css.mjs: lightningcss resolves @import chain, bundles/minifies CSS
- scripts/build-js.mjs: rolldown per-entry JS bundling (no code splitting)
- scripts/build.mjs: orchestrator for both CSS + JS
- scripts/check-build.mjs: staleness checker for CI/deploy guard
- justfile: add build, build-css, build-js, build-install, build-check recipes
- justfile: deploy recipe now runs build before deploy-code
- head.php + form-page.php: use dist/base.min.css instead of style.css
- All controllers + FormBootstrap: reference dist/*.min.{css,js}
- admin footer: load admin.min.js for all admin pages
- repertoire: use public.min.js instead of individual app JS files
- Fix stray '}' syntax error in admin.css line 305
- .gitignore: add app/public/assets/dist/
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -49,6 +49,9 @@ Thumbs.db
|
||||
|
||||
/node_modules
|
||||
|
||||
# Build output
|
||||
app/public/assets/dist/
|
||||
|
||||
# PHPStan cache
|
||||
.phpstan.result.cache
|
||||
|
||||
|
||||
18
TODO.md
18
TODO.md
@@ -1,14 +1,25 @@
|
||||
# TODO
|
||||
|
||||
> Last updated: 2026-06-24
|
||||
> Context: Inline JS/CSS + gzip analysis (see docs/ANALYSIS_INLINE_JS_CSS_MINIFY.md)
|
||||
> Context: Setup biome + rolldown + lightningcss build pipeline for JS/CSS bundling & minification
|
||||
|
||||
## Completed
|
||||
- [x] #build-pipeline Setup biome + rolldown + lightningcss build pipeline ✓
|
||||
- [x] #build-packagejson Create package.json with devDependencies ✓
|
||||
- [x] #build-biomecss Update biome.json to handle CSS formatting ✓
|
||||
- [x] #build-rolldown-config Create rolldown.config.mjs + build-js.mjs for JS bundling ✓
|
||||
- [x] #build-lightningcss Add lightningcss CSS bundling (resolve @import chain) ✓
|
||||
- [x] #build-justfile Add just build/deploy recipes + integrate build into deploy ✓
|
||||
- [x] #build-head Update head.php + form-page.php + controllers to use bundled assets ✓
|
||||
- [x] #build-gitignore Add dist/ to .gitignore ✓
|
||||
- [x] #build-cssfix Fix stray `}` syntax error in admin.css line 305 ✓
|
||||
|
||||
## Pending
|
||||
- [ ] #rep-student-touch Replace hover student popover with tap-to-open drawer for mobile `(repertoire.php, repertoire.css)`
|
||||
- [ ] #rep-polish Polish: scroll-position memory on HTMX swap, animation tuning `(repertoire.css)`
|
||||
- [ ] #icon-color-verify Verify icon colors render correctly across all pages (header, admin tables, forms, dialogs, cleanup modal)
|
||||
|
||||
## Completed
|
||||
## Completed (before this session)
|
||||
- [x] #gzip-nginx Enable gzip compression in nginx config `(nginx/xamxam.conf)` ✓
|
||||
- [x] #extract-inline-js Move inline JS to external files across 17 templates → 15 new JS files created `(app/public/assets/js/app/*.js)` ✓
|
||||
- [x] #inline-icon-helper Create `icon()` PHP helper + auto-load in bootstrap `(src/icon.php, bootstrap.php)` ✓
|
||||
@@ -63,7 +74,4 @@
|
||||
- [x] #extra-css-admin Update `head.php` to support `$extraCssAdmin` for admin-only stylesheets `(head.php)` ✓
|
||||
|
||||
## Deferred / Blocked
|
||||
- [ ] #minify-js Minify custom JS files (post-extraction, ~1,763 lines across 9 files)
|
||||
- [ ] #bundle-css Bundle CSS to eliminate @import waterfall (18 files, ~6,200 lines)
|
||||
- [ ] #build-step Add build step (justfile commands) for JS minification + CSS bundling
|
||||
- [ ] #tighten-csp Tighten CSP to remove 'unsafe-inline' after inline JS extraction
|
||||
|
||||
@@ -514,8 +514,8 @@ if ($isHtmx) {
|
||||
include APP_ROOT . '/templates/admin/index-table.php';
|
||||
}
|
||||
} else {
|
||||
$extraCssAdmin = ['/assets/css/filepond.min.css', '/assets/css/filepond-plugin-image-preview.min.css'];
|
||||
$extraJs = ['/assets/js/vendor/filepond.min.js', '/assets/js/vendor/filepond-plugin-file-validate-type.min.js', '/assets/js/vendor/filepond-plugin-file-validate-size.min.js', '/assets/js/vendor/filepond-plugin-image-preview.min.js', '/assets/js/vendor/filepond-plugin-image-exif-orientation.min.js', '/assets/js/app/file-upload-filepond.js'];
|
||||
$extraCssAdmin = [];
|
||||
$extraJs = ['/assets/js/vendor/filepond.min.js', '/assets/js/vendor/filepond-plugin-file-validate-type.min.js', '/assets/js/vendor/filepond-plugin-file-validate-size.min.js', '/assets/js/vendor/filepond-plugin-image-preview.min.js', '/assets/js/vendor/filepond-plugin-image-exif-orientation.min.js', '/assets/dist/admin.min.js'];
|
||||
require_once APP_ROOT . '/templates/head.php';
|
||||
include APP_ROOT . '/templates/header.php';
|
||||
if ($tab === 'trash') {
|
||||
|
||||
@@ -74,7 +74,7 @@ if (empty($_SESSION['csrf_token'])) {
|
||||
}
|
||||
|
||||
$isAdmin = true; $bodyClass = 'admin-body';
|
||||
$extraCssAdmin = ['/assets/css/system.css'];
|
||||
$extraCssAdmin = ['/assets/dist/system.min.css'];
|
||||
require_once APP_ROOT . '/templates/head.php';
|
||||
include APP_ROOT . '/templates/header.php';
|
||||
include APP_ROOT . '/templates/admin/parametres.php';
|
||||
|
||||
@@ -302,7 +302,6 @@
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Table ──────────────────────────────────────────────────────────────── */
|
||||
/* Base table/th/td styles live in components/tables.css */
|
||||
|
||||
28
app/public/assets/js/app/admin-entry.js
Normal file
28
app/public/assets/js/app/admin-entry.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Admin JS entry — all JS needed on admin pages.
|
||||
*
|
||||
* Import order matters for dependencies:
|
||||
* - htmx-global-setup must come first (HTMX event listeners)
|
||||
* - Vendor scripts (htmx, FilePond) are loaded separately via <script> tags
|
||||
*/
|
||||
|
||||
// Core utilities (no deps)
|
||||
import "./beforeunload-guard.js";
|
||||
import "./clipboard.js";
|
||||
import "./smtp-error-focus.js";
|
||||
|
||||
// HTMX-powered features (htmx is a global from vendor script)
|
||||
import "./htmx-global-setup.js";
|
||||
|
||||
// Admin features
|
||||
import "./admin-index-bulk.js";
|
||||
import "./admin-tags.js";
|
||||
import "./admin-contenus-langues.js";
|
||||
import "./admin-contenus-motscles.js";
|
||||
import "./admin-contacts-form.js";
|
||||
import "./admin-acces.js";
|
||||
import "./admin-acces-sharelink.js";
|
||||
import "./admin-file-access.js";
|
||||
import "./admin-toc.js";
|
||||
import "./admin-logs.js";
|
||||
import "./sidebar-links-editor.js";
|
||||
17
app/public/assets/js/app/form-entry.js
Normal file
17
app/public/assets/js/app/form-entry.js
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Form JS entry — form-specific JS for admin form pages (add/edit).
|
||||
*
|
||||
* Admin baseline JS (admin.min.js) is loaded separately via the admin footer.
|
||||
* This bundle only includes form-specific features.
|
||||
*
|
||||
* Vendor scripts (htmx, FilePond, OverType) are loaded separately via <script> tags.
|
||||
*/
|
||||
|
||||
// Form-specific features (admin.min.js provides htmx-global-setup, beforeunload-guard, etc.)
|
||||
import "./file-upload-filepond.js";
|
||||
import "./pill-search.js";
|
||||
import "./jury-autocomplete.js";
|
||||
import "./autosave-handler.js";
|
||||
import "./form-duration-toggle.js";
|
||||
import "./form-jury-fields.js";
|
||||
import "./form-language-asterisk.js";
|
||||
17
app/public/assets/js/app/partage-entry.js
Normal file
17
app/public/assets/js/app/partage-entry.js
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Partage (student share) JS entry — all JS needed on partage form pages.
|
||||
*
|
||||
* Vendor scripts (htmx, FilePond) are loaded separately via <script> tags.
|
||||
*/
|
||||
|
||||
// Core utilities
|
||||
import "./beforeunload-guard.js";
|
||||
|
||||
// Form-specific features
|
||||
import "./file-upload-filepond.js";
|
||||
import "./pill-search.js";
|
||||
import "./jury-autocomplete.js";
|
||||
import "./autosave-handler.js";
|
||||
import "./form-duration-toggle.js";
|
||||
import "./form-jury-fields.js";
|
||||
import "./form-language-asterisk.js";
|
||||
19
app/public/assets/js/app/public-entry.js
Normal file
19
app/public/assets/js/app/public-entry.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Public JS entry — all JS needed on public-facing pages.
|
||||
*
|
||||
* Import order matters.
|
||||
* Vendor scripts (htmx) are loaded separately via <script> tags.
|
||||
*/
|
||||
|
||||
// Core utilities
|
||||
import "./beforeunload-guard.js";
|
||||
import "./clipboard.js";
|
||||
|
||||
// HTMX-powered features
|
||||
import "./htmx-global-setup.js";
|
||||
|
||||
// Public page features
|
||||
import "./repertoire-accordion.js";
|
||||
import "./repertoire-student-popover.js";
|
||||
import "./access-request.js";
|
||||
import "./acces-password.js";
|
||||
@@ -55,7 +55,7 @@ class AboutController
|
||||
'sidebarLinks' => $sidebarLinks,
|
||||
'pageTitle' => 'À Propos – XAMXAM',
|
||||
'metaDescription' => "À propos de XAMXAM, le répertoire des mémoires de fin d'études de l'erg – École de Recherches Graphiques de Bruxelles.",
|
||||
'extraCss' => ['/assets/css/content-page.css'],
|
||||
'extraCss' => ['/assets/dist/content-page.min.css'],
|
||||
'bodyClass' => 'apropos-body',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class CharteController
|
||||
'pageTitle' => $pageTitle . ' – XAMXAM',
|
||||
'metaDescription' => "Charte d'utilisation de XAMXAM, le répertoire des TFE de l'erg.",
|
||||
'currentNav' => 'charte',
|
||||
'extraCss' => ['/assets/css/content-page.css'],
|
||||
'extraCss' => ['/assets/dist/content-page.min.css'],
|
||||
'bodyClass' => 'apropos-body',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ class HomeController
|
||||
|
||||
// Layout
|
||||
'currentNav' => '',
|
||||
'extraCss' => ['/assets/css/public.css'],
|
||||
'extraCss' => ['/assets/dist/public.min.css'],
|
||||
'bodyClass' => 'home-body',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class LicenceController
|
||||
'pageTitle' => $pageTitle . ' – XAMXAM',
|
||||
'metaDescription' => "Informations sur les licences d'utilisation des mémoires publiés sur XAMXAM, le répertoire des TFE de l'erg.",
|
||||
'currentNav' => 'licence',
|
||||
'extraCss' => ['/assets/css/content-page.css'],
|
||||
'extraCss' => ['/assets/dist/content-page.min.css'],
|
||||
'bodyClass' => 'apropos-body',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ class SearchController
|
||||
'site_name' => 'XAMXAM – ERG',
|
||||
],
|
||||
'currentNav' => 'repertoire',
|
||||
'extraCss' => ['/assets/css/repertoire.css'],
|
||||
'extraCss' => ['/assets/dist/repertoire.min.css'],
|
||||
'bodyClass' => 'search-body',
|
||||
];
|
||||
}
|
||||
@@ -205,7 +205,7 @@ class SearchController
|
||||
'site_name' => 'XAMXAM – ERG',
|
||||
],
|
||||
'currentNav' => 'repertoire',
|
||||
'extraCss' => ['/assets/css/repertoire.css'],
|
||||
'extraCss' => ['/assets/dist/repertoire.min.css'],
|
||||
'bodyClass' => 'search-body',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -146,8 +146,8 @@ class TfeController
|
||||
|
||||
// Layout
|
||||
'currentNav' => '',
|
||||
'extraCss' => ['/assets/css/tfe.css'],
|
||||
'extraJs' => ['/assets/js/app/access-request.js'],
|
||||
'extraCss' => ['/assets/dist/tfe.min.css'],
|
||||
'extraJs' => ['/assets/dist/public.min.js'],
|
||||
'bodyClass' => 'tfe-body',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -16,23 +16,15 @@ class FormBootstrap
|
||||
public static function adminAssetArrays(): array
|
||||
{
|
||||
return [
|
||||
'extraCss' => ['/assets/css/form-base.css'],
|
||||
'extraCssAdmin' => [
|
||||
'/assets/css/form-admin.css',
|
||||
'/assets/css/filepond.min.css',
|
||||
'/assets/css/filepond-plugin-image-preview.min.css',
|
||||
],
|
||||
'extraCss' => ['/assets/dist/form.min.css'],
|
||||
'extraCssAdmin' => [],
|
||||
'extraJs' => [
|
||||
'/assets/js/vendor/filepond.min.js',
|
||||
'/assets/js/vendor/filepond-plugin-file-validate-type.min.js',
|
||||
'/assets/js/vendor/filepond-plugin-file-validate-size.min.js',
|
||||
'/assets/js/vendor/filepond-plugin-image-preview.min.js',
|
||||
'/assets/js/vendor/filepond-plugin-image-exif-orientation.min.js',
|
||||
'/assets/js/app/file-upload-filepond.js',
|
||||
'/assets/js/app/beforeunload-guard.js',
|
||||
'/assets/js/app/pill-search.js',
|
||||
'/assets/js/app/jury-autocomplete.js',
|
||||
'/assets/js/app/autosave-handler.js',
|
||||
'/assets/dist/form.min.js',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -17,6 +17,6 @@
|
||||
<script><?= $extraJsInline ?></script>
|
||||
<?php endif; ?>
|
||||
<script src="/assets/js/vendor/htmx.min.js"></script>
|
||||
<script src="<?= App::assetV('/assets/js/app/htmx-global-setup.js') ?>"></script>
|
||||
<script src="<?= App::assetV('/assets/dist/admin.min.js') ?>"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
// Admin: append suffix to title and prepend admin.css
|
||||
if (!empty($isAdmin)) {
|
||||
$pageTitle = isset($pageTitle) ? $pageTitle . ' – Admin' : 'Admin';
|
||||
$extraCss = array_merge(['/assets/css/admin.css'], $extraCssAdmin ?? [], $extraCss ?? []);
|
||||
$extraCss = array_merge(['/assets/dist/admin.min.css'], $extraCssAdmin ?? [], $extraCss ?? []);
|
||||
}
|
||||
?>
|
||||
<title><?= htmlspecialchars($pageTitle ?? 'XAMXAM') ?></title>
|
||||
@@ -70,7 +70,7 @@
|
||||
<?php if (!empty($isAdmin) || !empty($filepondBase)): ?>
|
||||
<meta name="filepond-base" content="<?= htmlspecialchars($filepondBase ?? '/admin/actions/filepond') ?>">
|
||||
<?php endif; ?>
|
||||
<link rel="stylesheet" href="<?= App::assetV('/assets/css/style.css') ?>">
|
||||
<link rel="stylesheet" href="<?= App::assetV('/assets/dist/base.min.css') ?>">
|
||||
<?php foreach ($extraCss ?? [] as $css): ?>
|
||||
<link rel="stylesheet" href="<?= App::assetV($css) ?>">
|
||||
<?php endforeach; ?>
|
||||
|
||||
@@ -37,11 +37,11 @@ $filepondBase = $filepondBase ?? null;
|
||||
<?php if ($filepondBase !== null): ?>
|
||||
<meta name="filepond-base" content="<?= htmlspecialchars($filepondBase) ?>">
|
||||
<?php endif; ?>
|
||||
<link rel="stylesheet" href="<?= App::assetV('/assets/css/style.css') ?>">
|
||||
<link rel="stylesheet" href="<?= App::assetV('/assets/css/form-base.css') ?>">
|
||||
<link rel="stylesheet" href="<?= App::assetV('/assets/dist/base.min.css') ?>">
|
||||
<?php if ($includeFilePond): ?>
|
||||
<link rel="stylesheet" href="<?= App::assetV('/assets/css/filepond.min.css') ?>">
|
||||
<link rel="stylesheet" href="<?= App::assetV('/assets/css/filepond-plugin-image-preview.min.css') ?>">
|
||||
<link rel="stylesheet" href="<?= App::assetV('/assets/dist/partage-form.min.css') ?>">
|
||||
<?php else: ?>
|
||||
<link rel="stylesheet" href="<?= App::assetV('/assets/dist/form-base.min.css') ?>">
|
||||
<?php endif; ?>
|
||||
<?php foreach ($extraCss as $css): ?>
|
||||
<link rel="stylesheet" href="<?= App::assetV($css) ?>">
|
||||
@@ -52,14 +52,10 @@ $filepondBase = $filepondBase ?? null;
|
||||
<script src="<?= App::assetV('/assets/js/vendor/filepond-plugin-file-validate-size.min.js') ?>" defer></script>
|
||||
<script src="<?= App::assetV('/assets/js/vendor/filepond-plugin-image-preview.min.js') ?>" defer></script>
|
||||
<script src="<?= App::assetV('/assets/js/vendor/filepond-plugin-image-exif-orientation.min.js') ?>" defer></script>
|
||||
<script src="<?= App::assetV('/assets/js/app/file-upload-filepond.js') ?>" defer></script>
|
||||
<?php endif; ?>
|
||||
<script src="<?= App::assetV('/assets/js/app/beforeunload-guard.js') ?>" defer></script>
|
||||
<?php if ($includeFilePond): ?>
|
||||
<script src="<?= App::assetV('/assets/js/app/pill-search.js') ?>" defer></script>
|
||||
<script src="<?= App::assetV('/assets/js/app/jury-autocomplete.js') ?>" defer></script>
|
||||
<script src="<?= App::assetV('/assets/js/app/autosave-handler.js') ?>" defer></script>
|
||||
<script src="<?= App::assetV('/assets/js/vendor/htmx.min.js') ?>" defer></script>
|
||||
<script src="<?= App::assetV('/assets/dist/partage.min.js') ?>" defer></script>
|
||||
<?php else: ?>
|
||||
<script src="<?= App::assetV('/assets/dist/public.min.js') ?>" defer></script>
|
||||
<?php endif; ?>
|
||||
<?php foreach ($extraJs as $js): ?>
|
||||
<script src="<?= App::assetV($js) ?>" defer></script>
|
||||
|
||||
@@ -7,5 +7,4 @@
|
||||
<div id="student-popover" class="student-popover" hidden aria-live="polite"></div>
|
||||
|
||||
<script src="/assets/js/vendor/htmx.min.js"></script>
|
||||
<script src="<?= App::assetV('/assets/js/app/repertoire-student-popover.js') ?>"></script>
|
||||
<script src="<?= App::assetV('/assets/js/app/repertoire-accordion.js') ?>"></script>
|
||||
<script src="<?= App::assetV('/assets/dist/public.min.js') ?>"></script>
|
||||
|
||||
11
biome.json
11
biome.json
@@ -10,6 +10,14 @@
|
||||
"!app/public/assets/js/vendor/**"
|
||||
]
|
||||
},
|
||||
"css": {
|
||||
"formatter": {
|
||||
"enabled": true
|
||||
},
|
||||
"linter": {
|
||||
"enabled": false
|
||||
}
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
@@ -17,6 +25,7 @@
|
||||
}
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true
|
||||
"enabled": true,
|
||||
"includes": ["**/*.js", "**/*.css"]
|
||||
}
|
||||
}
|
||||
|
||||
27
justfile
27
justfile
@@ -32,12 +32,37 @@ stop:
|
||||
logs:
|
||||
@tail -n 20 error.log 2>/dev/null || echo "no error log"
|
||||
|
||||
# ============================================================================
|
||||
# Build (JS/CSS bundling & minification)
|
||||
# ============================================================================
|
||||
|
||||
[group('build')]
|
||||
build:
|
||||
@node scripts/build.mjs
|
||||
|
||||
[group('build')]
|
||||
build-css:
|
||||
@node scripts/build-css.mjs
|
||||
|
||||
[group('build')]
|
||||
build-js:
|
||||
@node scripts/build-js.mjs
|
||||
|
||||
[group('build')]
|
||||
build-install:
|
||||
@npm ci
|
||||
|
||||
[group('build')]
|
||||
build-check:
|
||||
@echo "Checking if build output is up to date…"
|
||||
@node scripts/check-build.mjs
|
||||
|
||||
# ============================================================================
|
||||
# Deploy
|
||||
# ============================================================================
|
||||
|
||||
[group('deploy')]
|
||||
deploy: deploy-code deploy-deps deploy-migrate
|
||||
deploy: build deploy-code deploy-deps deploy-migrate
|
||||
@just deploy-env
|
||||
@just deploy-verify-permissions
|
||||
@echo ""
|
||||
|
||||
829
package-lock.json
generated
Normal file
829
package-lock.json
generated
Normal file
@@ -0,0 +1,829 @@
|
||||
{
|
||||
"name": "xamxam",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "xamxam",
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.3.15",
|
||||
"lightningcss": "^1.32.0",
|
||||
"rolldown": "^1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/biome": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.5.1.tgz",
|
||||
"integrity": "sha512-IXWLCxKmae+rI7LOHS1B3EbVisQ6GRAWbhN9msa6KjNCyFWrvKZWR4oUdinaNssrV852OrSHuSPa95h1GPJc7Q==",
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"bin": {
|
||||
"biome": "bin/biome"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/biome"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@biomejs/cli-darwin-arm64": "2.5.1",
|
||||
"@biomejs/cli-darwin-x64": "2.5.1",
|
||||
"@biomejs/cli-linux-arm64": "2.5.1",
|
||||
"@biomejs/cli-linux-arm64-musl": "2.5.1",
|
||||
"@biomejs/cli-linux-x64": "2.5.1",
|
||||
"@biomejs/cli-linux-x64-musl": "2.5.1",
|
||||
"@biomejs/cli-win32-arm64": "2.5.1",
|
||||
"@biomejs/cli-win32-x64": "2.5.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-darwin-arm64": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.1.tgz",
|
||||
"integrity": "sha512-npqDzvqv7vFaWRiNN1Te71siRgPaqS9MpqgYCdP/CrUbkJ7ApezaeaKjueKHRN/JH/6lRjJQAHi8acQDCAz22w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-darwin-x64": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.1.tgz",
|
||||
"integrity": "sha512-RgwTqPAM8g2tn1j+b5oRjF/DbSBX8a4gwojtuG9XuhfK7GgomvZ9+T+tqjXiVbjLEeGJOoL6VEk8mvRTVeSybw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-arm64": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.1.tgz",
|
||||
"integrity": "sha512-yhV35CzZh38VyMvTEXi3JTjxZBs++oCKK9KG8vB6VI5+uvQvZNR3BFWEKKzuOmx9DJJj7sQpZ4LQJcmbGTs3+Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-arm64-musl": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.1.tgz",
|
||||
"integrity": "sha512-WMcvMLgByyTqVxGlq918NBBYliq9FRR9GAQVETHb+VjGVqXCZFfHlZHC1FX4ibuYY/Hg6TJE3rHU0xVrdJXNRw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-x64": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.1.tgz",
|
||||
"integrity": "sha512-J/7uHSX7NfoYDI7HijAkd8lnQIOrRb2W7j3X+tw4R+N5ExvXGsyXFiGdQcfcxfOmNQmZVSQOCDk757fwpzqQcg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-linux-x64-musl": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.1.tgz",
|
||||
"integrity": "sha512-ANTowtlLmPYm5yeMckWY8Xzb9Ix+JJP3tgHR/n6xRj1VWyIzzWtfRfih9hv9VmClwadpBvZduISZIbBsIlYG3A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-win32-arm64": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.1.tgz",
|
||||
"integrity": "sha512-zgXnKNgWPC4iPF7Y1lR3STUeCUuZRpD6IiOrC7TZTlh0Lx6FiVUT05myuMQHQ9D+1cc7uyMldi4forE6lp0ivQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@biomejs/cli-win32-x64": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.1.tgz",
|
||||
"integrity": "sha512-6uxpR9hvaglANkZemeSiN/FhYgkGasrEGn267eXIWvjrjJ2LhDlk251IhjVJq6MXzkV2/bcXwLwSroLyPtqRZg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=14.21.3"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
|
||||
"integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/wasi-threads": "1.2.2",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "1.11.1",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz",
|
||||
"integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/wasi-threads": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
|
||||
"integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz",
|
||||
"integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@tybys/wasm-util": "^0.10.3"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Brooooooklyn"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emnapi/core": "^1.7.1",
|
||||
"@emnapi/runtime": "^1.7.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@oxc-project/types": {
|
||||
"version": "0.137.0",
|
||||
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.137.0.tgz",
|
||||
"integrity": "sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/Boshen"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-android-arm64": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.3.tgz",
|
||||
"integrity": "sha512-DT6Z3PhvioeHMvxo+xHc3KtqggrI7CCTXCmC2h/5zUlp5jVitv7XEy+9q5/7v8IolhlioawpMo8Kg0EEBy7J0g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-arm64": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.3.tgz",
|
||||
"integrity": "sha512-0NwgwsjM7LrsuVnXMK3koTpagBNOhloc/BNjKqZjv4V5zI5r13qx69uVhRx+o5Z0yy4Hzq+lpy7TAgUG/ocvrw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-darwin-x64": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.3.tgz",
|
||||
"integrity": "sha512-YtiBp4disu6V560loT6PjMdiRaWmVvDNrUunAalbiFx2ggeJwxdAsgZMcoGP17uyAsTwAj5V1niksxlHnVQ1Sw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-freebsd-x64": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.3.tgz",
|
||||
"integrity": "sha512-yD3EkEdXk2LypPxnf/kSZHirarsI8gcPzc62SukhR9VJTyvV+F9Q/GxWNuCojc7sXyuVC4DxRGhdDK4X8VSsbw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.3.tgz",
|
||||
"integrity": "sha512-c+8vieQbsD7HNAHKIA34w0GJ9FedFFuJGD+7E6vz7Q3uqAIugL5p45fhlsj4UaAsHpcmlqugBWMhA0/j7o0sIg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-gnu": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.3.tgz",
|
||||
"integrity": "sha512-50jD0uUwLvur7Zz9LHz17kaAdTPjn5wN93hEgjvmYFRZwiR7ZJYovTd5ipyWJDAnXKvZ+wgc+/Ika6dwSF5OcA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-arm64-musl": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.3.tgz",
|
||||
"integrity": "sha512-BO9+oPL8K9poZJBfYPsXNtYjPE5uM3qeehT3aFcW4LITOl+iSqhp0abzjR2nWBUNjIZeKXjAEWBZ64WjNoHd6w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.3.tgz",
|
||||
"integrity": "sha512-f3VpLB1vQ0Eo6ecr/6cekLnvYMFF4YBFoVGkfkvPLq1bAkbAwHYQPZKoAmG6OJyTcxxoC+AvezGx/S1obNC0Mw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-s390x-gnu": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.3.tgz",
|
||||
"integrity": "sha512-AmurZ26Pqx/RI9N1gzEOCklkKXl927yjfXWUUS0O7Puh8ARM/Ob8qfrD3qnWksScdw6cSrW5PSHE9DyLu7+PtA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-gnu": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.3.tgz",
|
||||
"integrity": "sha512-JJpqs8bRGITDOdbkNKnlojzBabbOHrqjSvDr0IVsZObE1lBcPjxItUEY9eWIDbxaJ3cGrXPWGfGkIxFijg/URg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-linux-x64-musl": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.3.tgz",
|
||||
"integrity": "sha512-rSJcdjPxzA/by/6/rYs+v+bXU7UjvnbUWz8MJb6kh6+knqB1dCrtHg0uu7C/4haqJvqdkYHQ5IGn+tCH9GLW/g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-openharmony-arm64": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.3.tgz",
|
||||
"integrity": "sha512-hQ3/PYkDJICgevvyNcVrihVeqq7k1Pp3VZ9lY+dauAYUJKO+auqApvANhvR1An9BhmqYKvW2Mu1F9u4DXSMLxQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openharmony"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-wasm32-wasi": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.3.tgz",
|
||||
"integrity": "sha512-Elcv/BtML9lXrV6JuKITc/grN2kYV9gjsQpW8Jfw4ioK0TOkjBjye0nnyqQNy9STNaI20lXNaQBRrD5gSgR0Yg==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/core": "1.11.1",
|
||||
"@emnapi/runtime": "1.11.1",
|
||||
"@napi-rs/wasm-runtime": "^1.1.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-arm64-msvc": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.3.tgz",
|
||||
"integrity": "sha512-2DrEfhluH9yhiaFApmsjsjwrSYbNcY1oFTzYSP1a535jDbV98zCFanA/96TBUd0iDFcxGmw9QRExwGCXz3U+/g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/binding-win32-x64-msvc": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.3.tgz",
|
||||
"integrity": "sha512-OL4OMk7UPXOeVGGd3qo5zJyPIljf4AFgk5QAkPPS+OoLuOOozhuaQGC18MxVTnw/06q93gShAJzlwnSCY9YtqA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz",
|
||||
"integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@tybys/wasm-util": {
|
||||
"version": "0.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz",
|
||||
"integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
|
||||
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz",
|
||||
"integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==",
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"lightningcss-android-arm64": "1.32.0",
|
||||
"lightningcss-darwin-arm64": "1.32.0",
|
||||
"lightningcss-darwin-x64": "1.32.0",
|
||||
"lightningcss-freebsd-x64": "1.32.0",
|
||||
"lightningcss-linux-arm-gnueabihf": "1.32.0",
|
||||
"lightningcss-linux-arm64-gnu": "1.32.0",
|
||||
"lightningcss-linux-arm64-musl": "1.32.0",
|
||||
"lightningcss-linux-x64-gnu": "1.32.0",
|
||||
"lightningcss-linux-x64-musl": "1.32.0",
|
||||
"lightningcss-win32-arm64-msvc": "1.32.0",
|
||||
"lightningcss-win32-x64-msvc": "1.32.0"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-android-arm64": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz",
|
||||
"integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-darwin-arm64": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz",
|
||||
"integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-darwin-x64": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz",
|
||||
"integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-freebsd-x64": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz",
|
||||
"integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm-gnueabihf": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz",
|
||||
"integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm64-gnu": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz",
|
||||
"integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm64-musl": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz",
|
||||
"integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-x64-gnu": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz",
|
||||
"integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-x64-musl": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz",
|
||||
"integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-win32-arm64-msvc": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz",
|
||||
"integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-win32-x64-msvc": {
|
||||
"version": "1.32.0",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz",
|
||||
"integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/parcel"
|
||||
}
|
||||
},
|
||||
"node_modules/rolldown": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.3.tgz",
|
||||
"integrity": "sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@oxc-project/types": "=0.137.0",
|
||||
"@rolldown/pluginutils": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"rolldown": "bin/cli.mjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || >=22.12.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rolldown/binding-android-arm64": "1.1.3",
|
||||
"@rolldown/binding-darwin-arm64": "1.1.3",
|
||||
"@rolldown/binding-darwin-x64": "1.1.3",
|
||||
"@rolldown/binding-freebsd-x64": "1.1.3",
|
||||
"@rolldown/binding-linux-arm-gnueabihf": "1.1.3",
|
||||
"@rolldown/binding-linux-arm64-gnu": "1.1.3",
|
||||
"@rolldown/binding-linux-arm64-musl": "1.1.3",
|
||||
"@rolldown/binding-linux-ppc64-gnu": "1.1.3",
|
||||
"@rolldown/binding-linux-s390x-gnu": "1.1.3",
|
||||
"@rolldown/binding-linux-x64-gnu": "1.1.3",
|
||||
"@rolldown/binding-linux-x64-musl": "1.1.3",
|
||||
"@rolldown/binding-openharmony-arm64": "1.1.3",
|
||||
"@rolldown/binding-wasm32-wasi": "1.1.3",
|
||||
"@rolldown/binding-win32-arm64-msvc": "1.1.3",
|
||||
"@rolldown/binding-win32-x64-msvc": "1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true,
|
||||
"license": "0BSD",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
15
package.json
Normal file
15
package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "xamxam",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "node scripts/build.mjs",
|
||||
"build:css": "node scripts/build-css.mjs",
|
||||
"build:js": "node scripts/build-js.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.3.15",
|
||||
"lightningcss": "^1.32.0",
|
||||
"rolldown": "^1.1.3"
|
||||
}
|
||||
}
|
||||
43
rolldown.config.mjs
Normal file
43
rolldown.config.mjs
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Rolldown configuration for XAMXAM JS bundling.
|
||||
*
|
||||
* Entry points:
|
||||
* - admin.js → all JS needed on admin pages
|
||||
* - public.js → all JS needed on public-facing pages
|
||||
* - form.js → all JS needed on admin form pages (add/edit)
|
||||
*
|
||||
* Vendor scripts (htmx, FilePond plugins, OverType) are NOT bundled —
|
||||
* they're already minified and served from vendor/.
|
||||
*
|
||||
* Output: app/public/assets/dist/[name].min.js
|
||||
*/
|
||||
|
||||
import { defineConfig } from "rolldown";
|
||||
import { resolve, dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const root = __dirname;
|
||||
const jsDir = resolve(root, "app/public/assets/js/app");
|
||||
const distDir = resolve(root, "app/public/assets/dist");
|
||||
|
||||
export default defineConfig({
|
||||
input: {
|
||||
admin: resolve(jsDir, "admin-entry.js"),
|
||||
public: resolve(jsDir, "public-entry.js"),
|
||||
form: resolve(jsDir, "form-entry.js"),
|
||||
partage: resolve(jsDir, "partage-entry.js"),
|
||||
},
|
||||
output: {
|
||||
dir: distDir,
|
||||
format: "esm",
|
||||
entryFileNames: "[name].min.js",
|
||||
// Disable code splitting — each entry gets its own self-contained bundle.
|
||||
codeSplitting: false,
|
||||
// rolldown built-in minification
|
||||
minify: true,
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".js"],
|
||||
},
|
||||
});
|
||||
152
scripts/build-css.mjs
Normal file
152
scripts/build-css.mjs
Normal file
@@ -0,0 +1,152 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Build CSS bundles with Lightning CSS.
|
||||
*
|
||||
* - base.min.css: resolves the @import chain in style.css into a single minified file.
|
||||
* This eliminates ~17 sequential @import requests on every page.
|
||||
* - admin.min.css: minifies admin.css
|
||||
* - form.min.css: bundles form-base.css + form-admin.css + filepond vendor CSS
|
||||
*
|
||||
* All other page-specific CSS files (public.css, tfe.css, repertoire.css, etc.)
|
||||
* are minified in-place as individual files.
|
||||
*
|
||||
* Output: app/public/assets/dist/
|
||||
*/
|
||||
|
||||
import { bundleAsync } from "lightningcss";
|
||||
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
||||
import { resolve, dirname, basename } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const root = resolve(__dirname, "..");
|
||||
const cssDir = resolve(root, "app/public/assets/css");
|
||||
const distDir = resolve(root, "app/public/assets/dist");
|
||||
|
||||
mkdirSync(distDir, { recursive: true });
|
||||
|
||||
const targets = {
|
||||
chrome: 115 << 16,
|
||||
firefox: 115 << 16,
|
||||
safari: 16 << 16,
|
||||
};
|
||||
|
||||
function makeResolver() {
|
||||
return {
|
||||
resolve(specifier, from) {
|
||||
return resolve(dirname(from), specifier);
|
||||
},
|
||||
read(filePath) {
|
||||
return readFileSync(filePath, "utf8");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function bundleCss(filename, outName) {
|
||||
const entryPath = resolve(cssDir, filename);
|
||||
const result = await bundleAsync({
|
||||
filename: entryPath,
|
||||
resolver: makeResolver(),
|
||||
minify: true,
|
||||
sourceMap: false,
|
||||
targets,
|
||||
});
|
||||
const outPath = resolve(distDir, outName);
|
||||
writeFileSync(outPath, result.code);
|
||||
const size = Buffer.byteLength(result.code, "utf8");
|
||||
console.log(` ✓ ${outName} (${size.toLocaleString()} bytes)`);
|
||||
return size;
|
||||
}
|
||||
|
||||
async function concatBundle(filenames, outName) {
|
||||
const parts = [];
|
||||
for (const f of filenames) {
|
||||
const fp = resolve(cssDir, f);
|
||||
parts.push(readFileSync(fp, "utf8"));
|
||||
}
|
||||
const combined = parts.join("\n");
|
||||
|
||||
// Use lightningcss to minify the combined content
|
||||
const result = await bundleAsync({
|
||||
filename: resolve(cssDir, filenames[0]),
|
||||
resolver: {
|
||||
resolve() {
|
||||
throw new Error("unexpected @import in concat bundle");
|
||||
},
|
||||
read(fp) {
|
||||
if (fp === resolve(cssDir, filenames[0])) {
|
||||
return combined;
|
||||
}
|
||||
// Allow vendor CSS @imports within the combined content
|
||||
throw new Error(`unexpected file in concat: ${fp}`);
|
||||
},
|
||||
},
|
||||
minify: true,
|
||||
sourceMap: false,
|
||||
targets,
|
||||
});
|
||||
|
||||
const outPath = resolve(distDir, outName);
|
||||
writeFileSync(outPath, result.code);
|
||||
const size = Buffer.byteLength(result.code, "utf8");
|
||||
console.log(` ✓ ${outName} (${size.toLocaleString()} bytes)`);
|
||||
return size;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log("🎨 Building CSS bundles…\n");
|
||||
|
||||
let total = 0;
|
||||
|
||||
// 1. Base bundle: resolve style.css @import chain
|
||||
total += await bundleCss("style.css", "base.min.css");
|
||||
|
||||
// 2. Admin bundle: just minify admin.css (standalone)
|
||||
total += await bundleCss("admin.css", "admin.min.css");
|
||||
|
||||
// 3. Form bundle: concat + minify form-base.css + form-admin.css + filepond vendor CSS
|
||||
total += await concatBundle(
|
||||
[
|
||||
"form-base.css",
|
||||
"form-admin.css",
|
||||
"filepond.min.css",
|
||||
"filepond-plugin-image-preview.min.css",
|
||||
],
|
||||
"form.min.css"
|
||||
);
|
||||
|
||||
// 4. Individual page-specific CSS files: minify each
|
||||
const individualFiles = [
|
||||
"public.css",
|
||||
"tfe.css",
|
||||
"repertoire.css",
|
||||
"content-page.css",
|
||||
"system.css",
|
||||
"file-access.css",
|
||||
];
|
||||
|
||||
for (const f of individualFiles) {
|
||||
const outName = f.replace(/\.css$/, ".min.css");
|
||||
total += await bundleCss(f, outName);
|
||||
}
|
||||
|
||||
// 5. Form-base standalone (for partage pages without FilePond)
|
||||
total += await bundleCss("form-base.css", "form-base.min.css");
|
||||
|
||||
// 6. Partage bundle: form-base + filepond (for partage pages with FilePond)
|
||||
total += await concatBundle(
|
||||
[
|
||||
"form-base.css",
|
||||
"filepond.min.css",
|
||||
"filepond-plugin-image-preview.min.css",
|
||||
],
|
||||
"partage-form.min.css"
|
||||
);
|
||||
|
||||
console.log(`\n✅ CSS bundles done — ${total.toLocaleString()} bytes total\n`);
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error("❌ CSS build failed:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
64
scripts/build-js.mjs
Normal file
64
scripts/build-js.mjs
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Build JS bundles: one self-contained file per entry point.
|
||||
*
|
||||
* Each bundle includes all its dependencies inline (no code splitting).
|
||||
* Output: app/public/assets/dist/{admin,public,form,partage}.min.js
|
||||
*/
|
||||
|
||||
import { rolldown } from "rolldown";
|
||||
import { resolve, dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { writeFileSync, mkdirSync } from "node:fs";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const root = resolve(__dirname, "..");
|
||||
const jsDir = resolve(root, "app/public/assets/js/app");
|
||||
const distDir = resolve(root, "app/public/assets/dist");
|
||||
|
||||
mkdirSync(distDir, { recursive: true });
|
||||
|
||||
const entries = {
|
||||
admin: resolve(jsDir, "admin-entry.js"),
|
||||
public: resolve(jsDir, "public-entry.js"),
|
||||
form: resolve(jsDir, "form-entry.js"),
|
||||
partage: resolve(jsDir, "partage-entry.js"),
|
||||
};
|
||||
|
||||
async function buildEntry(name, input) {
|
||||
const bundle = await rolldown({
|
||||
input,
|
||||
resolve: { extensions: [".js"] },
|
||||
output: {
|
||||
format: "esm",
|
||||
minify: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { output } = await bundle.generate();
|
||||
// output is an array of OutputChunks; we want the entry chunk
|
||||
const entryChunk = output.find((c) => c.isEntry);
|
||||
if (!entryChunk) {
|
||||
console.error(` ✗ ${name}.min.js — no entry chunk`);
|
||||
return;
|
||||
}
|
||||
|
||||
const outPath = resolve(distDir, `${name}.min.js`);
|
||||
writeFileSync(outPath, entryChunk.code);
|
||||
|
||||
const size = Buffer.byteLength(entryChunk.code, "utf8");
|
||||
console.log(` ✓ ${name}.min.js (${size.toLocaleString()} bytes)`);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log("📦 Building JS bundles…\n");
|
||||
for (const [name, input] of Object.entries(entries)) {
|
||||
await buildEntry(name, input);
|
||||
}
|
||||
console.log("\n✅ JS bundles done\n");
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error("❌ JS build failed:", err);
|
||||
process.exit(1);
|
||||
});
|
||||
48
scripts/build.mjs
Normal file
48
scripts/build.mjs
Normal file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Build all frontend assets: CSS + JS.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/build.mjs # build everything
|
||||
* node scripts/build.mjs --css # CSS only
|
||||
* node scripts/build.mjs --js # JS only
|
||||
*
|
||||
* Requires: npm install (lightningcss-cli, rolldown)
|
||||
*/
|
||||
|
||||
import { execSync } from "node:child_process";
|
||||
import { existsSync } from "node:fs";
|
||||
import { resolve, dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const root = resolve(__dirname, "..");
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const onlyCss = args.includes("--css");
|
||||
const onlyJs = args.includes("--js");
|
||||
const buildAll = !onlyCss && !onlyJs;
|
||||
|
||||
function run(label, cmd) {
|
||||
console.log(`\n📦 ${label}…`);
|
||||
execSync(cmd, {
|
||||
cwd: root,
|
||||
stdio: "inherit",
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure node_modules exist
|
||||
if (!existsSync(resolve(root, "node_modules"))) {
|
||||
console.log("📥 Installing dependencies (npm ci)…");
|
||||
execSync("npm ci", { cwd: root, stdio: "inherit" });
|
||||
}
|
||||
|
||||
if (buildAll || onlyCss) {
|
||||
run("Building CSS bundles", "node scripts/build-css.mjs");
|
||||
}
|
||||
|
||||
if (buildAll || onlyJs) {
|
||||
run("Building JS bundles", "node scripts/build-js.mjs");
|
||||
}
|
||||
|
||||
console.log("\n✅ Build complete\n");
|
||||
82
scripts/check-build.mjs
Normal file
82
scripts/check-build.mjs
Normal file
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Quick check: are dist files present and fresh?
|
||||
* Exits 0 if ok, 1 if missing or stale.
|
||||
*
|
||||
* Staleness: any source file newer than the oldest dist file.
|
||||
*/
|
||||
|
||||
import { statSync, existsSync, readdirSync } from "node:fs";
|
||||
import { resolve, dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const root = resolve(__dirname, "..");
|
||||
const distDir = resolve(root, "app/public/assets/dist");
|
||||
|
||||
const distFiles = readdirSync(distDir).filter(
|
||||
(f) => f.endsWith(".min.css") || f.endsWith(".min.js")
|
||||
);
|
||||
|
||||
if (distFiles.length === 0) {
|
||||
console.error("❌ No dist files found. Run: just build");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Check each dist file exists
|
||||
for (const f of distFiles) {
|
||||
if (!existsSync(resolve(distDir, f))) {
|
||||
console.error(`❌ Missing: dist/${f}. Run: just build`);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Check staleness: any source newer than the oldest dist?
|
||||
function walkDir(dir, ext) {
|
||||
const files = [];
|
||||
const entries = readdirSync(dir, { withFileTypes: true });
|
||||
for (const e of entries) {
|
||||
const full = resolve(dir, e.name);
|
||||
if (e.isDirectory() && e.name !== "components") {
|
||||
files.push(...walkDir(full, ext));
|
||||
} else if (e.isFile() && full.endsWith(ext)) {
|
||||
files.push(full);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
const cssSrcFiles = walkDir(
|
||||
resolve(root, "app/public/assets/css"),
|
||||
".css"
|
||||
).filter((f) => !f.includes("filepond") && !f.includes("modern-normalize"));
|
||||
|
||||
const jsSrcFiles = walkDir(
|
||||
resolve(root, "app/public/assets/js/app"),
|
||||
".js"
|
||||
);
|
||||
|
||||
const srcFiles = [...cssSrcFiles, ...jsSrcFiles];
|
||||
|
||||
const oldestDist = Math.min(
|
||||
...distFiles.map((f) => statSync(resolve(distDir, f)).mtimeMs)
|
||||
);
|
||||
|
||||
let stale = false;
|
||||
for (const f of srcFiles) {
|
||||
try {
|
||||
if (statSync(f).mtimeMs > oldestDist) {
|
||||
console.error(`❌ Stale dist (source newer than output): ${f}`);
|
||||
stale = true;
|
||||
}
|
||||
} catch {
|
||||
// file may not exist (e.g. entry files), skip
|
||||
}
|
||||
}
|
||||
|
||||
if (stale) {
|
||||
console.error("❌ Run: just build");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log("✅ Build output is up to date");
|
||||
Reference in New Issue
Block a user