You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							111 lines
						
					
					
						
							4.1 KiB
						
					
					
				
			
		
		
	
	
							111 lines
						
					
					
						
							4.1 KiB
						
					
					
				const fs = require('fs-extra') | 
						|
const path = require('path') | 
						|
 | 
						|
// https://gist.github.com/samthor/64b114e4a4f539915a95b91ffd340acc | 
						|
const safariFix = `!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()}}();` | 
						|
 | 
						|
class ModernModePlugin { | 
						|
  constructor ({ targetDir, isModernBuild, unsafeInline, jsDirectory }) { | 
						|
    this.targetDir = targetDir | 
						|
    this.isModernBuild = isModernBuild | 
						|
    this.unsafeInline = unsafeInline | 
						|
    this.jsDirectory = jsDirectory | 
						|
  } | 
						|
 | 
						|
  apply (compiler) { | 
						|
    if (!this.isModernBuild) { | 
						|
      this.applyLegacy(compiler) | 
						|
    } else { | 
						|
      this.applyModern(compiler) | 
						|
    } | 
						|
  } | 
						|
 | 
						|
  applyLegacy (compiler) { | 
						|
    const ID = `vue-cli-legacy-bundle` | 
						|
    compiler.hooks.compilation.tap(ID, compilation => { | 
						|
      compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(ID, async (data, cb) => { | 
						|
        // get stats, write to disk | 
						|
        await fs.ensureDir(this.targetDir) | 
						|
        const htmlName = path.basename(data.plugin.options.filename) | 
						|
        // Watch out for output files in sub directories | 
						|
        const htmlPath = path.dirname(data.plugin.options.filename) | 
						|
        const tempFilename = path.join(this.targetDir, htmlPath, `legacy-assets-${htmlName}.json`) | 
						|
        await fs.mkdirp(path.dirname(tempFilename)) | 
						|
        await fs.writeFile(tempFilename, JSON.stringify(data.body)) | 
						|
        cb() | 
						|
      }) | 
						|
    }) | 
						|
  } | 
						|
 | 
						|
  applyModern (compiler) { | 
						|
    const ID = `vue-cli-modern-bundle` | 
						|
    compiler.hooks.compilation.tap(ID, compilation => { | 
						|
      compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(ID, async (data, cb) => { | 
						|
        // use <script type="module"> for modern assets | 
						|
        data.body.forEach(tag => { | 
						|
          if (tag.tagName === 'script' && tag.attributes) { | 
						|
            tag.attributes.type = 'module' | 
						|
          } | 
						|
        }) | 
						|
 | 
						|
        // use <link rel="modulepreload"> instead of <link rel="preload"> | 
						|
        // for modern assets | 
						|
        data.head.forEach(tag => { | 
						|
          if (tag.tagName === 'link' && | 
						|
              tag.attributes.rel === 'preload' && | 
						|
              tag.attributes.as === 'script') { | 
						|
            tag.attributes.rel = 'modulepreload' | 
						|
          } | 
						|
        }) | 
						|
 | 
						|
        // inject links for legacy assets as <script nomodule> | 
						|
        const htmlName = path.basename(data.plugin.options.filename) | 
						|
        // Watch out for output files in sub directories | 
						|
        const htmlPath = path.dirname(data.plugin.options.filename) | 
						|
        const tempFilename = path.join(this.targetDir, htmlPath, `legacy-assets-${htmlName}.json`) | 
						|
        const legacyAssets = JSON.parse(await fs.readFile(tempFilename, 'utf-8')) | 
						|
          .filter(a => a.tagName === 'script' && a.attributes) | 
						|
        legacyAssets.forEach(a => { a.attributes.nomodule = '' }) | 
						|
 | 
						|
        if (this.unsafeInline) { | 
						|
          // inject inline Safari 10 nomodule fix | 
						|
          data.body.push({ | 
						|
            tagName: 'script', | 
						|
            closeTag: true, | 
						|
            innerHTML: safariFix | 
						|
          }) | 
						|
        } else { | 
						|
          // inject the fix as an external script | 
						|
          const safariFixPath = path.join(this.jsDirectory, 'safari-nomodule-fix.js') | 
						|
          const fullSafariFixPath = path.join(compilation.options.output.publicPath, safariFixPath) | 
						|
          compilation.assets[safariFixPath] = { | 
						|
            source: function () { | 
						|
              return new Buffer(safariFix) | 
						|
            }, | 
						|
            size: function () { | 
						|
              return Buffer.byteLength(safariFix) | 
						|
            } | 
						|
          } | 
						|
          data.body.push({ | 
						|
            tagName: 'script', | 
						|
            closeTag: true, | 
						|
            attributes: { | 
						|
              src: fullSafariFixPath | 
						|
            } | 
						|
          }) | 
						|
        } | 
						|
 | 
						|
        data.body.push(...legacyAssets) | 
						|
        await fs.remove(tempFilename) | 
						|
        cb() | 
						|
      }) | 
						|
 | 
						|
      compilation.hooks.htmlWebpackPluginAfterHtmlProcessing.tap(ID, data => { | 
						|
        data.html = data.html.replace(/\snomodule="">/g, ' nomodule>') | 
						|
      }) | 
						|
    }) | 
						|
  } | 
						|
} | 
						|
 | 
						|
ModernModePlugin.safariFix = safariFix | 
						|
module.exports = ModernModePlugin
 | 
						|
 |