diff --git a/src/index.js b/src/index.js index 0ba81395..d6660673 100644 --- a/src/index.js +++ b/src/index.js @@ -70,15 +70,19 @@ class FaviconsWebpackPlugin { const defaultLogo = path.resolve(compiler.context, 'logo.png'); try { compiler.inputFileSystem.statSync(defaultLogo); - this.options.logo = defaultLogo; + this.options.logo = [defaultLogo]; } catch (e) {} // @ts-ignore assert( - typeof this.options.logo === 'string', + typeof this.options.logo[0] === 'string', 'Could not find `logo.png` for the current webpack context' ); + } else if (this.options.logo instanceof Array) { + this.options.logo = this.options.logo.map((logo) => + path.resolve(compiler.context, logo) + ); } else { - this.options.logo = path.resolve(compiler.context, this.options.logo); + this.options.logo = [path.resolve(compiler.context, this.options.logo)]; } if (typeof this.options.manifest === 'string') { @@ -95,7 +99,7 @@ class FaviconsWebpackPlugin { async (compilation) => { const faviconCompilation = runCached( [ - this.options.logo, + ...this.options.logo, typeof this.options.manifest === 'string' ? this.options.manifest : '', @@ -110,20 +114,33 @@ class FaviconsWebpackPlugin { // Recompile filesystem cache if the user change the favicon options JSON.stringify(this.options.favicons), ], - // Recompile filesystem cache if the logo source based path change: - ([logo]) => - getRelativeOutputPath(logo.hash, compilation, this.options), - ([logo, manifest], getRelativeOutputPath) => - this.generateFavicons( - logo, - manifest.content, + // Recompile filesystem cache if any source based path change: + (fileSources) => + getRelativeOutputPath( + fileSources[0].hash, + compilation, + this.options + ), + (fileSources, relativeOutputPath) => { + const logoFileSources = fileSources.slice( + 0, + this.options.logo.length + ); + const manifestFileSource = fileSources[this.options.logo.length]; + + return this.generateFavicons( + logoFileSources, + manifestFileSource.content, compilation, - getRelativeOutputPath - ) + relativeOutputPath + ); + } ); // Watch for changes to the logo - compilation.fileDependencies.add(this.options.logo); + for (const logo of this.options.logo) { + compilation.fileDependencies.add(logo); + } // Watch for changes to the base manifest.json if (typeof this.options.manifest === 'string') { @@ -286,12 +303,17 @@ class FaviconsWebpackPlugin { * @param {import('webpack').Compilation} compilation * @param {string} outputPath */ - generateFavicons(logo, baseManifest, compilation, outputPath) { + generateFavicons(logoFileSources, baseManifest, compilation, outputPath) { const resolvedPublicPath = getResolvedPublicPath( - logo.hash, + logoFileSources[0].hash, compilation, this.options ); + + const logoFileSourceContents = logoFileSources.map( + (source) => source.content + ); + /** @type {{[key: string]: any}} - the parsed manifest from options.manifest */ const parsedBaseManifest = typeof this.options.manifest === 'string' @@ -307,7 +329,7 @@ class FaviconsWebpackPlugin { } return this.generateFaviconsLight( - logo.content, + logoFileSourceContents, parsedBaseManifest, compilation, resolvedPublicPath, @@ -318,7 +340,7 @@ class FaviconsWebpackPlugin { webpackLogger(compilation).log('generate favicons'); return this.generateFaviconsWebapp( - logo.content, + logoFileSourceContents, parsedBaseManifest, compilation, resolvedPublicPath, @@ -339,13 +361,13 @@ class FaviconsWebpackPlugin { * @param {string} outputPath */ async generateFaviconsLight( - logoSource, + logoFileSources, baseManifest, compilation, resolvedPublicPath, outputPath ) { - const faviconExt = path.extname(this.options.logo); + const faviconExt = path.extname(this.options.logo[0]); const faviconName = `favicon${faviconExt}`; const RawSource = compilation.compiler.webpack.sources.RawSource; @@ -353,7 +375,7 @@ class FaviconsWebpackPlugin { const assets = [ { name: path.join(outputPath, faviconName), - contents: new RawSource(logoSource, false), + contents: new RawSource(logoFileSources[0], false), }, ]; @@ -398,7 +420,7 @@ class FaviconsWebpackPlugin { * @param {string} outputPath */ async generateFaviconsWebapp( - logoSource, + logoFileSources, baseManifest, compilation, resolvedPublicPath, @@ -406,12 +428,13 @@ class FaviconsWebpackPlugin { ) { const RawSource = compilation.compiler.webpack.sources.RawSource; const { favicons } = loadFaviconsLibrary(); + // Generate favicons using the npm favicons library const { html: tags, images, files, - } = await favicons(logoSource, { + } = await favicons(logoFileSources, { // Generate all assets relative to the root directory // to allow relative manifests and to set the final public path // once it has been provided by the html-webpack-plugin diff --git a/test/logo-array.test.mjs b/test/logo-array.test.mjs new file mode 100644 index 00000000..ff07d2d0 --- /dev/null +++ b/test/logo-array.test.mjs @@ -0,0 +1,24 @@ +import test from 'ava'; +import * as path from 'path'; +import FaviconsWebpackPlugin from '../src/index.js'; +import { + logo, + generate, + withTempDirectory, + snapshotCompilationAssets, +} from './_util.mjs'; + +withTempDirectory(test); + +test('should work with logo array', async (t) => { + const dist = path.join(t.context.root, 'dist'); + const compilationStats = await generate({ + context: t.context.root, + output: { + path: dist, + }, + plugins: [new FaviconsWebpackPlugin({ logo: [logo] })], + }); + + snapshotCompilationAssets(t, compilationStats); +}); diff --git a/test/snapshots/logo-array.test.mjs.md b/test/snapshots/logo-array.test.mjs.md new file mode 100644 index 00000000..2c0f0f22 --- /dev/null +++ b/test/snapshots/logo-array.test.mjs.md @@ -0,0 +1,341 @@ +# Snapshot report for `test/logo-array.test.mjs` + +The actual snapshot is saved in `logo-array.test.mjs.snap`. + +Generated by [AVA](https://avajs.dev). + +## should work with logo array + +> Snapshot 1 + + [ + 'assets/android-chrome-144x144.png', + 'assets/android-chrome-192x192.png', + 'assets/android-chrome-256x256.png', + 'assets/android-chrome-36x36.png', + 'assets/android-chrome-384x384.png', + 'assets/android-chrome-48x48.png', + 'assets/android-chrome-512x512.png', + 'assets/android-chrome-72x72.png', + 'assets/android-chrome-96x96.png', + 'assets/apple-touch-icon-1024x1024.png', + 'assets/apple-touch-icon-114x114.png', + 'assets/apple-touch-icon-120x120.png', + 'assets/apple-touch-icon-144x144.png', + 'assets/apple-touch-icon-152x152.png', + 'assets/apple-touch-icon-167x167.png', + 'assets/apple-touch-icon-180x180.png', + 'assets/apple-touch-icon-57x57.png', + 'assets/apple-touch-icon-60x60.png', + 'assets/apple-touch-icon-72x72.png', + 'assets/apple-touch-icon-76x76.png', + 'assets/apple-touch-icon-precomposed.png', + 'assets/apple-touch-icon.png', + 'assets/apple-touch-startup-image-1125x2436.png', + 'assets/apple-touch-startup-image-1136x640.png', + 'assets/apple-touch-startup-image-1170x2532.png', + 'assets/apple-touch-startup-image-1242x2208.png', + 'assets/apple-touch-startup-image-1242x2688.png', + 'assets/apple-touch-startup-image-1284x2778.png', + 'assets/apple-touch-startup-image-1334x750.png', + 'assets/apple-touch-startup-image-1536x2048.png', + 'assets/apple-touch-startup-image-1620x2160.png', + 'assets/apple-touch-startup-image-1668x2224.png', + 'assets/apple-touch-startup-image-1668x2388.png', + 'assets/apple-touch-startup-image-1792x828.png', + 'assets/apple-touch-startup-image-2048x1536.png', + 'assets/apple-touch-startup-image-2048x2732.png', + 'assets/apple-touch-startup-image-2160x1620.png', + 'assets/apple-touch-startup-image-2208x1242.png', + 'assets/apple-touch-startup-image-2224x1668.png', + 'assets/apple-touch-startup-image-2388x1668.png', + 'assets/apple-touch-startup-image-2436x1125.png', + 'assets/apple-touch-startup-image-2532x1170.png', + 'assets/apple-touch-startup-image-2688x1242.png', + 'assets/apple-touch-startup-image-2732x2048.png', + 'assets/apple-touch-startup-image-2778x1284.png', + 'assets/apple-touch-startup-image-640x1136.png', + 'assets/apple-touch-startup-image-750x1334.png', + 'assets/apple-touch-startup-image-828x1792.png', + 'assets/browserconfig.xml', + 'assets/favicon-16x16.png', + 'assets/favicon-32x32.png', + 'assets/favicon-48x48.png', + 'assets/favicon.ico', + 'assets/manifest.webmanifest', + 'assets/mstile-144x144.png', + 'assets/mstile-150x150.png', + 'assets/mstile-310x150.png', + 'assets/mstile-310x310.png', + 'assets/mstile-70x70.png', + 'assets/yandex-browser-50x50.png', + 'assets/yandex-browser-manifest.json', + 'main.js', + ] + +> Snapshot 2 + + [ + { + assetName: 'assets/android-chrome-144x144.png', + content: 'png 144x144', + }, + { + assetName: 'assets/android-chrome-192x192.png', + content: 'png 192x192', + }, + { + assetName: 'assets/android-chrome-256x256.png', + content: 'png 256x256', + }, + { + assetName: 'assets/android-chrome-36x36.png', + content: 'png 36x36', + }, + { + assetName: 'assets/android-chrome-384x384.png', + content: 'png 384x384', + }, + { + assetName: 'assets/android-chrome-48x48.png', + content: 'png 48x48', + }, + { + assetName: 'assets/android-chrome-512x512.png', + content: 'png 512x512', + }, + { + assetName: 'assets/android-chrome-72x72.png', + content: 'png 72x72', + }, + { + assetName: 'assets/android-chrome-96x96.png', + content: 'png 96x96', + }, + { + assetName: 'assets/apple-touch-icon-1024x1024.png', + content: 'png 1024x1024', + }, + { + assetName: 'assets/apple-touch-icon-114x114.png', + content: 'png 114x114', + }, + { + assetName: 'assets/apple-touch-icon-120x120.png', + content: 'png 120x120', + }, + { + assetName: 'assets/apple-touch-icon-144x144.png', + content: 'png 144x144', + }, + { + assetName: 'assets/apple-touch-icon-152x152.png', + content: 'png 152x152', + }, + { + assetName: 'assets/apple-touch-icon-167x167.png', + content: 'png 167x167', + }, + { + assetName: 'assets/apple-touch-icon-180x180.png', + content: 'png 180x180', + }, + { + assetName: 'assets/apple-touch-icon-57x57.png', + content: 'png 57x57', + }, + { + assetName: 'assets/apple-touch-icon-60x60.png', + content: 'png 60x60', + }, + { + assetName: 'assets/apple-touch-icon-72x72.png', + content: 'png 72x72', + }, + { + assetName: 'assets/apple-touch-icon-76x76.png', + content: 'png 76x76', + }, + { + assetName: 'assets/apple-touch-icon-precomposed.png', + content: 'png 180x180', + }, + { + assetName: 'assets/apple-touch-icon.png', + content: 'png 180x180', + }, + { + assetName: 'assets/apple-touch-startup-image-1125x2436.png', + content: 'png 1125x2436', + }, + { + assetName: 'assets/apple-touch-startup-image-1136x640.png', + content: 'png 1136x640', + }, + { + assetName: 'assets/apple-touch-startup-image-1170x2532.png', + content: 'png 1170x2532', + }, + { + assetName: 'assets/apple-touch-startup-image-1242x2208.png', + content: 'png 1242x2208', + }, + { + assetName: 'assets/apple-touch-startup-image-1242x2688.png', + content: 'png 1242x2688', + }, + { + assetName: 'assets/apple-touch-startup-image-1284x2778.png', + content: 'png 1284x2778', + }, + { + assetName: 'assets/apple-touch-startup-image-1334x750.png', + content: 'png 1334x750', + }, + { + assetName: 'assets/apple-touch-startup-image-1536x2048.png', + content: 'png 1536x2048', + }, + { + assetName: 'assets/apple-touch-startup-image-1620x2160.png', + content: 'png 1620x2160', + }, + { + assetName: 'assets/apple-touch-startup-image-1668x2224.png', + content: 'png 1668x2224', + }, + { + assetName: 'assets/apple-touch-startup-image-1668x2388.png', + content: 'png 1668x2388', + }, + { + assetName: 'assets/apple-touch-startup-image-1792x828.png', + content: 'png 1792x828', + }, + { + assetName: 'assets/apple-touch-startup-image-2048x1536.png', + content: 'png 2048x1536', + }, + { + assetName: 'assets/apple-touch-startup-image-2048x2732.png', + content: 'png 2048x2732', + }, + { + assetName: 'assets/apple-touch-startup-image-2160x1620.png', + content: 'png 2160x1620', + }, + { + assetName: 'assets/apple-touch-startup-image-2208x1242.png', + content: 'png 2208x1242', + }, + { + assetName: 'assets/apple-touch-startup-image-2224x1668.png', + content: 'png 2224x1668', + }, + { + assetName: 'assets/apple-touch-startup-image-2388x1668.png', + content: 'png 2388x1668', + }, + { + assetName: 'assets/apple-touch-startup-image-2436x1125.png', + content: 'png 2436x1125', + }, + { + assetName: 'assets/apple-touch-startup-image-2532x1170.png', + content: 'png 2532x1170', + }, + { + assetName: 'assets/apple-touch-startup-image-2688x1242.png', + content: 'png 2688x1242', + }, + { + assetName: 'assets/apple-touch-startup-image-2732x2048.png', + content: 'png 2732x2048', + }, + { + assetName: 'assets/apple-touch-startup-image-2778x1284.png', + content: 'png 2778x1284', + }, + { + assetName: 'assets/apple-touch-startup-image-640x1136.png', + content: 'png 640x1136', + }, + { + assetName: 'assets/apple-touch-startup-image-750x1334.png', + content: 'png 750x1334', + }, + { + assetName: 'assets/apple-touch-startup-image-828x1792.png', + content: 'png 828x1792', + }, + { + assetName: 'assets/browserconfig.xml', + content: `␊ + ␊ + ␊ + ␊ + ␊ + ␊ + ␊ + ␊ + #fff␊ + ␊ + ␊ + `, + }, + { + assetName: 'assets/favicon-16x16.png', + content: 'png 16x16', + }, + { + assetName: 'assets/favicon-32x32.png', + content: 'png 32x32', + }, + { + assetName: 'assets/favicon-48x48.png', + content: 'png 48x48', + }, + { + assetName: 'assets/favicon.ico', + content: 'ico 16x16', + }, + { + assetName: 'assets/manifest.webmanifest', + content: 'binary assets/manifest.webmanifest', + }, + { + assetName: 'assets/mstile-144x144.png', + content: 'png 144x144', + }, + { + assetName: 'assets/mstile-150x150.png', + content: 'png 150x150', + }, + { + assetName: 'assets/mstile-310x150.png', + content: 'png 310x150', + }, + { + assetName: 'assets/mstile-310x310.png', + content: 'png 310x310', + }, + { + assetName: 'assets/mstile-70x70.png', + content: 'png 70x70', + }, + { + assetName: 'assets/yandex-browser-50x50.png', + content: 'png 50x50', + }, + { + assetName: 'assets/yandex-browser-manifest.json', + content: `{␊ + "api_version": 1,␊ + "layout": {␊ + "logo": "yandex-browser-50x50.png",␊ + "color": "#fff",␊ + "show_title": true␊ + }␊ + }`, + }, + ] diff --git a/test/snapshots/logo-array.test.mjs.snap b/test/snapshots/logo-array.test.mjs.snap new file mode 100644 index 00000000..bcad7b74 Binary files /dev/null and b/test/snapshots/logo-array.test.mjs.snap differ