In your config.toml:
[outputs]
home = [ "HTML", "RSS", "Algolia", "REDIR", "HEADERS" ]
[outputFormats.HEADERS]
mediatype = "text/netlify"
baseName = "_headers"
isPlainText = true
notAlternative = true
The HEADERS
part is important, ignore all else you don’t already have
Then in _default/index.header
add your template for the headers file in netlify. Mine looks very specific, but should explain some points. The with partial footer/js.html
is the place where the hash is created for my preloaded script. the same use cold be done for adding a CSP hash for the script.
/
Accept-Encoding: gzip, deflate, br
Link: </assets/fonts/panton/panton-regular-webfont.woff2>; rel=preload; as=font; crossorigin; type="font/woff2"
Link: </assets/fonts/panton/panton-regularitalic-webfont.woff2>; rel=preload; as=font; crossorigin; type="font/woff2"
Link: </assets/fonts/panton/panton-black-webfont.woff2>; rel=preload; as=font; crossorigin; type="font/woff2"
Link: </assets/fonts/panton/panton-blackitalic-webfont.woff2>; rel=preload; as=font; crossorigin; type="font/woff2"
Link: </assets/fonts/panton/panton-heavy-webfont.woff2>; rel=preload; as=font; crossorigin; type="font/woff2"
{{ with partial "footer/js.html" . }}
Link: <{{ .RelPermalink }}>; rel=preload; as=script; integrity='{{ .Data.Integrity }}'
{{ end }}
{{ with partialCached "head/css.html" . }}
Link: <{{ .RelPermalink }}>; rel=preload; as=style; integrity='{{ .Data.Integrity }}'
{{ end }}
Feature-Policy: geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; fullscreen 'none'; payment 'none'
/*
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
Content-Security-Policy: default-src 'self' googleads.g.doubleclick.net; script-src 'self' 'unsafe-inline' 'unsafe-eval' pagead2.googlesyndication.com storage.googleapis.com googleads.g.doubleclick.net ajax.googleapis.com www.google-analytics.com www.google.com www.gstatic.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: www.google-analytics.com; connect-src *.algolia.net *.algolianet.com; frame-src www.google.com www.youtube.com googleads.g.doubleclick.net; upgrade-insecure-requests; manifest-src 'self'; font-src 'self' fonts.googleapis.com; frame-ancestors 'self'; object-src 'self'
/*.html
Accept-Encoding: gzip, deflate, br
/*.manifest
Content-Type: application/manifest+json; charset=utf-8
Cache-Control: public, max-age=31536000, immutable
Accept-Encoding: gzip, deflate, br
/script*.js
Expires: Tue, 31-Dec-2020 23:59:59 GMT+0700
Content-Type: text/javascript; charset=utf-8
Cache-Control: public, max-age=31536000, immutable
Accept-Encoding: gzip, deflate, br
/style*.css
Expires: Tue, 31-Dec-2020 23:59:59 GMT+0700
Cache-Control: public, max-age=31536000, immutable
Accept-Encoding: gzip, deflate, br
/*.jpg
Expires: Tue, 31-Dec-2020 23:59:59 GMT+0700
Cache-Control: public, max-age=31536000, immutable
Accept-Encoding: gzip, deflate, br
/*.png
Expires: Tue, 31-Dec-2020 23:59:59 GMT+0700
Cache-Control: public, max-age=31536000, immutable
Accept-Encoding: gzip, deflate, br
/assets/*
Expires: Tue, 31-Dec-2020 23:59:59 GMT+0700
Cache-Control: public, max-age=31536000, immutable
/images/*
Expires: Tue, 31-Dec-2020 23:59:59 GMT+0700
Cache-Control: public, max-age=31536000, immutable
I think this topic is interesting for my website too, but it might take some days to implement it properly. If you can wait, then wait. Else: be an explorer and tell us how to do it 