diff --git a/packages/plugin-legacy/README.md b/packages/plugin-legacy/README.md index 70106c11690abb..2491d941612d34 100644 --- a/packages/plugin-legacy/README.md +++ b/packages/plugin-legacy/README.md @@ -128,6 +128,19 @@ export default { } ``` +## Content Security Policy + +The legacy plugin requires inline scripts for [Safari 10.1 `nomodule` fix](https://gist.github.com/samthor/64b114e4a4f539915a95b91ffd340acc) and SystemJS initialization. If you have a strict CSP policy requirement, you will need to [add the corresponding hashes to your `script-src` list](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#unsafe_inline_script): + +- `MS6/3FCg4WjP9gwgaBGwLpRCY6fZBgwmhVCdrPrNf3E=` +- `tQjf8gvb2ROOMapIxFvFAYBeUJ0v1HCbOcSmDNXGtDo=` + +These values can also be retrived via + +```js +const { cspHashes } = require('@vitejs/plugin-legacy') +``` + ## References - [Vue CLI modern mode](https://cli.vuejs.org/guide/browser-compatibility.html#modern-mode) diff --git a/packages/plugin-legacy/index.d.ts b/packages/plugin-legacy/index.d.ts index c3bfba5f13e24c..6a88de581ce8ce 100644 --- a/packages/plugin-legacy/index.d.ts +++ b/packages/plugin-legacy/index.d.ts @@ -26,3 +26,5 @@ export interface Options { declare function createPlugin(options?: Options): Plugin export default createPlugin + +export const cspHashes: string[] diff --git a/packages/plugin-legacy/index.js b/packages/plugin-legacy/index.js index 00fb1ee7eaf4f1..1244856238cff8 100644 --- a/packages/plugin-legacy/index.js +++ b/packages/plugin-legacy/index.js @@ -1,5 +1,6 @@ // @ts-check const path = require('path') +const { createHash } = require('crypto') const { build } = require('vite') // lazy load babel since it's not used during dev @@ -10,8 +11,12 @@ let babel const loadBabel = () => babel || (babel = require('@babel/standalone')) // https://gist.github.com/samthor/64b114e4a4f539915a95b91ffd340acc +// DO NOT ALTER THIS CONTENT const safari10NoModuleFix = `!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();` +const legacyEntryId = 'vite-legacy-entry' +const systemJSInlineCode = `System.import(document.getElementById('${legacyEntryId}').getAttribute('data-src'))` + /** * @param {import('.').Options} options * @returns {import('vite').Plugin[]} @@ -293,8 +298,15 @@ function viteLegacyPlugin(options = {}) { if (legacyEntryFilename) { tags.push({ tag: 'script', - attrs: { nomodule: true }, - children: `System.import("${config.build.base}${legacyEntryFilename}")`, + attrs: { + nomodule: true, + // we set the entry path on the element as an attribute so that the + // script content will stay consistent - which allows using a constant + // hash value for CSP. + id: legacyEntryId, + 'data-src': config.build.base + legacyEntryFilename + }, + children: systemJSInlineCode, injectTo: 'body' }) } else { @@ -446,4 +458,10 @@ function isLegacyOutput(options) { } module.exports = viteLegacyPlugin + viteLegacyPlugin.default = viteLegacyPlugin + +viteLegacyPlugin.cpsHashes = [ + createHash('sha256').update(safari10NoModuleFix).digest('base64'), + createHash('sha256').update(systemJSInlineCode).digest('base64') +]