-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
75 lines (59 loc) · 2.01 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
'use strict';
const path = require('path');
const critical = require('critical');
const urlValidator = require('valid-url');
const request = require('sync-request');
module.exports = class CriticalWebpackPlugin {
constructor(criticalOptions, options) {
options = options || {};
if (CriticalWebpackPlugin.hasValidOptions(criticalOptions)) {
this.criticalOptions = criticalOptions;
// Optional parameters
this.silent = options.silent || true;
this.verbose = !this.silent;
} else {
// Throw exception
throw new Error('Parameters are invalid');
}
}
static hasValidOptions(options) {
return typeof options === 'object';
}
static hasToFetchContent(source) {
return urlValidator.isUri(source);
}
static hasToWrapStyle(buffer) {
const content = buffer.toString('utf8');
const containsHTML = content.match(/<([a-z][a-z0-9]*)\b[^>]*>/gi) !== null;
const containsStyle = content.match(/(?:\S+\s*{[^}]*})+/gi) !== null;
return !containsHTML && containsStyle;
}
hydrateWithExternalContent() {
const externalContentURL = this.criticalOptions.src;
const externalContent = request('GET', externalContentURL);
delete this.criticalOptions.src;
this.criticalOptions.html = externalContent.getBody();
}
apply(compiler) {
const that = this;
compiler.plugin('emit', (compilation, callback) => {
const dest = that.criticalOptions.dest;
const assetName = path.basename(dest);
delete that.criticalOptions.dest;
if (CriticalWebpackPlugin.hasToFetchContent(that.criticalOptions.src)) {
that.hydrateWithExternalContent();
}
critical.generate(that.criticalOptions).then((output) => {
let content = output;
if (CriticalWebpackPlugin.hasToWrapStyle(content)) {
content = `<style>${output}</style>`;
}
compilation.assets[assetName] = {
source: () => content,
size: () => content.length,
};
callback();
});
});
}
};