SafariNomoduleFixPlugin.js 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. // https://gist.github.com/samthor/64b114e4a4f539915a95b91ffd340acc
  2. 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()}}();`
  3. const path = require('path')
  4. const HtmlWebpackPlugin = require('html-webpack-plugin')
  5. const { semver } = require('@vue/cli-shared-utils')
  6. const { projectModuleTargets } = require('../util/targets')
  7. const minSafariVersion = projectModuleTargets.safari
  8. const minIOSVersion = projectModuleTargets.ios
  9. const supportsSafari10 =
  10. (minSafariVersion && semver.lt(semver.coerce(minSafariVersion), '11.0.0')) ||
  11. (minIOSVersion && semver.lt(semver.coerce(minIOSVersion), '11.0.0'))
  12. const needsSafariFix = supportsSafari10
  13. class SafariNomoduleFixPlugin {
  14. constructor ({ unsafeInline, jsDirectory }) {
  15. this.unsafeInline = unsafeInline
  16. this.jsDirectory = jsDirectory
  17. }
  18. apply (compiler) {
  19. if (!needsSafariFix) {
  20. return
  21. }
  22. const { RawSource } = compiler.webpack
  23. ? compiler.webpack.sources
  24. : require('webpack-sources')
  25. const ID = 'SafariNomoduleFixPlugin'
  26. compiler.hooks.compilation.tap(ID, compilation => {
  27. HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tap(ID, data => {
  28. let scriptTag
  29. if (this.unsafeInline) {
  30. // inject inline Safari 10 nomodule fix
  31. scriptTag = {
  32. tagName: 'script',
  33. closeTag: true,
  34. innerHTML: safariFix
  35. }
  36. } else {
  37. // inject the fix as an external script
  38. const safariFixPath = path.join(this.jsDirectory, 'safari-nomodule-fix.js')
  39. const fullSafariFixPath = path.join(compilation.options.output.publicPath, safariFixPath)
  40. compilation.assets[safariFixPath] = new RawSource(safariFix)
  41. scriptTag = {
  42. tagName: 'script',
  43. closeTag: true,
  44. attributes: {
  45. src: fullSafariFixPath
  46. }
  47. }
  48. }
  49. let tags = data.bodyTags
  50. if (data.plugin.options.scriptLoading === 'defer') {
  51. tags = data.headTags
  52. }
  53. // insert just before the first actual script tag,
  54. // and after all other tags such as `meta`
  55. const firstScriptIndex = tags.findIndex(tag => tag.tagName === 'script')
  56. tags.splice(firstScriptIndex, 0, scriptTag)
  57. })
  58. })
  59. }
  60. }
  61. SafariNomoduleFixPlugin.safariFix = safariFix
  62. module.exports = SafariNomoduleFixPlugin