@small-tech/vite-plugin-sri
Version:
A Vite plugin that adds subresource integrity hashes to your index.html file at build time.
69 lines (60 loc) • 2.37 kB
JavaScript
////////////////////////////////////////////////////////////////////////////////
//
// @small-tech/vite-plugin-sri
//
// Subresource integrity (SRI) plugin for Vite (https://vitejs.dev/)
//
// Adds subresource integrity hashes to script and stylesheet
// imports from your index.html file at build time.
//
// If you’re looking for a generic Rollup plugin that does the same thing,
// see rollup-plugin-sri by Jonas Kruckenberg that this one was inspired by:
// https://github.com/JonasKruckenberg/rollup-plugin-sri
//
// Like this? Fund us!
// https://small-tech.org/fund-us
//
// Copyright ⓒ 2021-present Aral Balkan, Small Technology Foundation
// License: ISC.
//
////////////////////////////////////////////////////////////////////////////////
import { createHash } from 'crypto'
import cheerio from 'cheerio'
import fetch from 'node-fetch'
export default function sri () {
return {
name: 'vite-plugin-sri',
enforce: 'post',
apply: 'build',
async transformIndexHtml(html, context) {
const bundle = context.bundle
const calculateIntegrityHashes = async (element) => {
let source
let attributeName = element.attribs.src ? 'src' : 'href'
const resourcePath = element.attribs[attributeName]
if (resourcePath.startsWith('http')) {
// Load remote source from URL.
source = await (await fetch(resourcePath)).buffer()
} else {
// Load local source from bundle.
const resourcePathWithoutLeadingSlash = element.attribs[attributeName].slice(1)
const bundleItem = bundle[resourcePathWithoutLeadingSlash]
source = bundleItem.code || bundleItem.source
}
element.attribs.integrity = `sha384-${createHash('sha384').update(source).digest().toString('base64')}`
}
const $ = cheerio.load(html)
$.prototype.asyncForEach = async function (callback) {
for (let index = 0; index < this.length; index++) {
await callback(this[index], index, this);
}
}
// Implement SRI for scripts and stylesheets.
const scripts = $('script').filter('[src]')
const stylesheets = $('link[rel=stylesheet]').filter('[href]')
await scripts.asyncForEach(calculateIntegrityHashes)
await stylesheets.asyncForEach(calculateIntegrityHashes)
return $.html()
}
}
}