From 0f990db1eaae4645d35c0fb6a4b348f080b7d7ac Mon Sep 17 00:00:00 2001 From: Sarah Vaupel Date: Fri, 18 Oct 2024 18:06:38 +0200 Subject: [PATCH] build(frontend): rework bundler (esbuild) asset and static file embedding using manifest --- .gitignore | 2 +- config/settings.yml | 6 +- esbuild.config.mjs | 53 ++- package-lock.json | 343 +++++++++++++++++- package.json | 8 +- routes | 5 +- src/Foundation/Instances.hs | 4 +- src/Foundation/SiteLayout.hs | 5 +- src/Settings.hs | 6 +- src/Settings/StaticFiles.hs | 10 +- .../StaticFiles/{Webpack.hs => Bundler.hs} | 33 +- src/Settings/WellKnownFiles/TH.hs | 8 +- 12 files changed, 426 insertions(+), 57 deletions(-) rename src/Settings/StaticFiles/{Webpack.hs => Bundler.hs} (75%) diff --git a/.gitignore b/.gitignore index 08249c6c4..eec19fc73 100644 --- a/.gitignore +++ b/.gitignore @@ -46,7 +46,7 @@ test.log /.stack-work.lock /.npmrc /.npm/ -/config/webpack.yml +/config/manifest.json tunnel.log /static /well-known diff --git a/config/settings.yml b/config/settings.yml index 328b3d24b..04f69e649 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022 Gregor Kleen ,Sarah Vaupel ,Steffen Jost ,Wolfgang Witt +# SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel , Gregor Kleen ,Sarah Vaupel ,Steffen Jost ,Wolfgang Witt # # SPDX-License-Identifier: AGPL-3.0-or-later @@ -9,9 +9,9 @@ static-dir: "_env:STATIC_DIR:static" well-known-dir: "_env:WELL_KNOWN_DIR:well-known" -well-known-link-file: html_code.html +well-known-link-file: include.html -webpack-manifest: "_env:WEBPACK_MANIFEST:config/webpack.yml" +bundler-manifest: "_env:BUNDLER_MANIFEST:config/manifest.json" host: "_env:HOST:*4" # any IPv4 host port: "_env:PORT:3000" ip-from-header: "_env:IP_FROM_HEADER:false" diff --git a/esbuild.config.mjs b/esbuild.config.mjs index 7fb8d74fd..9978e23c0 100644 --- a/esbuild.config.mjs +++ b/esbuild.config.mjs @@ -1,36 +1,65 @@ import * as esbuild from 'esbuild'; import { sassPlugin } from 'esbuild-sass-plugin'; -import svgPlugin from 'esbuild-plugin-svg-bundle'; +// import svgPlugin from 'esbuild-plugin-svg-bundle'; +import svgPlugin from 'esbuild-plugin-svg'; import { copy } from 'esbuild-plugin-copy'; +// import manifestPlugin from 'esbuild-plugin-manifest'; +import manifestPlugin from 'esbuild-plugin-assets-manifest'; +import copyWithHashPlugin from '@enonic/esbuild-plugin-copy-with-hash'; +import inlineImportPlugin from 'esbuild-plugin-inline-import'; + +const staticDir = './static'; +const wellKnownDir = './well-known'; await esbuild.build({ + bundle: true, + minify: true, + sourcemap: true, + entryPoints: { + main: './frontend/src/main.js', + polyfill: './frontend/src/polyfill.js', + }, + outdir: staticDir, plugins: [ sassPlugin(), svgPlugin({ - bundleFile: './svg-bundle.svg', - bundleUrl: './svg-bundle.svg', + minify: true, + // bundleFile: `${wellKnownDir}/svg-bundle.svg`, + // bundleUrl: `${wellKnownDir}/svg-bundle.svg`, }), copy({ resolveFrom: 'cwd', assets: { from: [ './assets/favicons/*' ], - to: [ './static' ], + to: [ `${wellKnownDir}/de-de-formal`, `${wellKnownDir}/en-eu` ], }, }), copy({ resolveFrom: 'cwd', assets: { from: [ './config/robots.txt' ], - to: [ './static' ], + to: [ `${wellKnownDir}/de-de-formal`, `${wellKnownDir}/en-eu` ], }, }), + // ...['de-de-formal','en-eu'].map((lang) => manifestPlugin({ + manifestPlugin({ + filename: 'manifest.json', + path: 'config', + // metadata: { timestamp: new Date(), module: 'myapp', type: 'esm', }, + processOutput(assets) { + const orderAssets = { + main: assets['main'], + ...assets + }; + return JSON.stringify(orderAssets, null, ' '); + }, + }), + /* copyWithHashPlugin({ + patterns: [ + './assets/favicons/*', + './config/robots.txt', + ], + }), */ ], - entryPoints: [ - './frontend/src/main.js', - './frontend/src/polyfill.js', - ], - bundle: true, - minify: true, - outdir: './static', }); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index da44cc198..6e3c048fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-runtime": "^7.25.4", "@babel/preset-env": "^7.25.4", + "@enonic/esbuild-plugin-copy-with-hash": "^0.2.0", "@eslint/js": "^9.9.1", "@fortawesome/fontawesome-free": "^6.6.0", "autoprefixer": "^10.4.20", @@ -45,7 +46,11 @@ "css-loader": "^7.1.2", "css-minimizer-webpack-plugin": "^7.0.0", "esbuild": "0.24.0", + "esbuild-plugin-assets-manifest": "^1.0.8", "esbuild-plugin-copy": "2.1.1", + "esbuild-plugin-inline-import": "^1.1.0", + "esbuild-plugin-manifest": "1.0.4", + "esbuild-plugin-svg": "^0.1.0", "esbuild-plugin-svg-bundle": "1.3.0", "esbuild-sass-plugin": "3.3.1", "eslint": "^9.9.1", @@ -2009,6 +2014,72 @@ "license": "(Apache-2.0 AND BSD-3-Clause)", "peer": true }, + "node_modules/@cjs-exporter/globby": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/@cjs-exporter/globby/-/globby-13.1.3.tgz", + "integrity": "sha512-rxSVbUhNmIYTZKzrtb6cJIUfFk0PDxzeR4+dzi8edKYmmbqRBO/k7N+tW///QmtY6OznemXiLMSZ20E6DHegxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "13.1.3" + } + }, + "node_modules/@cjs-exporter/globby/node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@cjs-exporter/globby/node_modules/globby": { + "version": "13.1.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", + "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@cjs-exporter/globby/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@cjs-exporter/globby/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -3077,6 +3148,21 @@ "node": ">=10.0.0" } }, + "node_modules/@enonic/esbuild-plugin-copy-with-hash": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@enonic/esbuild-plugin-copy-with-hash/-/esbuild-plugin-copy-with-hash-0.2.0.tgz", + "integrity": "sha512-2KX60dKlPx5Q7d3Jz+23hekbHrCTZzvlZC4U+rLZiP3GMbumEq5lmocw5XKLNTvHtRwNlUze+3TwiXSCD46EeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cjs-exporter/globby": "^13.1.3", + "colorette": "^2.0.20", + "xxh3-ts": "^1.0.6" + }, + "peerDependencies": { + "esbuild": "~0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.24.0", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz", @@ -4816,8 +4902,7 @@ "url": "https://feross.org/support" } ], - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/base64id": { "version": "2.0.0", @@ -6287,6 +6372,23 @@ "postcss": "^8.4" } }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/css-tree": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", @@ -6840,6 +6942,21 @@ "void-elements": "^2.0.0" } }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, "node_modules/domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -6865,6 +6982,37 @@ ], "license": "BSD-2-Clause" }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", @@ -7072,6 +7220,16 @@ "node": ">= 0.4" } }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "license": "BSD-2-Clause", + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -7282,6 +7440,16 @@ "@esbuild/win32-x64": "0.24.0" } }, + "node_modules/esbuild-plugin-assets-manifest": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/esbuild-plugin-assets-manifest/-/esbuild-plugin-assets-manifest-1.0.8.tgz", + "integrity": "sha512-2goWUmBLpqaHASkMQIgsSqcAs3Y1rDMKcOjk8cWOTtAzmbHYQLh77MEjuQYDx3bBEQ9dVZCaU0/cBIjhvdJf+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "esbuild": "*" + } + }, "node_modules/esbuild-plugin-copy": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/esbuild-plugin-copy/-/esbuild-plugin-copy-2.1.1.tgz", @@ -7453,6 +7621,36 @@ "node": ">=8" } }, + "node_modules/esbuild-plugin-inline-import": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/esbuild-plugin-inline-import/-/esbuild-plugin-inline-import-1.1.0.tgz", + "integrity": "sha512-b0xX4tPKBdRjX1CkzpnULpEdeTo9vxD+wf83PKvgUYnOEaJfVxLey4q+sfTUPAdDnRRYasJsQUgQW7/e2Gm5Dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild-plugin-manifest": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esbuild-plugin-manifest/-/esbuild-plugin-manifest-1.0.4.tgz", + "integrity": "sha512-z+aDPuNIFZto5cYZhZwYk+aWhSqi8yShxx6Yfz+gqMKu+mIrYRtJztxoI2GNIv9hcsEatn+uInkEbf20kTZLxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "proper-lockfile": "^4.1.2" + }, + "peerDependencies": { + "esbuild": "~0" + } + }, + "node_modules/esbuild-plugin-svg": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/esbuild-plugin-svg/-/esbuild-plugin-svg-0.1.0.tgz", + "integrity": "sha512-/9ZhvIpl+Ovl6glVK3BedvIwrOwSQnECw4Fy6ZwysWib3Ns7UkX6WNGjMOWtvQ1Cnm0uc7sptiKGm0BthKCAJA==", + "dev": true, + "license": "ISC", + "dependencies": { + "svgo": "^2.2.2" + } + }, "node_modules/esbuild-plugin-svg-bundle": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/esbuild-plugin-svg-bundle/-/esbuild-plugin-svg-bundle-1.3.0.tgz", @@ -7514,6 +7712,72 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/esbuild-plugin-svg/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/esbuild-plugin-svg/node_modules/css-tree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz", + "integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.0.14", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esbuild-plugin-svg/node_modules/csso": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", + "integrity": "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esbuild-plugin-svg/node_modules/mdn-data": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz", + "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/esbuild-plugin-svg/node_modules/svgo": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz", + "integrity": "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^4.1.3", + "css-tree": "^1.1.3", + "csso": "^4.2.0", + "picocolors": "^1.0.0", + "stable": "^0.1.8" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/esbuild-sass-plugin": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-3.3.1.tgz", @@ -8934,8 +9198,7 @@ "url": "https://feross.org/support" } ], - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/ignore": { "version": "5.3.2", @@ -15391,6 +15654,25 @@ "license": "MIT", "peer": true }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/proper-lockfile/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -15907,6 +16189,16 @@ "dev": true, "license": "MIT" }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -17015,6 +17307,14 @@ "dev": true, "license": "CC0-1.0" }, + "node_modules/stable": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "deprecated": "Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility", + "dev": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -19055,6 +19355,41 @@ "node": ">=0.4" } }, + "node_modules/xxh3-ts": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/xxh3-ts/-/xxh3-ts-1.0.6.tgz", + "integrity": "sha512-mFdXT/i6svQNNmwICmszSfKgnYBGBIaCKzPxYHfpM6e1hxYX2gfGPrI9mKRzSnFpi6ieBIK88TGlaudcPYZW5g==", + "dev": true, + "license": "BSD-2 Clause", + "dependencies": { + "buffer": "^6.0.3" + } + }, + "node_modules/xxh3-ts/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index c6ca4787e..740a62c7f 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@babel/plugin-transform-private-property-in-object": "^7.24.7", "@babel/plugin-transform-runtime": "^7.25.4", "@babel/preset-env": "^7.25.4", + "@enonic/esbuild-plugin-copy-with-hash": "^0.2.0", "@eslint/js": "^9.9.1", "@fortawesome/fontawesome-free": "^6.6.0", "autoprefixer": "^10.4.20", @@ -31,7 +32,11 @@ "css-loader": "^7.1.2", "css-minimizer-webpack-plugin": "^7.0.0", "esbuild": "0.24.0", + "esbuild-plugin-assets-manifest": "^1.0.8", "esbuild-plugin-copy": "2.1.1", + "esbuild-plugin-inline-import": "^1.1.0", + "esbuild-plugin-manifest": "1.0.4", + "esbuild-plugin-svg": "^0.1.0", "esbuild-plugin-svg-bundle": "1.3.0", "esbuild-sass-plugin": "3.3.1", "eslint": "^9.9.1", @@ -80,6 +85,7 @@ "whatwg-fetch": "^3.6.20" }, "scripts": { - "build": "node esbuild.config.mjs" + "build": "node esbuild.config.mjs", + "start": "node esbuild.config.mjs --watch" } } diff --git a/routes b/routes index 34ad73505..db80030ec 100644 --- a/routes +++ b/routes @@ -1,4 +1,4 @@ --- SPDX-FileCopyrightText: 2022 Gregor Kleen ,Sarah Vaupel ,Steffen Jost ,Wolfgang Witt +-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel , Gregor Kleen , Sarah Vaupel , Steffen Jost , Wolfgang Witt -- -- SPDX-License-Identifier: AGPL-3.0-or-later @@ -44,6 +44,7 @@ -- !development -- like free, but only for development builds /static StaticR EmbeddedStatic appStatic !free + /auth AuthR Auth getAuth !free /metrics MetricsR GET !free -- verify if this can be free @@ -297,4 +298,4 @@ /swagger SwaggerR GET !free /swagger.json SwaggerJsonR GET !free -!/*WellKnownFileName WellKnownR GET !free +!/*WellKnownFileName WellKnownR GET !free \ No newline at end of file diff --git a/src/Foundation/Instances.hs b/src/Foundation/Instances.hs index b7d6a555b..cf684b5bc 100644 --- a/src/Foundation/Instances.hs +++ b/src/Foundation/Instances.hs @@ -1,4 +1,4 @@ --- SPDX-FileCopyrightText: 2022 Gregor Kleen ,Sarah Vaupel ,Steffen Jost ,Wolfgang Witt +-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel , Gregor Kleen ,Sarah Vaupel ,Steffen Jost ,Wolfgang Witt -- -- SPDX-License-Identifier: AGPL-3.0-or-later @@ -91,7 +91,9 @@ instance Yesod UniWorX where isAuthorized :: HasCallStack => Route UniWorX -> Bool -> HandlerFor UniWorX AuthResult isAuthorized r w = runDBRead $ evalAccess r w + -- TODO: replace memcached-based static-content caching with basic addStaticContent addStaticContent = UniWorX.addStaticContent + -- addStaticContent = embedStaticContent appStatic StaticR Right -- TODO: minify on production builds fileUpload _site _length = FileUploadMemory lbsBackEnd diff --git a/src/Foundation/SiteLayout.hs b/src/Foundation/SiteLayout.hs index 46d3f9272..2aaede481 100644 --- a/src/Foundation/SiteLayout.hs +++ b/src/Foundation/SiteLayout.hs @@ -1,4 +1,4 @@ --- SPDX-FileCopyrightText: 2022 Gregor Kleen ,Sarah Vaupel ,Steffen Jost ,Winnie Ros ,Wolfgang Witt +-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel , Gregor Kleen ,Sarah Vaupel ,Steffen Jost ,Winnie Ros ,Wolfgang Witt -- -- SPDX-License-Identifier: AGPL-3.0-or-later @@ -488,7 +488,8 @@ siteLayout' overrideHeading widget = do frontendDatetimeLocale <- toJSON <$> selectLanguage frontendDatetimeLocales pc <- widgetToPageContent $ do - webpackLinks_main StaticR + bundlerLinks_main StaticR + bundlerLinks_polyfill StaticR toWidget $(juliusFile "templates/i18n.julius") whenIsJust currentApproot' $ \currentApproot -> toWidget $(juliusFile "templates/approot.julius") diff --git a/src/Settings.hs b/src/Settings.hs index e3fcc6105..2ef85a2f2 100644 --- a/src/Settings.hs +++ b/src/Settings.hs @@ -1,4 +1,4 @@ --- SPDX-FileCopyrightText: 2022 Gregor Kleen ,Sarah Vaupel ,Steffen Jost +-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel , Gregor Kleen ,Sarah Vaupel ,Steffen Jost -- -- SPDX-License-Identifier: AGPL-3.0-or-later @@ -90,7 +90,7 @@ import qualified Data.Set as Set data AppSettings = AppSettings { appStaticDir :: FilePath -- ^ Directory from which to serve static files. - , appWebpackEntrypoints :: FilePath + , appBundlerEntrypoints :: FilePath , appWellKnownDir :: FilePath , appWellKnownLinkFile :: FilePath , appDatabaseConf :: PostgresConf @@ -624,7 +624,7 @@ instance FromJSON AppSettings where appStaticDir <- o .: "static-dir" appWellKnownDir <- o .: "well-known-dir" appWellKnownLinkFile <- o .: "well-known-link-file" - appWebpackEntrypoints <- o .: "webpack-manifest" + appBundlerEntrypoints <- o .: "bundler-manifest" appDatabaseConf <- o .: "database" appAutoDbMigrate <- o .: "auto-db-migrate" let nonEmptyHost LdapConf{..} = case ldapHost of diff --git a/src/Settings/StaticFiles.hs b/src/Settings/StaticFiles.hs index 8e851d903..3f483f227 100644 --- a/src/Settings/StaticFiles.hs +++ b/src/Settings/StaticFiles.hs @@ -1,4 +1,4 @@ --- SPDX-FileCopyrightText: 2022 Gregor Kleen ,Steffen Jost ,Steffen Jost +-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel , Gregor Kleen , Steffen Jost , Steffen Jost -- -- SPDX-License-Identifier: AGPL-3.0-or-later @@ -7,16 +7,16 @@ -- prevents rebuilds if files change, that are not directly used (like -- webpack bundles) module Settings.StaticFiles - ( webpackLinks_main + ( bundlerLinks_main, bundlerLinks_polyfill , embeddedStatic , module Yesod.EmbeddedStatic ) where import ClassyPrelude.Yesod -import Settings (appStaticDir, appWebpackEntrypoints, compileTimeAppSettings) +import Settings (appStaticDir, appBundlerEntrypoints, compileTimeAppSettings) import Settings.StaticFiles.Generator -import Settings.StaticFiles.Webpack +import Settings.StaticFiles.Bundler import Yesod.EmbeddedStatic -- This generates easy references to files in the static directory at compile time, @@ -35,4 +35,4 @@ import Yesod.EmbeddedStatic #endif mkEmbeddedStatic DEV_BOOL "embeddedStatic" . pure . staticGenerator $ appStaticDir compileTimeAppSettings -mkWebpackEntrypoints (appWebpackEntrypoints compileTimeAppSettings) (pure staticGenerator) $ appStaticDir compileTimeAppSettings +mkBundlerEntrypoints (appBundlerEntrypoints compileTimeAppSettings) (pure staticGenerator) $ appStaticDir compileTimeAppSettings \ No newline at end of file diff --git a/src/Settings/StaticFiles/Webpack.hs b/src/Settings/StaticFiles/Bundler.hs similarity index 75% rename from src/Settings/StaticFiles/Webpack.hs rename to src/Settings/StaticFiles/Bundler.hs index a889d22fa..4c82b50ff 100644 --- a/src/Settings/StaticFiles/Webpack.hs +++ b/src/Settings/StaticFiles/Bundler.hs @@ -1,9 +1,9 @@ --- SPDX-FileCopyrightText: 2022 Gregor Kleen +-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel , Gregor Kleen -- -- SPDX-License-Identifier: AGPL-3.0-or-later -module Settings.StaticFiles.Webpack - ( mkWebpackEntrypoints +module Settings.StaticFiles.Bundler + ( mkBundlerEntrypoints ) where import ClassyPrelude @@ -12,7 +12,7 @@ import Language.Haskell.TH import Language.Haskell.TH.Syntax hiding (Lift(..)) import qualified Language.Haskell.TH.Syntax as TH (Lift(..)) -import qualified Data.Yaml as Yaml +import qualified Data.Aeson as Aeson import qualified Data.Map as Map @@ -25,7 +25,6 @@ import Control.Lens.Indexed (iforM) import Control.Monad.Writer.Class (MonadWriter(..)) import Control.Monad.Trans.Writer.Lazy (execWriterT) -import Control.Monad.Catch (MonadThrow(..)) import System.FilePath (makeRelative) @@ -35,11 +34,11 @@ import Utils () import Data.Containers.ListUtils -mkWebpackEntrypoints :: FilePath -- ^ Path to YAML-manifest +mkBundlerEntrypoints :: FilePath -- ^ Path to manifest (json) -> [FilePath -> Generator] -> FilePath -- ^ Path to static dir -> DecsQ -mkWebpackEntrypoints manifest mkGen stDir = do +mkBundlerEntrypoints manifest mkGen stDir = do addDependentFile manifest entrypoints <- decodeManifest manifest @@ -54,14 +53,14 @@ mkWebpackEntrypoints manifest mkGen stDir = do , ebLocation entry , "” of file “" , file - , "” of webpack entrypoint “" + , "” of bundler entrypoint “" , entrypoint , "” has no haskellName" ] Just n -> tell $ pure (n, ebMimeType entry) - let entryName = mkName $ "webpackEntrypoint_" <> entrypoint - widgetName = mkName $ "webpackLinks_" <> entrypoint + let entryName = mkName $ "bundlerEntrypoint_" <> entrypoint + widgetName = mkName $ "bundlerLinks_" <> entrypoint staticR <- newName "staticR" sequence @@ -82,16 +81,12 @@ mkWebpackEntrypoints manifest mkGen stDir = do | mime `ctEq` "application/javascript" -> addScript $ $(varE staticR) sRoute | otherwise - -> $logErrorS "siteLayout" [st|Unknown mime type in webpack bundle: #{tshow mime}|] + -> $logErrorS "siteLayout" [st|Unknown mime type in bundle: #{tshow mime}|] |]) [] ] ] - where - decodeManifest :: FilePath -> Q (Map String [FilePath]) - decodeManifest manifest' = do - res <- liftIO $ Yaml.decodeFileWithWarnings manifest' - case res of - Left exc -> throwM exc - Right (ws, res') -> res' <$ mapM_ (\w -> reportWarning $ "Warning while parsing webpack manifest: " <> show w) ws - +decodeManifest :: FilePath -> Q (Map String (Map String FilePath)) +decodeManifest manifest' = liftIO (Aeson.eitherDecodeFileStrict manifest') >>= \case + Left exc -> error $ "Encountered error while decoding manifest: " ++ exc + Right res -> return res \ No newline at end of file diff --git a/src/Settings/WellKnownFiles/TH.hs b/src/Settings/WellKnownFiles/TH.hs index 3844bf664..10e332a29 100644 --- a/src/Settings/WellKnownFiles/TH.hs +++ b/src/Settings/WellKnownFiles/TH.hs @@ -1,4 +1,4 @@ --- SPDX-FileCopyrightText: 2022 Gregor Kleen +-- SPDX-FileCopyrightText: 2022-2024 Sarah Vaupel , Gregor Kleen -- -- SPDX-License-Identifier: AGPL-3.0-or-later @@ -58,7 +58,7 @@ nwellKnownHtmlLinks = mkName "wellKnownHtmlLinks" mkWellKnown :: Lang -- ^ Default language -> FilePath -- ^ Base directory - -> FilePath -- ^ Link file (@html_code.html@) + -> FilePath -- ^ Link file (@include.html@) -> DecsQ mkWellKnown defLang wellKnownBase wellKnownLinks = do inputFiles <- fmap dirTree . liftIO $ readDirectoryWith (\f -> (f, ) <$> BS.readFile f) wellKnownBase @@ -79,7 +79,7 @@ mkWellKnown defLang wellKnownBase wellKnownLinks = do return $ file & _1 %~ makeRelative (wellKnownBase language) return (Text.pack language, lContents') | otherwise - -> fail "wellKnownBase is not a directory" + -> fail "well-known does not exist or is not a directory" fLanguages <- if | defLang `Set.member` Map.keysSet languageFiles @@ -103,7 +103,7 @@ mkWellKnown defLang wellKnownBase wellKnownLinks = do c <- lContents' return (Text.pack language, c) | otherwise - -> fail "wellKnownBase is not a directory" + -> fail "well-known does not exist or is not a directory" lLanguages <- if | defLang `Set.member` Map.keysSet languageLinks