@videinfra/static-website-builder 2.0.9 → 2.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
package/tasks/sitemap/task.js
CHANGED
|
@@ -2,7 +2,7 @@ import gulp from 'gulp';
|
|
|
2
2
|
import gulpif from 'gulp-if';
|
|
3
3
|
import nanomemoize from 'nano-memoize';
|
|
4
4
|
import ignore from 'gulp-ignore';
|
|
5
|
-
import gulpSitemap from 'gulp-sitemap';
|
|
5
|
+
import gulpSitemap from '../../vendor/gulp-sitemap/index.js';
|
|
6
6
|
|
|
7
7
|
import { getDestPath } from './../../lib/get-path.js';
|
|
8
8
|
import { getTaskConfig } from './../../lib/get-config.js';
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) Gilad Peleg <gilad@giladpeleg.com> (https://www.giladpeleg.com)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# [gulp](https://github.com/wearefractal/gulp)-sitemap
|
|
2
|
+
> Generate a search engine friendly sitemap.xml using a Gulp stream
|
|
3
|
+
|
|
4
|
+
[](https://www.npmjs.org/package/gulp-sitemap)
|
|
5
|
+
[](https://www.npmjs.org/package/gulp-sitemap)
|
|
6
|
+
[](https://travis-ci.org/pgilad/gulp-sitemap)
|
|
7
|
+
|
|
8
|
+
Easily generate a search engine friendly sitemap.xml from your project.
|
|
9
|
+
|
|
10
|
+
:bowtie: Search engines love the sitemap.xml and it helps SEO as well.
|
|
11
|
+
|
|
12
|
+
For information about sitemap properties and structure, see the [wiki for sitemaps](http://www.wikiwand.com/en/Sitemaps)
|
|
13
|
+
|
|
14
|
+
## Install
|
|
15
|
+
|
|
16
|
+
Install with [npm](https://npmjs.org/package/gulp-sitemap)
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
$ npm install --save-dev gulp-sitemap
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Example
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
var gulp = require('gulp');
|
|
26
|
+
var sitemap = require('gulp-sitemap');
|
|
27
|
+
|
|
28
|
+
gulp.task('sitemap', function () {
|
|
29
|
+
gulp.src('build/**/*.html', {
|
|
30
|
+
read: false
|
|
31
|
+
})
|
|
32
|
+
.pipe(sitemap({
|
|
33
|
+
siteUrl: 'http://www.amazon.com'
|
|
34
|
+
}))
|
|
35
|
+
.pipe(gulp.dest('./build'));
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
* `siteUrl` is required.
|
|
40
|
+
* `index.html` will be turned into directory path `/`.
|
|
41
|
+
* `404.html` will be skipped automatically. No need to unglob it.
|
|
42
|
+
|
|
43
|
+
Let's see an example of how we can create and output a sitemap, and then return to the original stream files:
|
|
44
|
+
```js
|
|
45
|
+
var gulp = require('gulp');
|
|
46
|
+
var sitemap = require('gulp-sitemap');
|
|
47
|
+
var save = require('gulp-save');
|
|
48
|
+
|
|
49
|
+
gulp.task('html', function() {
|
|
50
|
+
gulp.src('*.html', {
|
|
51
|
+
read: false
|
|
52
|
+
})
|
|
53
|
+
.pipe(save('before-sitemap'))
|
|
54
|
+
.pipe(sitemap({
|
|
55
|
+
siteUrl: 'http://www.amazon.com'
|
|
56
|
+
})) // Returns sitemap.xml
|
|
57
|
+
.pipe(gulp.dest('./dist'))
|
|
58
|
+
.pipe(save.restore('before-sitemap')) //restore all files to the state when we cached them
|
|
59
|
+
// -> continue stream with original html files
|
|
60
|
+
// ...
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Options
|
|
65
|
+
|
|
66
|
+
### siteUrl
|
|
67
|
+
|
|
68
|
+
Your website's base url. This gets prepended to all documents locations.
|
|
69
|
+
|
|
70
|
+
Type: `string`
|
|
71
|
+
|
|
72
|
+
Required: `true`
|
|
73
|
+
|
|
74
|
+
### fileName
|
|
75
|
+
|
|
76
|
+
Determine the output filename for the sitemap.
|
|
77
|
+
|
|
78
|
+
Type: `string`
|
|
79
|
+
|
|
80
|
+
Default: `sitemap.xml`
|
|
81
|
+
|
|
82
|
+
Required: `false`
|
|
83
|
+
|
|
84
|
+
### changefreq
|
|
85
|
+
|
|
86
|
+
Gets filled inside the sitemap in the tag `<changefreq>`. Not added by default.
|
|
87
|
+
|
|
88
|
+
Type: `string`
|
|
89
|
+
|
|
90
|
+
Default: `undefined`
|
|
91
|
+
|
|
92
|
+
Valid Values: `['always', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'never']`
|
|
93
|
+
|
|
94
|
+
Required: `false`
|
|
95
|
+
|
|
96
|
+
**Note: any falsey value is also valid and will skip this xml tag**
|
|
97
|
+
|
|
98
|
+
### priority
|
|
99
|
+
|
|
100
|
+
Gets filled inside the sitemap in the tag `<priority>`. Not added by default.
|
|
101
|
+
|
|
102
|
+
Type: `string|function`
|
|
103
|
+
|
|
104
|
+
Default: `undefined`
|
|
105
|
+
|
|
106
|
+
Valid Values: `0.0` to `1.0`
|
|
107
|
+
|
|
108
|
+
Required: `false`
|
|
109
|
+
|
|
110
|
+
**Note: any falsey (non-zero) value is also valid and will skip this xml tag**
|
|
111
|
+
|
|
112
|
+
Example using a function as `priority`:
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
```js
|
|
116
|
+
priority: function(siteUrl, loc, entry) {
|
|
117
|
+
// Give pages inside root path (i.e. no slashes) a higher priority
|
|
118
|
+
return loc.split('/').length === 0 ? 1 : 0.5;
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### lastmod
|
|
123
|
+
|
|
124
|
+
The file last modified time.
|
|
125
|
+
|
|
126
|
+
- If `null` then this plugin will try to get the last modified time from the stream vinyl file, or use `Date.now()` as lastmod.
|
|
127
|
+
- If the value is not `null` - It will be used as lastmod.
|
|
128
|
+
- When `lastmod` is a function, it is executed with the current file given as parameter. (Note: the function is expected to be sync).
|
|
129
|
+
- A string can be used to manually set a fixed `lastmod`.
|
|
130
|
+
|
|
131
|
+
Type: `string|datetime|function`
|
|
132
|
+
|
|
133
|
+
Default: `null`
|
|
134
|
+
|
|
135
|
+
Required: `false`
|
|
136
|
+
|
|
137
|
+
Example that uses git to get lastmod from the latest commit of a file:
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
lastmod: function(file) {
|
|
141
|
+
var cmd = 'git log -1 --format=%cI "' + file.relative + '"';
|
|
142
|
+
return execSync(cmd, {
|
|
143
|
+
cwd: file.base
|
|
144
|
+
}).toString().trim();
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Note: any falsey (other than null) value is also valid and will skip this xml tag**
|
|
149
|
+
|
|
150
|
+
### newLine
|
|
151
|
+
|
|
152
|
+
How to join line in the target sitemap file.
|
|
153
|
+
|
|
154
|
+
Type: `string`
|
|
155
|
+
|
|
156
|
+
Default: Your OS's new line, mostly: `\n`
|
|
157
|
+
|
|
158
|
+
Required: `false`
|
|
159
|
+
|
|
160
|
+
### spacing
|
|
161
|
+
|
|
162
|
+
How should the sitemap xml file be spaced. You can use `\t` for tabs, or ` ` with 2
|
|
163
|
+
spaces if you'd like.
|
|
164
|
+
|
|
165
|
+
Type: `string`
|
|
166
|
+
|
|
167
|
+
Default: ` ` (4 spaces)
|
|
168
|
+
|
|
169
|
+
Required: `false`
|
|
170
|
+
|
|
171
|
+
### noindex
|
|
172
|
+
|
|
173
|
+
Exclude pages from the sitemap when the `robots` meta tag is set to `noindex`. The plugin needs to be able to read the contents of the files for this to have an effect.
|
|
174
|
+
|
|
175
|
+
Type: `boolean`
|
|
176
|
+
|
|
177
|
+
Default: `false`
|
|
178
|
+
|
|
179
|
+
Required: `false`
|
|
180
|
+
|
|
181
|
+
### images
|
|
182
|
+
|
|
183
|
+
For generate sitemap for images per page, just enable images flag to `true`
|
|
184
|
+
|
|
185
|
+
Type: `boolean`
|
|
186
|
+
|
|
187
|
+
Default: `undefined`
|
|
188
|
+
|
|
189
|
+
Required: `false`
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
### mappings
|
|
193
|
+
|
|
194
|
+
An object to custom map pages to their own configuration.
|
|
195
|
+
|
|
196
|
+
This should be an array with the following structure:
|
|
197
|
+
|
|
198
|
+
Type: `array`
|
|
199
|
+
|
|
200
|
+
Default: `[]`
|
|
201
|
+
|
|
202
|
+
Required: `false`
|
|
203
|
+
|
|
204
|
+
Example:
|
|
205
|
+
|
|
206
|
+
```js
|
|
207
|
+
mappings: [{
|
|
208
|
+
pages: [ 'minimatch pattern' ],
|
|
209
|
+
changefreq: 'hourly',
|
|
210
|
+
priority: 0.5,
|
|
211
|
+
lastmod: Date.now(),
|
|
212
|
+
getLoc(siteUrl, loc, entry) {
|
|
213
|
+
// Removes the file extension if it exists
|
|
214
|
+
return loc.replace(/\.\w+$/, '');
|
|
215
|
+
},
|
|
216
|
+
hreflang: [{
|
|
217
|
+
lang: 'ru',
|
|
218
|
+
getHref(siteUrl, file, lang, loc) {
|
|
219
|
+
return 'http://www.amazon.ru/' + file;
|
|
220
|
+
}
|
|
221
|
+
}]
|
|
222
|
+
},
|
|
223
|
+
//....
|
|
224
|
+
]
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
- Every file will be matched against the supplied patterns
|
|
228
|
+
- Only defined attributes for a matched file are applied.
|
|
229
|
+
- Only the first match will apply, so consequent matches for the filename will not apply.
|
|
230
|
+
- Possible attributes to set: `hreflang`, `changefreq`, `priority`, `loc` and `lastmod`.
|
|
231
|
+
- All rules applying to [options](#options) apply to the attributes that can overridden.
|
|
232
|
+
|
|
233
|
+
##### pages
|
|
234
|
+
|
|
235
|
+
Type: `array`
|
|
236
|
+
|
|
237
|
+
Required: `true`
|
|
238
|
+
|
|
239
|
+
This is an array with [minimatch](https://github.com/isaacs/minimatch) patterns to match the
|
|
240
|
+
relevant pages to override.
|
|
241
|
+
Every file will be matched against the supplied patterns.
|
|
242
|
+
|
|
243
|
+
Uses [multimatch](https://github.com/sindresorhus/multimatch) to match patterns against filenames.
|
|
244
|
+
|
|
245
|
+
Example: `pages: ['home/index.html', 'home/see-*.html', '!home/see-admin.html']`
|
|
246
|
+
|
|
247
|
+
##### hreflang
|
|
248
|
+
|
|
249
|
+
Matching pages can get their `hreflang` tags set using this option.
|
|
250
|
+
|
|
251
|
+
The input is an array like so:
|
|
252
|
+
|
|
253
|
+
```js
|
|
254
|
+
hreflang: [{
|
|
255
|
+
lang: 'ru',
|
|
256
|
+
getHref: function(siteUrl, file, lang, loc) {
|
|
257
|
+
// return href src for the hreflang. For example:
|
|
258
|
+
return 'http://www.amazon.ru/' + file;
|
|
259
|
+
}
|
|
260
|
+
}]
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
##### getLoc
|
|
264
|
+
|
|
265
|
+
Matching pages can get their `loc` tag modified by using a function.
|
|
266
|
+
|
|
267
|
+
```js
|
|
268
|
+
getLoc: function(siteUrl, loc, entry) {
|
|
269
|
+
return loc.replace(/\.\w+$/, '');
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
#### verbose
|
|
274
|
+
|
|
275
|
+
Type: `boolean`
|
|
276
|
+
|
|
277
|
+
Required: `false`
|
|
278
|
+
|
|
279
|
+
Default: `false`
|
|
280
|
+
|
|
281
|
+
If true, will log the number of files that where handled.
|
|
282
|
+
|
|
283
|
+
## Complementary plugins
|
|
284
|
+
|
|
285
|
+
- [gulp-sitemap-files](https://github.com/adam-lynch/gulp-sitemap-files) - Get all files listed in a sitemap (Perhaps one generated from this plugin)
|
|
286
|
+
|
|
287
|
+
## Thanks
|
|
288
|
+
|
|
289
|
+
To [grunt-sitemap](https://github.com/RayViljoen/grunt-sitemap) for the inspiration on writing this.
|
|
290
|
+
|
|
291
|
+
## License
|
|
292
|
+
|
|
293
|
+
MIT © [Gilad Peleg](https://www.giladpeleg.com)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const defaults = require('lodash/defaults');
|
|
4
|
+
const log = require('fancy-log');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const PluginError = require('plugin-error');
|
|
7
|
+
const through = require('through2');
|
|
8
|
+
const Vinyl = require('vinyl');
|
|
9
|
+
|
|
10
|
+
const pluginName = 'gulp-sitemap';
|
|
11
|
+
const sitemap = require('./lib/sitemap');
|
|
12
|
+
|
|
13
|
+
module.exports = function (options = {}) {
|
|
14
|
+
const config = defaults({}, options, {
|
|
15
|
+
changefreq: undefined,
|
|
16
|
+
fileName: 'sitemap.xml',
|
|
17
|
+
lastmod: null,
|
|
18
|
+
mappings: [],
|
|
19
|
+
newLine: '\n',
|
|
20
|
+
priority: undefined,
|
|
21
|
+
spacing: ' ',
|
|
22
|
+
verbose: false,
|
|
23
|
+
noindex: false
|
|
24
|
+
});
|
|
25
|
+
const entries = [];
|
|
26
|
+
let firstFile;
|
|
27
|
+
let msg;
|
|
28
|
+
|
|
29
|
+
if (!config.siteUrl) {
|
|
30
|
+
msg = 'siteUrl is a required param';
|
|
31
|
+
throw new PluginError(pluginName, msg);
|
|
32
|
+
}
|
|
33
|
+
if (options.changeFreq) {
|
|
34
|
+
msg = chalk.magenta('changeFreq') + ' has been deprecated. Please use ' + chalk.cyan('changefreq');
|
|
35
|
+
throw new PluginError(pluginName, msg);
|
|
36
|
+
}
|
|
37
|
+
// site url should have a trailing slash
|
|
38
|
+
if (config.siteUrl.slice(-1) !== '/') {
|
|
39
|
+
config.siteUrl = config.siteUrl + '/';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return through.obj(function (file, enc, callback) {
|
|
43
|
+
//we handle null files (that have no contents), but not dirs
|
|
44
|
+
if (file.isDirectory()) {
|
|
45
|
+
return callback(null, file);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (file.isStream()) {
|
|
49
|
+
msg = 'Streaming not supported';
|
|
50
|
+
return callback(new PluginError(pluginName), msg);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//skip 404 file
|
|
54
|
+
if (/404\.html?$/i.test(file.relative)) {
|
|
55
|
+
return callback();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if(options.noindex){
|
|
59
|
+
const contents = file.contents.toString();
|
|
60
|
+
if (/<meta [^>]*?noindex/i.test(contents)) {
|
|
61
|
+
return callback();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (!firstFile) {
|
|
66
|
+
firstFile = file;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const entry = sitemap.getEntryConfig(file, config);
|
|
70
|
+
entries.push(entry);
|
|
71
|
+
callback();
|
|
72
|
+
},
|
|
73
|
+
function (callback) {
|
|
74
|
+
if (!firstFile) {
|
|
75
|
+
return callback();
|
|
76
|
+
}
|
|
77
|
+
const contents = sitemap.prepareSitemap(entries, config);
|
|
78
|
+
if (options.verbose) {
|
|
79
|
+
msg = 'Files in sitemap: ' + entries.length;
|
|
80
|
+
log(pluginName, msg);
|
|
81
|
+
}
|
|
82
|
+
//create and push new vinyl file for sitemap
|
|
83
|
+
this.push(new Vinyl({
|
|
84
|
+
cwd: firstFile.cwd,
|
|
85
|
+
base: firstFile.cwd,
|
|
86
|
+
path: path.join(firstFile.cwd, config.fileName),
|
|
87
|
+
contents: Buffer.from(contents)
|
|
88
|
+
}));
|
|
89
|
+
callback();
|
|
90
|
+
});
|
|
91
|
+
};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Changes by Kaspars Zuks:
|
|
3
|
+
* - Removed xmlns:image attribute from `urlset` if images is false
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const defaults = require('lodash/defaults');
|
|
8
|
+
const find = require('lodash/find');
|
|
9
|
+
const includes = require('lodash/includes');
|
|
10
|
+
const multimatch = require('multimatch');
|
|
11
|
+
const slash = require('slash');
|
|
12
|
+
const pick = require('lodash/pick');
|
|
13
|
+
|
|
14
|
+
const header = [
|
|
15
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
16
|
+
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const headerHref = [
|
|
20
|
+
'<?xml version="1.0" encoding="UTF-8"?>',
|
|
21
|
+
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">'
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
const footer = ['</urlset>'];
|
|
25
|
+
const allowedProperties = ['getLoc', 'lastmod', 'priority', 'changefreq', 'hreflang'];
|
|
26
|
+
|
|
27
|
+
function getEntryConfig(file, siteConfig) {
|
|
28
|
+
const relativePath = file.relative;
|
|
29
|
+
const mappingsForFile = find(siteConfig.mappings, function(item) {
|
|
30
|
+
return multimatch(relativePath, item.pages).length > 0;
|
|
31
|
+
}) || {};
|
|
32
|
+
|
|
33
|
+
const entry = defaults(
|
|
34
|
+
{},
|
|
35
|
+
pick(mappingsForFile, allowedProperties),
|
|
36
|
+
pick(siteConfig, allowedProperties)
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
// if images enabled add headerHref
|
|
40
|
+
if (siteConfig.images) {
|
|
41
|
+
header[1] = '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">';
|
|
42
|
+
headerHref[1] = '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (entry.lastmod === null) {
|
|
46
|
+
// calculate mtime manually
|
|
47
|
+
entry.lastmod = file.stat && file.stat.mtime || Date.now();
|
|
48
|
+
} else if (typeof entry.lastmod === 'function') {
|
|
49
|
+
entry.lastmod = entry.lastmod(file);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//turn index.html into -> /
|
|
53
|
+
let relativeFile = relativePath.replace(/(\/|\\|^)index\.html?$/, '/');
|
|
54
|
+
if (relativeFile === '/') {
|
|
55
|
+
relativeFile = '';
|
|
56
|
+
}
|
|
57
|
+
//url location. Use slash to convert windows \\ or \ to /
|
|
58
|
+
const adjustedFile = slash(relativeFile);
|
|
59
|
+
entry.loc = siteConfig.siteUrl + adjustedFile;
|
|
60
|
+
entry.file = adjustedFile;
|
|
61
|
+
entry.source = file.history[0];
|
|
62
|
+
|
|
63
|
+
return entry;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function wrapTag(tag, value) {
|
|
67
|
+
return `
|
|
68
|
+
<${ tag }>${ value }</${ tag }>
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function createImageSitemap(imageURL) {
|
|
73
|
+
return `
|
|
74
|
+
<image:image>
|
|
75
|
+
<image:loc>${imageURL}</image:loc>
|
|
76
|
+
</image:image>
|
|
77
|
+
`;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function notIsHTTPURL(text) {
|
|
81
|
+
return !(/https?:\/\//ig).test(text);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function getImagesUrl(entry, siteConfig) {
|
|
85
|
+
const reImageMatch = /<img\s+src="((https?:\/\/)?[\w\.\/\-@\?=&]+)"/ig;
|
|
86
|
+
const reSourceMatch = /"((https?:\/\/)?[\w\.\/\-@\?=&]+)"/ig;
|
|
87
|
+
const html = fs.readFileSync(entry.source, { encoding : 'utf8'})
|
|
88
|
+
const images = html.match(reImageMatch);
|
|
89
|
+
|
|
90
|
+
if (images === null) {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const URLs = images.map(image => {
|
|
95
|
+
let currentURL = image.match(reSourceMatch)[0].replace(/^\"|\"$/ig, '');
|
|
96
|
+
|
|
97
|
+
if (notIsHTTPURL(currentURL)) {
|
|
98
|
+
currentURL = currentURL.replace(/^\/|\.\//, '');
|
|
99
|
+
currentURL = siteConfig.siteUrl + currentURL;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return currentURL;
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
return URLs;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function generateImagesMap(entry, siteConfig) {
|
|
109
|
+
let imagesURLS = [];
|
|
110
|
+
let XMLImageList = '';
|
|
111
|
+
|
|
112
|
+
// Crawling page for images
|
|
113
|
+
imagesURLS = getImagesUrl(entry, siteConfig);
|
|
114
|
+
|
|
115
|
+
// if truthy create image sitemap
|
|
116
|
+
if (imagesURLS.length) {
|
|
117
|
+
XMLImageList = imagesURLS.map(imageURL => createImageSitemap(imageURL)).join('')
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return XMLImageList;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* processEntry
|
|
125
|
+
*
|
|
126
|
+
* @param entry
|
|
127
|
+
* @param siteConfig
|
|
128
|
+
* @return {string}
|
|
129
|
+
*/
|
|
130
|
+
function processEntry(entry, siteConfig) {
|
|
131
|
+
const returnArr = [siteConfig.spacing + '<url>'];
|
|
132
|
+
|
|
133
|
+
const loc = entry.getLoc ? entry.getLoc(siteConfig.siteUrl, entry.loc, entry) : entry.loc;
|
|
134
|
+
returnArr.push(siteConfig.spacing + siteConfig.spacing + wrapTag('loc', loc) + (siteConfig.images ? generateImagesMap(entry, siteConfig) : ''));
|
|
135
|
+
|
|
136
|
+
let lastmod = entry.lastmod;
|
|
137
|
+
if (lastmod) {
|
|
138
|
+
//format mtime to ISO (same as +00:00)
|
|
139
|
+
lastmod = new Date(lastmod).toISOString();
|
|
140
|
+
returnArr.push(siteConfig.spacing + siteConfig.spacing + wrapTag('lastmod', lastmod));
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const changefreq = entry.changefreq;
|
|
144
|
+
if (changefreq) {
|
|
145
|
+
returnArr.push(siteConfig.spacing + siteConfig.spacing + wrapTag('changefreq', changefreq));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let priority;
|
|
149
|
+
|
|
150
|
+
if (typeof entry.priority === 'function') {
|
|
151
|
+
priority = entry.priority(siteConfig.siteUrl, entry.loc, entry);
|
|
152
|
+
} else if (typeof entry.priority !== 'undefined') {
|
|
153
|
+
priority = entry.priority;
|
|
154
|
+
}
|
|
155
|
+
if (typeof priority !== 'undefined') {
|
|
156
|
+
returnArr.push(siteConfig.spacing + siteConfig.spacing + wrapTag('priority', priority));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const hreflang = entry.hreflang;
|
|
160
|
+
if (hreflang && hreflang.length > 0) {
|
|
161
|
+
const file = entry.file;
|
|
162
|
+
hreflang.forEach(function(item) {
|
|
163
|
+
const href = item.getHref(siteConfig.siteUrl, file, item.lang, loc);
|
|
164
|
+
const tag = '<xhtml:link rel="alternate" hreflang="' + item.lang + '" href="' + href + '" />';
|
|
165
|
+
returnArr.push(siteConfig.spacing + siteConfig.spacing + tag);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
returnArr.push(siteConfig.spacing + '</url>');
|
|
170
|
+
return returnArr.join(siteConfig.newLine);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function prepareSitemap(entries, config) {
|
|
174
|
+
const entriesHref = entries.some(function(entry) {
|
|
175
|
+
return entry && entry.hreflang && entry.hreflang.length;
|
|
176
|
+
});
|
|
177
|
+
return (entriesHref ? headerHref : header)
|
|
178
|
+
.concat(entries.map(function(entry) {
|
|
179
|
+
return processEntry(entry, config);
|
|
180
|
+
}))
|
|
181
|
+
.concat(footer)
|
|
182
|
+
.join(config.newLine)
|
|
183
|
+
.toString();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const VALID_CHANGE_FREQUENCIES = [
|
|
187
|
+
'always',
|
|
188
|
+
'hourly',
|
|
189
|
+
'daily',
|
|
190
|
+
'weekly',
|
|
191
|
+
'monthly',
|
|
192
|
+
'yearly',
|
|
193
|
+
'never'
|
|
194
|
+
];
|
|
195
|
+
|
|
196
|
+
function isChangefreqValid(changefreq) {
|
|
197
|
+
// empty changefreq is valid
|
|
198
|
+
if (!changefreq) {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
return includes(VALID_CHANGE_FREQUENCIES, changefreq.toLowerCase());
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
exports.getEntryConfig = getEntryConfig;
|
|
205
|
+
exports.isChangefreqValid = isChangefreqValid;
|
|
206
|
+
exports.prepareSitemap = prepareSitemap;
|
|
207
|
+
exports.processEntry = processEntry;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gulp-sitemap",
|
|
3
|
+
"version": "8.0.0",
|
|
4
|
+
"description": "Generate a search engine friendly sitemap.xml using a Gulp stream",
|
|
5
|
+
"repository": "pgilad/gulp-sitemap",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Gilad Peleg <gilad@giladpeleg.com> (https://www.giladpeleg.com)",
|
|
8
|
+
"main": "index.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js",
|
|
11
|
+
"lib"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=10"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"test": "mocha -R spec test/*.spec.js"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"gulpplugin",
|
|
21
|
+
"gulp",
|
|
22
|
+
"js",
|
|
23
|
+
"javascript",
|
|
24
|
+
"SEO",
|
|
25
|
+
"sitemap",
|
|
26
|
+
"sitemap.xml",
|
|
27
|
+
"Google",
|
|
28
|
+
"search-engine",
|
|
29
|
+
"xml"
|
|
30
|
+
],
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"chalk": "^2.4.2",
|
|
33
|
+
"fancy-log": "^1.3.3",
|
|
34
|
+
"lodash": "^4.17.15",
|
|
35
|
+
"multimatch": "^4.0.0",
|
|
36
|
+
"plugin-error": "^1.0.1",
|
|
37
|
+
"slash": "^3.0.0",
|
|
38
|
+
"through2": "^3.0.1",
|
|
39
|
+
"vinyl": "^2.2.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"gulp": "^4.0.2",
|
|
43
|
+
"gulp-rename": "^1.4.0",
|
|
44
|
+
"mocha": "^6.2.2",
|
|
45
|
+
"should": "^13.2.3",
|
|
46
|
+
"strip-ansi": "^5.2.0"
|
|
47
|
+
}
|
|
48
|
+
}
|