Browse Source

Add SRI generation script (#2104)

Paweł Kuna 5 months ago
parent
commit
f94b153f7f

+ 5 - 0
.changeset/beige-apricots-pretend.md

@@ -0,0 +1,5 @@
+---
+"preview": patch
+---
+
+Add SRI hashes to scripts and styles

+ 1 - 1
.prettierrc

@@ -1,7 +1,7 @@
 {
 	"bracketSpacing": true,
 	"jsxSingleQuote": false,
-	"printWidth": 240,
+	"printWidth": 320,
 	"proseWrap": "always",
 	"semi": false,
 	"singleQuote": false,

+ 3 - 3
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": "[email protected]",
   "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"
   }
 }

+ 3 - 0
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

+ 0 - 0
preview/build/banner.mjs → preview/.build/banner.mjs


+ 0 - 0
preview/build/download-images.mjs → preview/.build/download-images.mjs


+ 107 - 0
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)
+	})
+}

+ 0 - 0
preview/build/import-icons.mjs → preview/.build/import-icons.mjs


+ 0 - 0
preview/build/import-illustrations.mjs → preview/.build/import-illustrations.mjs


+ 0 - 0
preview/build/rollup.config.mjs → preview/.build/rollup.config.mjs


+ 0 - 0
preview/build/unused-files.mjs → preview/.build/unused-files.mjs


+ 29 - 6
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
 	 */

+ 8 - 7
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": {

+ 22 - 15
preview/pages/_includes/layout/css.html

@@ -1,32 +1,39 @@
-{% if site.useIconfont %}
+{% if site.useIconfont -%}
 <!-- BEGIN ICONFONT STYLES -->
 <link href="https://www.unpkg.com/@tabler/icons-webfont@latest/dist/tabler-icons.min.css" rel="stylesheet" />
 <!-- END ICON FONT STYLES -->
-{% endif %}
-
+{% endif -%}
 
-{% if page-libs %}
+{% if page-libs -%}
 <!-- BEGIN PAGE LEVEL STYLES -->
-	{% 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] -%}
 				<link href="{% if file contains 'http://' or file contains 'https://' %}{{ file }}{% else %}{{ page | relative }}/libs/{% if environment != 'development' %}{{ file | replace: '@', '' }}{% else %}{{ file }}{% endif %}{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}{% endif %}" rel="stylesheet"/>
-			{% endfor %}
-		{% endif %}
-	{% endfor %}
+			{% endfor -%}
+		{% endif -%}
+	{% endfor -%}
 <!-- END PAGE LEVEL STYLES -->
 {% endif %}
 
 <!-- BEGIN GLOBAL MANDATORY STYLES -->
-<link href="{{ page | relative }}/dist/css/tabler{% if layout-rtl %}.rtl{% endif %}{% if environment != 'development' %}.min{% endif %}.css{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}" rel="stylesheet"/>
+{% if layout-rtl -%}
+<link href="{{ page | relative }}/dist/css/tabler-rtl{% if environment != 'development' %}.min{% endif %}.css{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}" rel="stylesheet"{% if environment != 'development' %} integrity="{{ sri.css-rtl }}"{% endif %} />
+{% else -%}
+<link href="{{ page | relative }}/dist/css/tabler{% if environment != 'development' %}.min{% endif %}.css{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}" rel="stylesheet"{% if environment != 'development' %} integrity="{{ sri.css }}"{% endif %} />
+{% endif -%}
 <!-- END GLOBAL MANDATORY STYLES -->
 
 <!-- BEGIN PLUGINS STYLES -->
-{% for plugin in site.tablerCssPlugins %}
-	<link href="{{ page | relative }}/dist/css/{{ plugin }}{% if layout-rtl %}.rtl{% endif %}{% if environment != 'development' %}.min{% endif %}.css{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}" rel="stylesheet"/>
-{% endfor %}
+{% for plugin in site.tablerCssPlugins -%}
+	{% if layout-rtl -%}
+	<link href="{{ page | relative }}/dist/css/{{ plugin.name }}.rtl{% if environment != 'development' %}.min{% endif %}.css{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}" rel="stylesheet"{% if environment != 'development' %} integrity="{{ sri[`${plugin.sri}-rtl`] }}"{% endif %}/>
+	{% else -%}
+	<link href="{{ page | relative }}/dist/css/{{ plugin.name }}{% if environment != 'development' %}.min{% endif %}.css{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}" rel="stylesheet"{% if environment != 'development' %} integrity="{{ sri[plugin.sri] }}"{% endif %}/>
+	{% endif -%}
+{% endfor -%}
 <!-- END PLUGINS STYLES -->
 
 <!-- BEGIN DEMO STYLES -->
-<link href="{{ page | relative }}/preview/css/demo{% if environment != 'development' %}.min{% endif %}.css{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}" rel="stylesheet"/>
+<link href="{{ page | relative }}/preview/css/demo{% if environment != 'development' %}.min{% endif %}.css{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}" rel="stylesheet"{% if environment != 'development' %} integrity="{{ sri.demo-css }}"{% endif %}/>
 <!-- END DEMO STYLES -->

+ 9 - 4
preview/pages/_includes/layout/js-libs.html

@@ -1,13 +1,18 @@
 {% if page-libs -%}
-<!-- BEGIN PAGE LIBRARIES -->
+{% capture libs-code -%}
 {% for lib in include.libs -%}
 {% if page-libs contains lib[0] -%}
 {% for file in lib[1] -%}
-<script
-	src="{% if file contains 'http://' or file contains 'https://' %}{{ file | replace: 'GOOGLE_MAPS_KEY', google-maps-key }}{% else %}{{ page | relative }}/libs/{% if environment != 'development' %}{{ file | replace: '@', '' }}{% else %}{{ file }}{% endif %}{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}{% endif %}"
-	defer></script>
+<script src="{% if file contains 'http://' or file contains 'https://' %}{{ file | replace: 'GOOGLE_MAPS_KEY', google-maps-key }}{% else %}{{ page | relative }}/libs/{% if environment != 'development' %}{{ file | replace: '@', '' }}{% else %}{{ file }}{% endif %}{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}{% endif %}" defer></script>
 {% endfor -%}
 {% endif -%}
 {% endfor -%}
+{% endcapture -%}
+
+{% assign libs-code = libs-code | strip -%}
+{% if libs-code != "" -%}
+<!-- BEGIN PAGE LIBRARIES -->
+{{ libs-code }}
 <!-- END PAGE LIBRARIES -->
+{% endif -%}
 {% endif -%}

+ 2 - 3
preview/pages/_includes/layout/js.html

@@ -6,11 +6,10 @@
 {% include "layout/js-libs.html" libs=libs.js %}
 
 <!-- BEGIN GLOBAL MANDATORY SCRIPTS -->
-<script src="{{ page | relative }}/dist/js/tabler{% if environment != 'development' %}.min{% endif %}.js{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}" defer></script>
+<script src="{{ page | relative }}/dist/js/tabler{% if environment != 'development' %}.min{% endif %}.js{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}" defer{% if environment != 'development' %} integrity="{{ sri.js }}"{% endif %}></script>
 <!-- END GLOBAL MANDATORY SCRIPTS -->
 
 <!-- BEGIN DEMO SCRIPTS -->
-<script src="{{ page | relative }}/preview/js/demo{% if environment != 'development' %}.min{% endif %}.js{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}" defer></script>
+<script src="{{ page | relative }}/preview/js/demo{% if environment != 'development' %}.min{% endif %}.js{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}" defer{% if environment != 'development' %} integrity="{{ sri.demo-js }}"{% endif %}></script>
 <!-- END DEMO SCRIPTS -->
-
 {% scripts %}

+ 1 - 1
preview/pages/_layouts/base.html

@@ -43,7 +43,7 @@
 {% assign layout-dark = layout-dark | default: site.layoutDark %}
 <body{% if layout.body-class or body-class %} class="{% if layout.body-class %} {{ layout.body-class }}{% endif %}{% if body-class %} {{ body-class }}{% endif %}"{% endif %}>
 	<!-- BEGIN GLOBAL THEME SCRIPT -->
-	<script src="{{ page | relative }}/dist/js/tabler-theme{% if environment != 'development' %}.min{% endif %}.js{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}"></script>
+	<script src="{{ page | relative }}/dist/js/tabler-theme{% if environment != 'development' %}.min{% endif %}.js{% if environment != 'development' %}?{{ 'now' | date: '%s' }}{% endif %}"{% if environment != 'development' %} integrity="{{ sri.js-theme }}"{% endif %}></script>
 	<!-- END GLOBAL THEME SCRIPT -->
 
 	{{ content }}