Skip to content

Commit ee4487d

Browse files
committed
feat: add option to allow processing the link href before injecting the link
1 parent 45fd762 commit ee4487d

File tree

13 files changed

+329
-3
lines changed

13 files changed

+329
-3
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@prepair/extract-css-chunks-webpack-plugin",
3-
"version": "0.0.0-development",
3+
"version": "4.7.1",
44
"description": "Extract CSS from chunks into stylesheets + HMR. Supports Webpack 4 + SSR",
55
"license": "MIT",
66
"author": "James Gillmore <james@faceyspacey.com>",

src/index.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ class ExtractCssChunksPlugin {
126126
filename: DEFAULT_FILENAME,
127127
moduleFilename: () => this.options.filename || DEFAULT_FILENAME,
128128
ignoreOrder: false,
129+
// note: that `processLinkHref` function will be stringified so the passed
130+
// in function should not rely on stuff found in outer scopes, use only
131+
// the parameter or globally available stuff like `window.x`
132+
// note: here we are using a plain ES5 function as a default, cause we don't
133+
// know what env this code will be run
134+
/* eslint-disable func-names, object-shorthand, prefer-template */
135+
processLinkHref: function(x) {
136+
return x;
137+
},
138+
/* eslint-enable func-names, object-shorthand, prefer-template */
129139
},
130140
options
131141
);
@@ -374,8 +384,9 @@ class ExtractCssChunksPlugin {
374384
Template.indent([
375385
'promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {',
376386
Template.indent([
387+
`var processLinkHref = ${this.options.processLinkHref};`,
377388
`var href = ${linkHrefPath};`,
378-
`var fullhref = ${mainTemplate.requireFn}.p + href;`,
389+
`var fullhref = processLinkHref(${mainTemplate.requireFn}.p + href);`,
379390
'var existingLinkTags = document.getElementsByTagName("link");',
380391
'for(var i = 0; i < existingLinkTags.length; i++) {',
381392
Template.indent([

src/options.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@
1010
"instanceof": "Function"
1111
}
1212
]
13+
},
14+
"processLinkHref": {
15+
"instanceof": "Function"
1316
}
1417
},
1518
"errorMessages": {
16-
"publicPath": "should be {String} or {Function} (https://github.com/webpack-contrib/mini-css-extract-plugin#publicpath)"
19+
"publicPath": "should be {String} or {Function} (https://github.com/webpack-contrib/mini-css-extract-plugin#publicpath)",
20+
"processLinkHref": "should be {Function}"
1721
},
1822
"type": "object"
1923
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.async { background: blue; }
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
import './in-async.css';
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.in-async { background: green; }
2+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.async { background: blue; }
2+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
body { background: red; }
2+
Lines changed: 273 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,273 @@
1+
/******/ (function(modules) { // webpackBootstrap
2+
/******/ // install a JSONP callback for chunk loading
3+
/******/ function webpackJsonpCallback(data) {
4+
/******/ var chunkIds = data[0];
5+
/******/ var moreModules = data[1];
6+
/******/
7+
/******/
8+
/******/ // add "moreModules" to the modules object,
9+
/******/ // then flag all "chunkIds" as loaded and fire callback
10+
/******/ var moduleId, chunkId, i = 0, resolves = [];
11+
/******/ for(;i < chunkIds.length; i++) {
12+
/******/ chunkId = chunkIds[i];
13+
/******/ if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
14+
/******/ resolves.push(installedChunks[chunkId][0]);
15+
/******/ }
16+
/******/ installedChunks[chunkId] = 0;
17+
/******/ }
18+
/******/ for(moduleId in moreModules) {
19+
/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
20+
/******/ modules[moduleId] = moreModules[moduleId];
21+
/******/ }
22+
/******/ }
23+
/******/ if(parentJsonpFunction) parentJsonpFunction(data);
24+
/******/
25+
/******/ while(resolves.length) {
26+
/******/ resolves.shift()();
27+
/******/ }
28+
/******/
29+
/******/ };
30+
/******/
31+
/******/
32+
/******/ // The module cache
33+
/******/ var installedModules = {};
34+
/******/
35+
/******/ // object to store loaded CSS chunks
36+
/******/ var installedCssChunks = {
37+
/******/ 0: 0
38+
/******/ }
39+
/******/
40+
/******/ // object to store loaded and loading chunks
41+
/******/ // undefined = chunk not loaded, null = chunk preloaded/prefetched
42+
/******/ // Promise = chunk loading, 0 = chunk loaded
43+
/******/ var installedChunks = {
44+
/******/ 0: 0
45+
/******/ };
46+
/******/
47+
/******/
48+
/******/
49+
/******/ // script path function
50+
/******/ function jsonpScriptSrc(chunkId) {
51+
/******/ return __webpack_require__.p + "" + ({}[chunkId]||chunkId) + ".js"
52+
/******/ }
53+
/******/
54+
/******/ // The require function
55+
/******/ function __webpack_require__(moduleId) {
56+
/******/
57+
/******/ // Check if module is in cache
58+
/******/ if(installedModules[moduleId]) {
59+
/******/ return installedModules[moduleId].exports;
60+
/******/ }
61+
/******/ // Create a new module (and put it into the cache)
62+
/******/ var module = installedModules[moduleId] = {
63+
/******/ i: moduleId,
64+
/******/ l: false,
65+
/******/ exports: {}
66+
/******/ };
67+
/******/
68+
/******/ // Execute the module function
69+
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
70+
/******/
71+
/******/ // Flag the module as loaded
72+
/******/ module.l = true;
73+
/******/
74+
/******/ // Return the exports of the module
75+
/******/ return module.exports;
76+
/******/ }
77+
/******/
78+
/******/ // This file contains only the entry chunk.
79+
/******/ // The chunk loading function for additional chunks
80+
/******/ __webpack_require__.e = function requireEnsure(chunkId) {
81+
/******/ var promises = [];
82+
/******/
83+
/******/
84+
/******/ // extract-css-chunks-webpack-plugin CSS loading
85+
/******/ var cssChunks = {"1":1,"2":1};
86+
/******/ if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);
87+
/******/ else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {
88+
/******/ promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {
89+
/******/ var processLinkHref = function (x) {
90+
/******/ return x + '.dummy';
91+
/******/ };
92+
/******/ var href = "" + ({}[chunkId]||chunkId) + ".css";
93+
/******/ var fullhref = processLinkHref(__webpack_require__.p + href;)
94+
/******/ var existingLinkTags = document.getElementsByTagName("link");
95+
/******/ for(var i = 0; i < existingLinkTags.length; i++) {
96+
/******/ var tag = existingLinkTags[i];
97+
/******/ var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");
98+
/******/ if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return resolve();
99+
/******/ }
100+
/******/ var existingStyleTags = document.getElementsByTagName("style");
101+
/******/ for(var i = 0; i < existingStyleTags.length; i++) {
102+
/******/ var tag = existingStyleTags[i];
103+
/******/ var dataHref = tag.getAttribute("data-href");
104+
/******/ if(dataHref === href || dataHref === fullhref) return resolve();
105+
/******/ }
106+
/******/ var linkTag = document.createElement("link");
107+
/******/ linkTag.rel = "stylesheet";
108+
/******/ linkTag.type = "text/css";
109+
/******/ linkTag.onload = resolve;
110+
/******/ linkTag.onerror = function(event) {
111+
/******/ var request = event && event.target && event.target.src || fullhref;
112+
/******/ var err = new Error("Loading CSS chunk " + chunkId + " failed.\n(" + request + ")");
113+
/******/ err.code = "CSS_CHUNK_LOAD_FAILED";
114+
/******/ err.request = request;
115+
/******/ delete installedCssChunks[chunkId]
116+
/******/ linkTag.parentNode.removeChild(linkTag)
117+
/******/ reject(err);
118+
/******/ };
119+
/******/ linkTag.href = fullhref;
120+
/******/
121+
/******/ var head = document.getElementsByTagName("head")[0];
122+
/******/ head.appendChild(linkTag);
123+
/******/ }).then(function() {
124+
/******/ installedCssChunks[chunkId] = 0;
125+
/******/ }));
126+
/******/ }
127+
/******/
128+
/******/ // JSONP chunk loading for javascript
129+
/******/
130+
/******/ var installedChunkData = installedChunks[chunkId];
131+
/******/ if(installedChunkData !== 0) { // 0 means "already installed".
132+
/******/
133+
/******/ // a Promise means "currently loading".
134+
/******/ if(installedChunkData) {
135+
/******/ promises.push(installedChunkData[2]);
136+
/******/ } else {
137+
/******/ // setup Promise in chunk cache
138+
/******/ var promise = new Promise(function(resolve, reject) {
139+
/******/ installedChunkData = installedChunks[chunkId] = [resolve, reject];
140+
/******/ });
141+
/******/ promises.push(installedChunkData[2] = promise);
142+
/******/
143+
/******/ // start chunk loading
144+
/******/ var script = document.createElement('script');
145+
/******/ var onScriptComplete;
146+
/******/
147+
/******/ script.charset = 'utf-8';
148+
/******/ script.timeout = 120;
149+
/******/ if (__webpack_require__.nc) {
150+
/******/ script.setAttribute("nonce", __webpack_require__.nc);
151+
/******/ }
152+
/******/ script.src = jsonpScriptSrc(chunkId);
153+
/******/
154+
/******/ // create error before stack unwound to get useful stacktrace later
155+
/******/ var error = new Error();
156+
/******/ onScriptComplete = function (event) {
157+
/******/ // avoid mem leaks in IE.
158+
/******/ script.onerror = script.onload = null;
159+
/******/ clearTimeout(timeout);
160+
/******/ var chunk = installedChunks[chunkId];
161+
/******/ if(chunk !== 0) {
162+
/******/ if(chunk) {
163+
/******/ var errorType = event && (event.type === 'load' ? 'missing' : event.type);
164+
/******/ var realSrc = event && event.target && event.target.src;
165+
/******/ error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ': ' + realSrc + ')';
166+
/******/ error.name = 'ChunkLoadError';
167+
/******/ error.type = errorType;
168+
/******/ error.request = realSrc;
169+
/******/ chunk[1](error);
170+
/******/ }
171+
/******/ installedChunks[chunkId] = undefined;
172+
/******/ }
173+
/******/ };
174+
/******/ var timeout = setTimeout(function(){
175+
/******/ onScriptComplete({ type: 'timeout', target: script });
176+
/******/ }, 120000);
177+
/******/ script.onerror = script.onload = onScriptComplete;
178+
/******/ document.head.appendChild(script);
179+
/******/ }
180+
/******/ }
181+
/******/ return Promise.all(promises);
182+
/******/ };
183+
/******/
184+
/******/ // expose the modules object (__webpack_modules__)
185+
/******/ __webpack_require__.m = modules;
186+
/******/
187+
/******/ // expose the module cache
188+
/******/ __webpack_require__.c = installedModules;
189+
/******/
190+
/******/ // define getter function for harmony exports
191+
/******/ __webpack_require__.d = function(exports, name, getter) {
192+
/******/ if(!__webpack_require__.o(exports, name)) {
193+
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
194+
/******/ }
195+
/******/ };
196+
/******/
197+
/******/ // define __esModule on exports
198+
/******/ __webpack_require__.r = function(exports) {
199+
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
200+
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
201+
/******/ }
202+
/******/ Object.defineProperty(exports, '__esModule', { value: true });
203+
/******/ };
204+
/******/
205+
/******/ // create a fake namespace object
206+
/******/ // mode & 1: value is a module id, require it
207+
/******/ // mode & 2: merge all properties of value into the ns
208+
/******/ // mode & 4: return value when already ns object
209+
/******/ // mode & 8|1: behave like require
210+
/******/ __webpack_require__.t = function(value, mode) {
211+
/******/ if(mode & 1) value = __webpack_require__(value);
212+
/******/ if(mode & 8) return value;
213+
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
214+
/******/ var ns = Object.create(null);
215+
/******/ __webpack_require__.r(ns);
216+
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
217+
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
218+
/******/ return ns;
219+
/******/ };
220+
/******/
221+
/******/ // getDefaultExport function for compatibility with non-harmony modules
222+
/******/ __webpack_require__.n = function(module) {
223+
/******/ var getter = module && module.__esModule ?
224+
/******/ function getDefault() { return module['default']; } :
225+
/******/ function getModuleExports() { return module; };
226+
/******/ __webpack_require__.d(getter, 'a', getter);
227+
/******/ return getter;
228+
/******/ };
229+
/******/
230+
/******/ // Object.prototype.hasOwnProperty.call
231+
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
232+
/******/
233+
/******/ // __webpack_public_path__
234+
/******/ __webpack_require__.p = "";
235+
/******/
236+
/******/ // on error function for async loading
237+
/******/ __webpack_require__.oe = function(err) { console.error(err); throw err; };
238+
/******/
239+
/******/ var jsonpArray = window["webpackJsonp"] = window["webpackJsonp"] || [];
240+
/******/ var oldJsonpFunction = jsonpArray.push.bind(jsonpArray);
241+
/******/ jsonpArray.push = webpackJsonpCallback;
242+
/******/ jsonpArray = jsonpArray.slice();
243+
/******/ for(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);
244+
/******/ var parentJsonpFunction = oldJsonpFunction;
245+
/******/
246+
/******/
247+
/******/ // Load entry module and return exports
248+
/******/ return __webpack_require__(__webpack_require__.s = 0);
249+
/******/ })
250+
/************************************************************************/
251+
/******/ ([
252+
/* 0 */
253+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
254+
255+
"use strict";
256+
__webpack_require__.r(__webpack_exports__);
257+
/* harmony import */ var _main_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
258+
/* harmony import */ var _main_css__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_main_css__WEBPACK_IMPORTED_MODULE_0__);
259+
260+
261+
__webpack_require__.e(/* import() */ 1).then(__webpack_require__.bind(null, 2));
262+
263+
__webpack_require__.e(/* import() */ 2).then(__webpack_require__.t.bind(null, 4, 7));
264+
265+
266+
/***/ }),
267+
/* 1 */
268+
/***/ (function(module, exports, __webpack_require__) {
269+
270+
// extracted by extract-css-chunks-webpack-plugin
271+
272+
/***/ })
273+
/******/ ]);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.in-async { background: green; }
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import './main.css';
2+
3+
import('./async');
4+
5+
import('./async.css');
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
body { background: red; }
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Self from '../../../src';
2+
3+
module.exports = {
4+
entry: './index.js',
5+
module: {
6+
rules: [
7+
{
8+
test: /\.css$/,
9+
use: [Self.loader, 'css-loader'],
10+
},
11+
],
12+
},
13+
plugins: [
14+
new Self({
15+
filename: '[name].css',
16+
/* eslint-disable func-names, object-shorthand, prefer-template */
17+
processLinkHref: function(x) {
18+
return x + '.dummy';
19+
},
20+
/* eslint-enable func-names, object-shorthand, prefer-template */
21+
}),
22+
],
23+
};

0 commit comments

Comments
 (0)