Skip to content

Commit e2928c4

Browse files
committed
feat: add manifest option
1 parent 7293186 commit e2928c4

37 files changed

+1227
-167
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,22 @@ If the webpack mode is set to `production` the favicons mode will use `webapp`.
225225

226226
This behaviour can be adjusted by setting the favicon `mode` and `devMode` options.
227227

228+
### Custom manifests
229+
230+
The manifest options allows to overwrite values of the generated manifest.json with own values
231+
232+
```javascript
233+
const FaviconsWebpackPlugin = require('favicons-webpack-plugin')
234+
235+
plugins: [
236+
new FaviconsWebpackPlugin({
237+
logo: './src/logo.png',
238+
mode: 'webapp',
239+
manifest: './src/manigest.json'
240+
})
241+
]
242+
```
243+
228244
## Compatibility
229245

230246
favicons-webpack-plugin 2.x is compatible with html-webpack-plugin 3.x
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"name": "webapp-example",
3+
"version": "1.0.0",
4+
"description": "Demo of webpapp webpack plugin",
5+
"scripts": {
6+
},
7+
"keywords": [],
8+
"author": "",
9+
"license": "MIT"
10+
}

example/custom-manifest/src/app.js

Whitespace-only changes.
56.2 KB
Loading
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html>
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<meta http-equiv="X-UA-Compatible" content="ie=edge">
8+
<title>Home</title>
9+
</head>
10+
11+
<body>
12+
</body>
13+
14+
</html>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"name": "FaviconsDemo",
3+
"short_name": "FaviconsDemo",
4+
"description": "Just a demo",
5+
"dir": "auto",
6+
"lang": "en",
7+
"display": "standalone",
8+
"background_color": "#fff",
9+
"theme_color": "#fff",
10+
"orientation": null
11+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const { resolve } = require('path');
2+
const HtmlWebpackPlugin = require('html-webpack-plugin');
3+
const FaviconsWebpackPlugin = require('../../src/');
4+
5+
const webpack = require('webpack');
6+
7+
module.exports = (env, args) => {
8+
return {
9+
context: __dirname,
10+
entry: './src/app.js',
11+
output: {
12+
path: resolve(__dirname, 'public'),
13+
filename: 'app.js',
14+
},
15+
cache: {
16+
type: 'filesystem',
17+
},
18+
plugins: [
19+
new HtmlWebpackPlugin({
20+
filename: 'index.html',
21+
template: './src/index.html',
22+
}),
23+
new FaviconsWebpackPlugin({
24+
logo: './src/favicon.png',
25+
manifest: './src/manifest.json',
26+
mode: 'webapp'
27+
28+
}),
29+
],
30+
stats: "errors-only"
31+
};
32+
}

src/cache.js

Lines changed: 75 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -30,29 +30,27 @@ const faviconCache = new WeakMap();
3030
* Executes the generator function and caches the result in memory
3131
* The cache will be invalidated after the logo source file was modified
3232
*
33-
* @param {import('./options').FaviconWebpackPlugionInternalOptions} faviconOptions
34-
* @param {string} context - the compiler.context patth
35-
* @param {WebpackCompilation} compilation - the current webpack compilation
33+
* @template TResult
34+
*
35+
* @param {string[]} files
3636
* @param {any} pluginInstance - the plugin instance to use as cache key
37-
* @param {(
38-
logoSource: Buffer | string,
39-
compilation: WebpackCompilation,
40-
resolvedPublicPath: string,
41-
outputPath: string
42-
) => Promise<FaviconsCompilationResult>
43-
} generator
37+
* @param {boolean} useWebpackCache - Support webpack built in cache
38+
* @param {WebpackCompilation} compilation - the current webpack compilation
39+
* @param {string[]} eTags - eTags to verify the string
40+
* @param {(files: { filePath: string, hash: string, content: Buffer }[]) => string} idGenerator
41+
* @param {(files: { filePath: string, hash: string, content: Buffer }[], id: string) => Promise<TResult>} generator
4442
*
45-
* @returns {Promise<FaviconsCompilationResult>}
43+
* @returns {Promise<TResult>}
4644
*/
4745
function runCached(
48-
faviconOptions,
49-
context,
50-
compilation,
46+
files,
5147
pluginInstance,
48+
useWebpackCache,
49+
compilation,
50+
eTags,
51+
idGenerator,
5252
generator
5353
) {
54-
const { logo } = faviconOptions;
55-
5654
const latestSnapShot = snapshots.get(pluginInstance);
5755
const cachedFavicons = latestSnapShot && faviconCache.get(latestSnapShot);
5856

@@ -64,10 +62,11 @@ function runCached(
6462
faviconCache.delete(latestSnapShot);
6563

6664
return runCached(
67-
faviconOptions,
68-
context,
69-
compilation,
65+
files,
7066
pluginInstance,
67+
compilation,
68+
idGenerator,
69+
eTags,
7170
generator
7271
);
7372
}
@@ -81,21 +80,19 @@ function runCached(
8180
// to find out if the logo was changed
8281
const newSnapShot = createSnapshot(
8382
{
84-
fileDependencies: [logo],
83+
fileDependencies: files,
8584
contextDependencies: [],
8685
missingDependencies: []
8786
},
8887
compilation
8988
);
9089
snapshots.set(pluginInstance, newSnapShot);
91-
9290
// Start generating the favicons
93-
const faviconsGenerationsPromise = runWithFileCache(
94-
faviconOptions,
95-
context,
96-
compilation,
97-
generator
98-
);
91+
const faviconsGenerationsPromise = useWebpackCache
92+
? runWithFileCache(files, compilation, idGenerator, eTags, generator)
93+
: readFiles(files, compilation).then(fileContents =>
94+
generator(fileContents, idGenerator(fileContents))
95+
);
9996

10097
// Store the promise of the favicon compilation in cache
10198
faviconCache.set(newSnapShot, faviconsGenerationsPromise);
@@ -128,101 +125,68 @@ function createSnapshot(fileDependencies, mainCompilation) {
128125
}
129126

130127
/**
128+
*
129+
* Use the webpack cache which supports filesystem caching to improve build speed
130+
* See also https://webpack.js.org/configuration/other-options/#cache
131+
* Create one cache for every output target
132+
*
131133
* Executes the generator function and stores it in the webpack file cache
134+
* @template TResult
132135
*
133-
* @param {import('./options').FaviconWebpackPlugionInternalOptions} faviconOptions
134-
* @param {string} context - the compiler.context patth
136+
* @param {string[]} files - the file pathes to be watched for changes
135137
* @param {WebpackCompilation} compilation - the current webpack compilation
136-
* @param {(
137-
logoSource: Buffer | string,
138-
compilation: WebpackCompilation,
139-
resolvedPublicPath: string,
140-
outputPath: string
141-
) => Promise<FaviconsCompilationResult>
142-
} generator
138+
* @param {(files: { filePath: string, hash: string, content: Buffer }[]) => string} idGenerator
139+
* @param {string[]} eTags - eTags to verify the string
140+
* @param {(files: { filePath: string, hash: string, content: Buffer }[], id: string) => Promise<TResult>} generator
143141
*
144-
* @returns {Promise<FaviconsCompilationResult>}
142+
* @returns {Promise<TResult>}
145143
*/
146144
async function runWithFileCache(
147-
faviconOptions,
148-
context,
145+
files,
149146
compilation,
147+
idGenerator,
148+
eTags,
150149
generator
151150
) {
152-
const { logo } = faviconOptions;
153-
const logoSource = await new Promise((resolve, reject) =>
154-
compilation.inputFileSystem.readFile(
155-
path.resolve(context, logo),
156-
(error, fileBuffer) => {
157-
if (error) {
158-
reject(error);
159-
} else {
160-
resolve(fileBuffer);
161-
}
162-
}
163-
)
164-
);
165-
166-
const compilationOutputPath =
167-
compilation.outputOptions.path === 'auto'
168-
? ''
169-
: compilation.outputOptions.path || '';
170-
/**
171-
* the relative output path to the folder where the favicon files should be generated to
172-
* it might include tokens like [fullhash] or [contenthash]
173-
*/
174-
const relativeOutputPath = faviconOptions.outputPath
175-
? path.relative(
176-
compilationOutputPath,
177-
path.resolve(compilationOutputPath, faviconOptions.outputPath)
178-
)
179-
: faviconOptions.prefix;
180-
181-
const logoContentHash = getContentHash(logoSource);
182-
const executeGenerator = () => {
183-
const outputPath = replaceContentHash(
184-
compilation,
185-
relativeOutputPath,
186-
logoContentHash
187-
);
188-
const webpackPublicPath =
189-
compilation.outputOptions.publicPath === 'auto'
190-
? ''
191-
: compilation.outputOptions.publicPath;
192-
const resolvedPublicPath = replaceContentHash(
193-
compilation,
194-
resolvePublicPath(
195-
compilation,
196-
faviconOptions.publicPath || webpackPublicPath,
197-
faviconOptions.prefix
198-
),
199-
logoContentHash
200-
);
201-
return generator(logoSource, compilation, resolvedPublicPath, outputPath);
202-
};
203-
204-
if (faviconOptions.cache === false) {
205-
return executeGenerator();
206-
}
207-
151+
const fileSources = await readFiles(files, compilation);
208152
const webpackCache = compilation.getCache('favicons-webpack-plugin');
209153
// Cache invalidation token
210-
const eTag = [
211-
JSON.stringify(faviconOptions.publicPath),
212-
JSON.stringify(faviconOptions.mode),
213-
// Recompile filesystem cache if the user change the favicon options
214-
JSON.stringify(faviconOptions.favicons),
215-
// Recompile filesystem cache if the logo source changes:
216-
logoContentHash
217-
].join('\n');
218-
219-
// Use the webpack cache which supports filesystem caching to improve build speed
220-
// See also https://webpack.js.org/configuration/other-options/#cache
221-
// Create one cache for every output target
222-
return webpackCache.providePromise(
223-
relativeOutputPath,
224-
eTag,
225-
executeGenerator
154+
const eTag = [...eTags, fileSources.map(({ hash }) => hash)].join(' ');
155+
const cacheId = idGenerator(fileSources);
156+
return webpackCache.providePromise(cacheId, eTag, () =>
157+
generator(fileSources, cacheId)
158+
);
159+
}
160+
161+
/**
162+
* readFiles and get content hashes
163+
*
164+
* @param {string[]} files
165+
* @param {WebpackCompilation} compilation
166+
* @returns {Promise<{filePath: string, hash: string, content: Buffer}[]>}
167+
*/
168+
function readFiles(files, compilation) {
169+
return Promise.all(
170+
files.map(filePath =>
171+
!filePath
172+
? { filePath, hash: '', content: '' }
173+
: new Promise((resolve, reject) =>
174+
compilation.inputFileSystem.readFile(
175+
path.resolve(compilation.compiler.context, filePath),
176+
(error, fileBuffer) => {
177+
if (error) {
178+
reject(error);
179+
} else {
180+
resolve({
181+
filePath,
182+
hash: getContentHash(fileBuffer),
183+
content: fileBuffer
184+
});
185+
}
186+
}
187+
)
188+
)
189+
)
226190
);
227191
}
228192

0 commit comments

Comments
 (0)