123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- const ID = 'vue-cli:pwa-html-plugin'
- const defaults = {
- name: 'PWA app',
- themeColor: '#4DBA87', // The Vue color
- msTileColor: '#000000',
- appleMobileWebAppCapable: 'no',
- appleMobileWebAppStatusBarStyle: 'default',
- assetsVersion: '',
- manifestPath: 'manifest.json',
- manifestOptions: {},
- manifestCrossorigin: undefined
- }
- const defaultManifest = {
- icons: [
- {
- 'src': './img/icons/android-chrome-192x192.png',
- 'sizes': '192x192',
- 'type': 'image/png'
- },
- {
- 'src': './img/icons/android-chrome-512x512.png',
- 'sizes': '512x512',
- 'type': 'image/png'
- },
- {
- 'src': './img/icons/android-chrome-maskable-192x192.png',
- 'sizes': '192x192',
- 'type': 'image/png',
- 'purpose': 'maskable'
- },
- {
- 'src': './img/icons/android-chrome-maskable-512x512.png',
- 'sizes': '512x512',
- 'type': 'image/png',
- 'purpose': 'maskable'
- }
- ],
- start_url: '.',
- display: 'standalone',
- background_color: '#000000'
- }
- const defaultIconPaths = {
- favicon32: 'img/icons/favicon-32x32.png',
- favicon16: 'img/icons/favicon-16x16.png',
- appleTouchIcon: 'img/icons/apple-touch-icon-152x152.png',
- maskIcon: 'img/icons/safari-pinned-tab.svg',
- msTileImage: 'img/icons/msapplication-icon-144x144.png'
- }
- module.exports = class HtmlPwaPlugin {
- constructor (options = {}) {
- const iconPaths = Object.assign({}, defaultIconPaths, options.iconPaths)
- delete options.iconPaths
- this.options = Object.assign({ iconPaths: iconPaths }, defaults, options)
- }
- apply (compiler) {
- compiler.hooks.compilation.tap(ID, compilation => {
- compilation.hooks.htmlWebpackPluginBeforeHtmlProcessing.tapAsync(ID, (data, cb) => {
- // wrap favicon in the base template with IE only comment
- data.html = data.html.replace(/<link rel="icon"[^>]+>/, '<!--[if IE]>$&<![endif]-->')
- cb(null, data)
- })
- compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(ID, (data, cb) => {
- const {
- name,
- themeColor,
- msTileColor,
- appleMobileWebAppCapable,
- appleMobileWebAppStatusBarStyle,
- assetsVersion,
- manifestPath,
- iconPaths,
- manifestCrossorigin
- } = this.options
- const { publicPath } = compiler.options.output
- const assetsVersionStr = assetsVersion ? `?v=${assetsVersion}` : ''
- // Favicons
- if (iconPaths.favicon32 != null) {
- data.head.push(makeTag('link', {
- rel: 'icon',
- type: 'image/png',
- sizes: '32x32',
- href: getTagHref(publicPath, iconPaths.favicon32, assetsVersionStr)
- }))
- }
- if (iconPaths.favicon16 != null) {
- data.head.push(makeTag('link', {
- rel: 'icon',
- type: 'image/png',
- sizes: '16x16',
- href: getTagHref(publicPath, iconPaths.favicon16, assetsVersionStr)
- }))
- }
- // Add to home screen for Android and modern mobile browsers
- data.head.push(
- makeTag('link', manifestCrossorigin
- ? {
- rel: 'manifest',
- href: getTagHref(publicPath, manifestPath, assetsVersionStr),
- crossorigin: manifestCrossorigin
- }
- : {
- rel: 'manifest',
- href: getTagHref(publicPath, manifestPath, assetsVersionStr)
- }
- )
- )
- if (themeColor != null) {
- data.head.push(
- makeTag('meta', {
- name: 'theme-color',
- content: themeColor
- })
- )
- }
- // Add to home screen for Safari on iOS
- data.head.push(
- makeTag('meta', {
- name: 'apple-mobile-web-app-capable',
- content: appleMobileWebAppCapable
- }),
- makeTag('meta', {
- name: 'apple-mobile-web-app-status-bar-style',
- content: appleMobileWebAppStatusBarStyle
- }),
- makeTag('meta', {
- name: 'apple-mobile-web-app-title',
- content: name
- })
- )
- if (iconPaths.appleTouchIcon != null) {
- data.head.push(makeTag('link', {
- rel: 'apple-touch-icon',
- href: getTagHref(publicPath, iconPaths.appleTouchIcon, assetsVersionStr)
- }))
- }
- if (iconPaths.maskIcon != null) {
- data.head.push(makeTag('link', {
- rel: 'mask-icon',
- href: getTagHref(publicPath, iconPaths.maskIcon, assetsVersionStr),
- color: themeColor
- }))
- }
- // Add to home screen for Windows
- if (iconPaths.msTileImage != null) {
- data.head.push(makeTag('meta', {
- name: 'msapplication-TileImage',
- content: getTagHref(publicPath, iconPaths.msTileImage, assetsVersionStr)
- }))
- }
- if (msTileColor != null) {
- data.head.push(
- makeTag('meta', {
- name: 'msapplication-TileColor',
- content: msTileColor
- })
- )
- }
- cb(null, data)
- })
- })
- if (!isHrefAbsoluteUrl(this.options.manifestPath)) {
- compiler.hooks.emit.tapAsync(ID, (data, cb) => {
- const {
- name,
- themeColor,
- manifestPath,
- manifestOptions
- } = this.options
- const publicOptions = {
- name,
- short_name: name,
- theme_color: themeColor
- }
- const outputManifest = JSON.stringify(
- Object.assign(publicOptions, defaultManifest, manifestOptions)
- )
- data.assets[manifestPath] = {
- source: () => outputManifest,
- size: () => outputManifest.length
- }
- cb(null, data)
- })
- }
- }
- }
- function makeTag (tagName, attributes, closeTag = false) {
- return {
- tagName,
- closeTag,
- attributes
- }
- }
- function getTagHref (publicPath, href, assetsVersionStr) {
- let tagHref = `${href}${assetsVersionStr}`
- if (!isHrefAbsoluteUrl(href)) {
- tagHref = `${publicPath}${tagHref}`
- }
- return tagHref
- }
- function isHrefAbsoluteUrl (href) {
- return /(http(s?)):\/\//gi.test(href)
- }
|