From f94b153f7f8b4c6db08d18e4a660e6e6ccef12cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kuna?= <1282324+codecalm@users.noreply.github.com> Date: Mon, 24 Mar 2025 01:26:53 +0100 Subject: [PATCH] Add SRI generation script (#2104) --- .changeset/beige-apricots-pretend.md | 5 + .prettierrc | 2 +- package.json | 6 +- pnpm-lock.yaml | 3 + preview/{build => .build}/banner.mjs | 0 preview/{build => .build}/download-images.mjs | 0 preview/.build/generate-sri.js | 107 ++++++++++++++++++ preview/{build => .build}/import-icons.mjs | 0 .../import-illustrations.mjs | 0 preview/{build => .build}/rollup.config.mjs | 0 preview/{build => .build}/unused-files.mjs | 0 preview/eleventy.config.mjs | 35 +++++- preview/package.json | 15 +-- preview/pages/_includes/layout/css.html | 37 +++--- preview/pages/_includes/layout/js-libs.html | 13 ++- preview/pages/_includes/layout/js.html | 5 +- preview/pages/_layouts/base.html | 2 +- 17 files changed, 190 insertions(+), 40 deletions(-) create mode 100644 .changeset/beige-apricots-pretend.md rename preview/{build => .build}/banner.mjs (100%) rename preview/{build => .build}/download-images.mjs (100%) create mode 100644 preview/.build/generate-sri.js rename preview/{build => .build}/import-icons.mjs (100%) rename preview/{build => .build}/import-illustrations.mjs (100%) rename preview/{build => .build}/rollup.config.mjs (100%) rename preview/{build => .build}/unused-files.mjs (100%) diff --git a/.changeset/beige-apricots-pretend.md b/.changeset/beige-apricots-pretend.md new file mode 100644 index 000000000..a365f9804 --- /dev/null +++ b/.changeset/beige-apricots-pretend.md @@ -0,0 +1,5 @@ +--- +"preview": patch +--- + +Add SRI hashes to scripts and styles diff --git a/.prettierrc b/.prettierrc index 86ae4b399..35b5ef642 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,7 +1,7 @@ { "bracketSpacing": true, "jsxSingleQuote": false, - "printWidth": 240, + "printWidth": 320, "proseWrap": "always", "semi": false, "singleQuote": false, diff --git a/package.json b/package.json index 9aca548a4..3d34509e7 100644 --- a/package.json +++ b/package.json @@ -10,10 +10,9 @@ "version": "changeset version", "publish": "changeset publish", "playwright": "pnpm run build && pnpm run vt", - "vt": "playwright test tests", "reformat-mdx": "node .build/reformat-mdx.mjs", "start": "pnpm dev", - "zip": "mkdir -p packages-zip && zip -qr9 packages-zip/tabler-$(node -p \"require('./core/package.json').version\").zip ./preview/dist/*" + "zip": "mkdir -p packages-zip && zip -r packages-zip/tabler-$(node -p \"require('./package.json').version\").zip preview/dist/*" }, "packageManager": "pnpm@10.6.4", "devDependencies": { @@ -41,6 +40,7 @@ "sass": "1.71.0", "shx": "^0.4.0", "terser": "^5.39.0", - "turbo": "^2.4.4" + "turbo": "^2.4.4", + "shelljs": "^0.9.2" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5cebbb86f..9aef9b24d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -74,6 +74,9 @@ importers: sass: specifier: 1.71.0 version: 1.71.0 + shelljs: + specifier: ^0.9.2 + version: 0.9.2 shx: specifier: ^0.4.0 version: 0.4.0 diff --git a/preview/build/banner.mjs b/preview/.build/banner.mjs similarity index 100% rename from preview/build/banner.mjs rename to preview/.build/banner.mjs diff --git a/preview/build/download-images.mjs b/preview/.build/download-images.mjs similarity index 100% rename from preview/build/download-images.mjs rename to preview/.build/download-images.mjs diff --git a/preview/.build/generate-sri.js b/preview/.build/generate-sri.js new file mode 100644 index 000000000..cc78363fe --- /dev/null +++ b/preview/.build/generate-sri.js @@ -0,0 +1,107 @@ +const crypto = require('node:crypto'); +const fs = require('node:fs'); +const path = require('node:path'); +const sh = require('shelljs'); + +sh.config.fatal = true + +const configFile = path.join(__dirname, '../eleventy.config.mjs') + +const files = [ + { + file: '../core/dist/css/tabler.min.css', + configPropertyName: 'css' + }, + { + file: '../core/dist/css/tabler.rtl.min.css', + configPropertyName: 'css-rtl' + }, + { + file: '../core/dist/css/tabler-flags.min.css', + configPropertyName: 'css-flags' + }, + { + file: '../core/dist/css/tabler-flags.rtl.min.css', + configPropertyName: 'css-flags-rtl' + }, + { + file: '../core/dist/css/tabler-marketing.min.css', + configPropertyName: 'css-marketing' + }, + { + file: '../core/dist/css/tabler-marketing.rtl.min.css', + configPropertyName: 'css-marketing-rtl' + }, + { + file: '../core/dist/css/tabler-payments.min.css', + configPropertyName: 'css-payments' + }, + { + file: '../core/dist/css/tabler-payments.rtl.min.css', + configPropertyName: 'css-payments-rtl' + }, + { + file: '../core/dist/css/tabler-props.min.css', + configPropertyName: 'css-props' + }, + { + file: '../core/dist/css/tabler-props.rtl.min.css', + configPropertyName: 'css-props-rtl' + }, + { + file: '../core/dist/css/tabler-themes.min.css', + configPropertyName: 'css-themes' + }, + { + file: '../core/dist/css/tabler-themes.rtl.min.css', + configPropertyName: 'css-themes-rtl' + }, + { + file: '../core/dist/css/tabler-socials.min.css', + configPropertyName: 'css-socials' + }, + { + file: '../core/dist/css/tabler-socials.rtl.min.css', + configPropertyName: 'css-socials-rtl' + }, + { + file: '../core/dist/css/tabler-vendors.min.css', + configPropertyName: 'css-vendors' + }, + { + file: '../core/dist/css/tabler-vendors.rtl.min.css', + configPropertyName: 'css-vendors-rtl' + }, + { + file: '../core/dist/js/tabler.min.js', + configPropertyName: 'js' + }, + { + file: '../core/dist/js/tabler.min.js', + configPropertyName: 'js-theme' + }, + { + file: 'dist/preview/css/demo.min.css', + configPropertyName: 'demo-css' + }, + { + file: 'dist/preview/js/demo.min.js', + configPropertyName: 'demo-js' + }, +] + +for (const { file, configPropertyName } of files) { + fs.readFile(path.join(__dirname, '..', file), 'utf8', (error, data) => { + if (error) { + throw error + } + + const algorithm = 'sha384' + const hash = crypto.createHash(algorithm).update(data, 'utf8').digest('base64') + const integrity = `${algorithm}-${hash}` + + console.log(`${configPropertyName}: ${integrity}`) + + sh.sed('-i', new RegExp(`^(\\s+"${configPropertyName}":\\s+["'])\\S*(["'])`), `$1${integrity}$2`, configFile) + }) +} \ No newline at end of file diff --git a/preview/build/import-icons.mjs b/preview/.build/import-icons.mjs similarity index 100% rename from preview/build/import-icons.mjs rename to preview/.build/import-icons.mjs diff --git a/preview/build/import-illustrations.mjs b/preview/.build/import-illustrations.mjs similarity index 100% rename from preview/build/import-illustrations.mjs rename to preview/.build/import-illustrations.mjs diff --git a/preview/build/rollup.config.mjs b/preview/.build/rollup.config.mjs similarity index 100% rename from preview/build/rollup.config.mjs rename to preview/.build/rollup.config.mjs diff --git a/preview/build/unused-files.mjs b/preview/.build/unused-files.mjs similarity index 100% rename from preview/build/unused-files.mjs rename to preview/.build/unused-files.mjs diff --git a/preview/eleventy.config.mjs b/preview/eleventy.config.mjs index c1163c262..da5e17c4c 100644 --- a/preview/eleventy.config.mjs +++ b/preview/eleventy.config.mjs @@ -114,12 +114,12 @@ export default function (eleventyConfig) { npmPackage: "@tabler/core", tablerCssPlugins: [ - "tabler-flags", - "tabler-socials", - "tabler-payments", - "tabler-vendors", - "tabler-marketing", - "tabler-themes", + { name: "tabler-flags", sri: "css-flags" }, + { name: "tabler-socials", sri: "css-socials" }, + { name: "tabler-payments", sri: "css-payments" }, + { name: "tabler-vendors", sri: "css-vendors" }, + { name: "tabler-marketing", sri: "css-marketing" }, + { name: "tabler-themes", sri: "css-themes" }, ], icons: { @@ -411,6 +411,29 @@ export default function (eleventyConfig) { ] }); + eleventyConfig.addGlobalData("sri", { + "css": "sha384-+ysCwUILnDsnHwK+rITa6QNp8mGFdEXZMfZ/WBpY13iTiCwas5Ah0GIagDbU8Ocy", + "css-rtl": "sha384-kQMcoyzrq1HEu2/rW78iuKRreSYzdUb1KQhPweqwUyH8Gnydy+vaMP4MpFx2+z07", + "css-flags": "sha384-J4S9gTOgB6a60d8OIMRu7vveDJCqxLAcDfzDN24CQxXmfi1iIFoU3uelSShCMfAD", + "css-flags-rtl": "sha384-Rh33piKJ6K8C1b07vnxSLBK5RJSnp4UhH37XTfJxWlnVUl3FqH3mW14kOy6nU1Bd", + "css-marketing": "sha384-RFTn6c3X2MHvEcQwCc/w1n8IBV4B/GeFHms5KPCiMkSc+tCDtZe5F6aJ+dJYu7mI", + "css-marketing-rtl": "sha384-HZqaZjtszSlyS975Oe9Z9U9gVmMxvTBU1XziOLE3R4N/pKTmWiznOzHszVqoSufe", + "css-payments": "sha384-YnhOMEPyU5QfErzSK9sD18FMXdRCn/HB4a+88mFXbd45fFRNWKWeARptNw1k16+/", + "css-payments-rtl": "sha384-v6XNJfLEVre0G8WOfEeFRSDFItjdOvNGFZTlS6HpoKkkxYe/vbkJBfzhOnePD2dY", + "css-socials": "sha384-M/p2rVRhhVGWQaE5KAPB4+/uWqFtmb6ag3/NXG8E3SL2MAROPCfB5YJvDHmS5Rms", + "css-socials-rtl": "sha384-5h8LiZ8sjd3+w3/waxyu3/vTW2kdx90LLYaik7pugCUOR7YRQXbyP13dhp1mUrcW", + "css-props": "sha384-D9/OSlhkMpd/Nf7168lDKk/Tg/slS3Zu8+alAFMMKXmFkoPazXHR7kiSMKKgu5D6", + "css-props-rtl": "sha384-4v5rbYBY7WUjemTcFeoBDmH+qZUndtmwamnzHdqcUpAdopNjpVsG/+1IQOpKHNly", + "css-themes": "sha384-Bj8pP2O3iJP6JH/ZdDBnxIH/3XOJF8DSyYUUHs8wTxb0PRUe5DU01llAmog5ybpg", + "css-themes-rtl": "sha384-+bJhK3cbUPk0SGCLUskjOBARViddapb+MJA1CbWjerZ46uyZbm6L1Gar3Ggs4c8h", + "css-vendors-rtl": "sha384-bO98lLX+Ldg6g5nwEiyrECPhkSytviXXblROAGrjND8u+AM4zbk8gjQsCDK7zifX", + "css-vendors": "sha384-oxt7C0fn5FehJqUxTGaDMUo+IiNNM7wVIqvuv7aHn4hnfLyc0TxI2xXo6bMK1pyb", + "js": "sha384-uSpys8fjyVTPrXxPMi+NhnEMIp1YSGFZSCDrRHjYIUVdInIvlHft8JHLm6Oiw3vA", + "js-theme": "sha384-uSpys8fjyVTPrXxPMi+NhnEMIp1YSGFZSCDrRHjYIUVdInIvlHft8JHLm6Oiw3vA", + "demo-css": "sha384-BUDq2P684xwRBf0GDlySvob+KJg4ko8y2K7njgvYBscmEuqoVVqJ75zcTDozwkFA", + "demo-js": "sha384-UcTgbM9IZSOPHHuFa0R9H4TegQWoZkJKpeTjLV5hjem2k0CZ67Q4/bW2rT/Edf4Z", + }); + /** * Filters */ diff --git a/preview/package.json b/preview/package.json index 5c447e069..9958755c7 100644 --- a/preview/package.json +++ b/preview/package.json @@ -2,7 +2,7 @@ "name": "preview", "private": true, "scripts": { - "build": "pnpm run clean && pnpm run css && pnpm run js && pnpm run html", + "build": "pnpm run clean && pnpm run css && pnpm run js && pnpm run generate-sri && pnpm run html", "dev": "pnpm run clean && pnpm run watch", "watch": "concurrently \"pnpm run watch-html\" \"pnpm run watch-css\" \"pnpm run watch-js\"", "watch-html": "cross-env NODE_ENV=development eleventy --serve --port=3000 --incremental", @@ -10,10 +10,10 @@ "watch-css": "nodemon --watch scss/ --ext scss --exec \"pnpm run css\"", "css": "pnpm run css-compile && pnpm run css-prefix && pnpm run css-minify", "css-compile": "sass scss/:dist/preview/css/ --no-source-map --load-path=node_modules", - "css-prefix": "postcss --config build/postcss.config.mjs --replace \"dist/preview/css/*.css\" \"!dist/preview/css/*.rtl*.css\" \"!dist/preview/css/*.min.css\"", + "css-prefix": "postcss --config .build/postcss.config.mjs --replace \"dist/preview/css/*.css\" \"!dist/preview/css/*.rtl*.css\" \"!dist/preview/css/*.min.css\"", "css-minify": "cleancss -O1 --format breakWith=lf --with-rebase --source-map --source-map-inline-sources --output dist/preview/css/ --batch --batch-suffix \".min\" \"dist/preview/css/*.css\" \"!dist/preview/css/*.min.css\" \"!dist/preview/css/*rtl*.css\"", "js": "pnpm run js-compile && pnpm run js-minify", - "js-compile": "rollup --config build/rollup.config.mjs --sourcemap", + "js-compile": "rollup --config .build/rollup.config.mjs --sourcemap", "js-minify": "pnpm run js-minify-demo", "js-minify-demo": "terser --compress passes=2 --mangle --comments \"/^!/\" --source-map \"content=dist/preview/js/demo.js.map,includeSources,url=demo.min.js.map\" --output dist/preview/js/demo.min.js dist/preview/js/demo.js", "clean": "shx rm -rf dist demo", @@ -21,12 +21,13 @@ "html-build": "eleventy", "html-prettify": "prettier --write \"dist/**/*.html\"", "svg-optimize": "svgo -f svg/brand --pretty", - "unused-files": "node build/unused-files.mjs", - "download-images": "node build/download-images.mjs", + "unused-files": "node .build/unused-files.mjs", + "download-images": "node .build/download-images.mjs", "optimize-images": "for i in ./src/static/photos/*.jpg; do convert \"$i\" -quality 80% \"${i%.jpg}.jpg\"; done", - "svg-icons": "node build/import-icons.mjs", - "import-illustrations": "node build/import-illustrations.mjs", + "svg-icons": "node .build/import-icons.mjs", + "import-illustrations": "node .build/import-illustrations.mjs", "import-icons": "git checkout dev && BRANCH_NAME=\"dev-tabler-icons-`pnpm info @tabler/icons version`\" && git branch $BRANCH_NAME && git checkout $BRANCH_NAME && ncu -u @tabler/icons && pnpm install && pnpm run svg-icons && git add . && git commit -am \"update icons to v`pnpm info @tabler/icons version`\" && git push origin $BRANCH_NAME && git checkout dev", + "generate-sri": "node .build/generate-sri.js", "zip": "mkdir -p packages-zip && zip -r packages-zip/tabler-$(node -p \"require('./package.json').version\").zip demo/*" }, "dependencies": { diff --git a/preview/pages/_includes/layout/css.html b/preview/pages/_includes/layout/css.html index e81bcafa0..221240f91 100644 --- a/preview/pages/_includes/layout/css.html +++ b/preview/pages/_includes/layout/css.html @@ -1,32 +1,39 @@ -{% if site.useIconfont %} +{% if site.useIconfont -%} -{% endif %} +{% endif -%} - -{% if page-libs %} +{% if page-libs -%} - {% for lib in libs.css %} - {% if page-libs contains lib[0] %} - {% for file in lib[1] %} + {% for lib in libs.css -%} + {% if page-libs contains lib[0] -%} + {% for file in lib[1] -%} - {% endfor %} - {% endif %} - {% endfor %} + {% endfor -%} + {% endif -%} + {% endfor -%} {% endif %} - +{% if layout-rtl -%} + +{% else -%} + +{% endif -%} -{% for plugin in site.tablerCssPlugins %} - -{% endfor %} +{% for plugin in site.tablerCssPlugins -%} + {% if layout-rtl -%} + + {% else -%} + + {% endif -%} +{% endfor -%} - + \ No newline at end of file diff --git a/preview/pages/_includes/layout/js-libs.html b/preview/pages/_includes/layout/js-libs.html index a9294b9bd..e4028ac2d 100644 --- a/preview/pages/_includes/layout/js-libs.html +++ b/preview/pages/_includes/layout/js-libs.html @@ -1,13 +1,18 @@ {% if page-libs -%} - +{% capture libs-code -%} {% for lib in include.libs -%} {% if page-libs contains lib[0] -%} {% for file in lib[1] -%} - + {% endfor -%} {% endif -%} {% endfor -%} +{% endcapture -%} + +{% assign libs-code = libs-code | strip -%} +{% if libs-code != "" -%} + +{{ libs-code }} +{% endif -%} {% endif -%} \ No newline at end of file diff --git a/preview/pages/_includes/layout/js.html b/preview/pages/_includes/layout/js.html index 2e9620b80..c4ba0d4b7 100644 --- a/preview/pages/_includes/layout/js.html +++ b/preview/pages/_includes/layout/js.html @@ -6,11 +6,10 @@ {% include "layout/js-libs.html" libs=libs.js %} - + - + - {% scripts %} \ No newline at end of file diff --git a/preview/pages/_layouts/base.html b/preview/pages/_layouts/base.html index ba4600536..aee5fe62a 100644 --- a/preview/pages/_layouts/base.html +++ b/preview/pages/_layouts/base.html @@ -43,7 +43,7 @@ {% assign layout-dark = layout-dark | default: site.layoutDark %}
- + {{ content }}