-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
149 lines (138 loc) · 4.77 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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
'use strict';
const HtmlWebpackPlugin = require('html-webpack-plugin');
const isFunction = fun => typeof fun === 'function';
function HtmlWebpackInjectStylePlugin (options) {
var userOptions = options || {};
this.isRtl = userOptions.isRtl;
this.modifyTag = userOptions.modifyTag;
this.PluginName = 'HtmlWebpackInjectStylePlugin';
}
HtmlWebpackInjectStylePlugin.prototype.apply = function (compiler) {
if ('hooks' in compiler) {
// setup hooks for webpack 4
compiler.hooks.compilation.tap(this.PluginName, this.applyCompilation.bind(this));
} else {
// legacy approach
compiler.plugin('compilation', this.applyCompilation.bind(this));
}
};
HtmlWebpackInjectStylePlugin.prototype.applyCompilation = function applyCompilation (compilation) {
var self = this;
// process
if (HtmlWebpackPlugin.getHooks) {
// HtmlWebpackPlugin version 4.0.0-beta.5
HtmlWebpackPlugin.getHooks(compilation).alterAssetTagGroups.tapAsync(this.PluginName, self.processPluginGroup.bind(self));
} else if ('hooks' in compilation) {
// HtmlWebpackPlugin version ^3.2.0
if (!compilation.hooks.htmlWebpackPluginAlterAssetTags) {
throw new Error('The expected HtmlWebpackPlugin hook was not found! Ensure HtmlWebpackPlugin is installed and' +
' was initialized before this plugin.');
}
compilation.hooks.htmlWebpackPluginAlterAssetTags.tapAsync(this.PluginName, self.processPluginData.bind(self));
} else {
// HtmlWebpackPlugin version 3.2.0
compilation.plugin('html-webpack-plugin-alter-asset-tags', self.processPluginData.bind(self));
}
};
HtmlWebpackInjectStylePlugin.prototype.processPluginGroup = function (htmlPluginData, callback) {
this.validateOptions();
var { head, styleAssets } = this.filterStyleAssets(htmlPluginData, 'headTags');
var scriptNode = this.generateScriptNode(styleAssets, this.isRtl, this.modifyTag);
var result = {
...htmlPluginData,
headTags: [scriptNode, ...head]
};
if (callback) {
callback(null, result);
} else {
return Promise.resolve(result);
}
};
HtmlWebpackInjectStylePlugin.prototype.processPluginData = function (htmlPluginData, callback) {
this.validateOptions();
var { head, styleAssets } = this.filterStyleAssets(htmlPluginData);
var scriptNode = this.generateScriptNode(styleAssets, this.isRtl, this.modifyTag);
var result = {
...htmlPluginData,
head: [scriptNode, ...head]
};
if (callback) {
callback(null, result);
} else {
return Promise.resolve(result);
}
};
HtmlWebpackInjectStylePlugin.prototype.validateOptions = function () {
// validate the Options
// throw a error if the `isRtl` is invalid
if (!this.isRtl) {
throw new Error('The isRtl option is required.');
}
if (
this.isRtl.constructor !== RegExp &&
!isFunction(this.isRtl)
) {
throw new Error('The isRtl must be a Regexp or Function.');
}
// throw a error if the `modifyTag` is invalid
if (
this.modifyTag &&
!isFunction(this.modifyTag)
) {
throw new Error('The modifyTag must be a Function.');
}
};
HtmlWebpackInjectStylePlugin.prototype.filterStyleAssets = function (pluginData, headKey = 'head') {
var head = [];
var styleAssets = [];
pluginData[headKey].forEach(tag => {
var tagName = tag.tagName;
var href = tag.attributes.href;
if (tagName === 'link' && /\.css/.test(href)) {
if (/(?<!\.rtl).css$/.test(href)) {
styleAssets.push(tag);
}
} else {
head.push(tag);
}
});
return {
head,
styleAssets
};
};
HtmlWebpackInjectStylePlugin.prototype.generateScriptNode = function (styleAssets, isRtl, modifyTag) {
var styleAssetsHref = JSON.stringify(styleAssets.map(tag => tag.attributes.href.match(/(.*)\.css$/)[1]));
var genRtlFun = isFunction(isRtl)
? `new Function("href","return (${isRtl.toString().split('\n').join('\\n')})(window, href)")`
: `new Function("return ${isRtl}.test(document.cookie)")`;
var modifyTagFun = isFunction(modifyTag)
? `new Function("link","return (${modifyTag.toString().split('\n').join('\\n')})(link)")`
: undefined;
return {
tagName: 'script',
closeTag: true,
attributes: {
type: 'text/javascript'
},
innerHTML: `
(function (){
var isRTL = ${genRtlFun};
var modifyTag = ${modifyTagFun};
var head = document.querySelector('head');
${styleAssetsHref}.forEach(function (href) {
var fullhref = isRTL(href) ? href + '.rtl.css' : href + '.css';
var linkTag = document.createElement("link");
linkTag.rel = "stylesheet";
linkTag.type = "text/css";
linkTag.href = fullhref;
if (modifyTag) {
linkTag = modifyTag(linkTag);
}
head.appendChild(linkTag);
})
})();
`
};
};
module.exports = HtmlWebpackInjectStylePlugin;