Files

Return to Package Diff Home.
Brought to you by Intrinsic.

Package Diff: mini-css-extract-plugin @ 0.4.5 .. 0.6.0

CHANGELOG.md

@@ -2,6 +2,28 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+<a name="0.6.0"></a>
+# [0.6.0](https://github.com/webpack-contrib/mini-css-extract-plugin/compare/v0.5.0...v0.6.0) (2019-04-10)
+
+
+### Features
+
+* added error code to chunk load Error ([#347](https://github.com/webpack-contrib/mini-css-extract-plugin/issues/347)) ([b653641](https://github.com/webpack-contrib/mini-css-extract-plugin/commit/b653641))
+* adding hot module reloading ([#334](https://github.com/webpack-contrib/mini-css-extract-plugin/issues/334)) ([4ed9c5a](https://github.com/webpack-contrib/mini-css-extract-plugin/commit/4ed9c5a))
+* publicPath can be a function ([#373](https://github.com/webpack-contrib/mini-css-extract-plugin/issues/373)) ([7b1425a](https://github.com/webpack-contrib/mini-css-extract-plugin/commit/7b1425a))
+
+
+
+<a name="0.5.0"></a>
+# [0.5.0](https://github.com/webpack-contrib/mini-css-extract-plugin/compare/v0.4.5...v0.5.0) (2018-12-07)
+
+
+### Features
+
+* add crossOriginLoading option support ([#313](https://github.com/webpack-contrib/mini-css-extract-plugin/issues/313)) ([ffb0d87](https://github.com/webpack-contrib/mini-css-extract-plugin/commit/ffb0d87))
+
+
+
<a name="0.4.5"></a>
## [0.4.5](https://github.com/webpack-contrib/mini-css-extract-plugin/compare/v0.4.4...v0.4.5) (2018-11-21)

dist/cjs.js

@@ -1,3 +1,3 @@
-'use strict';
+"use strict";
module.exports = require('./index').default;
\ No newline at end of file

dist/hmr/hotModuleReplacement.js

@@ -0,0 +1,187 @@
+"use strict";
+
+/* global document, window */
+
+/*
+ eslint-disable
+ func-names,
+ no-var,
+ vars-on-top,
+ prefer-arrow-func,
+ prefer-rest-params,
+ prefer-arrow-callback,
+ prefer-template,
+ prefer-destructuring,
+ no-param-reassign,
+ no-console
+*/
+var normalizeUrl = require('normalize-url');
+
+var srcByModuleId = Object.create(null);
+var noDocument = typeof document === 'undefined';
+var forEach = Array.prototype.forEach;
+
+function debounce(fn, time) {
+ var timeout = 0; // eslint-disable-next-line func-names
+
+ return function () {
+ var self = this;
+ var args = arguments; // eslint-disable-next-line prefer-rest-params
+
+ var functionCall = function functionCall() {
+ return fn.apply(self, args);
+ };
+
+ clearTimeout(timeout);
+ timeout = setTimeout(functionCall, time);
+ };
+}
+
+function noop() {}
+
+function getCurrentScriptUrl(moduleId) {
+ var src = srcByModuleId[moduleId];
+
+ if (!src) {
+ if (document.currentScript) {
+ src = document.currentScript.src;
+ } else {
+ var scripts = document.getElementsByTagName('script');
+ var lastScriptTag = scripts[scripts.length - 1];
+
+ if (lastScriptTag) {
+ src = lastScriptTag.src;
+ }
+ }
+
+ srcByModuleId[moduleId] = src;
+ }
+
+ return function (fileMap) {
+ if (!src) {
+ return null;
+ }
+
+ var splitResult = src.split(/([^\\/]+)\.js$/);
+ var filename = splitResult && splitResult[1];
+
+ if (!filename) {
+ return [src.replace('.js', '.css')];
+ }
+
+ if (!fileMap) {
+ return [src.replace('.js', '.css')];
+ }
+
+ return fileMap.split(',').map(function (mapRule) {
+ var reg = new RegExp(filename + '\\.js$', 'g');
+ return normalizeUrl(src.replace(reg, mapRule.replace(/{fileName}/g, filename) + '.css'), {
+ stripWWW: false
+ });
+ });
+ };
+}
+
+function updateCss(el, url) {
+ if (!url) {
+ url = el.href.split('?')[0];
+ }
+
+ if (el.isLoaded === false) {
+ // We seem to be about to replace a css link that hasn't loaded yet.
+ // We're probably changing the same file more than once.
+ return;
+ }
+
+ if (!url || !(url.indexOf('.css') > -1)) {
+ return;
+ }
+
+ el.visited = true;
+ var newEl = el.cloneNode(); // eslint-disable-line vars-on-top
+
+ newEl.isLoaded = false;
+ newEl.addEventListener('load', function () {
+ newEl.isLoaded = true;
+ el.parentNode.removeChild(el);
+ });
+ newEl.addEventListener('error', function () {
+ newEl.isLoaded = true;
+ el.parentNode.removeChild(el);
+ });
+ newEl.href = url + '?' + Date.now();
+ el.parentNode.appendChild(newEl);
+}
+
+function getReloadUrl(href, src) {
+ var ret;
+ href = normalizeUrl(href, {
+ stripWWW: false
+ }); // eslint-disable-next-line array-callback-return
+
+ src.some(function (url) {
+ if (href.indexOf(src) > -1) {
+ ret = url;
+ }
+ });
+ return ret;
+}
+
+function reloadStyle(src) {
+ var elements = document.querySelectorAll('link');
+ var loaded = false;
+ forEach.call(elements, function (el) {
+ var url = getReloadUrl(el.href, src);
+
+ if (el.visited === true) {
+ return;
+ }
+
+ if (url) {
+ updateCss(el, url);
+ loaded = true;
+ }
+ });
+ return loaded;
+}
+
+function reloadAll() {
+ var elements = document.querySelectorAll('link');
+ forEach.call(elements, function (el) {
+ if (el.visited === true) {
+ return;
+ }
+
+ updateCss(el);
+ });
+}
+
+module.exports = function (moduleId, options) {
+ if (noDocument) {
+ console.log('no window.document found, will not HMR CSS');
+ return noop;
+ } // eslint-disable-next-line vars-on-top
+
+
+ var getScriptSrc = getCurrentScriptUrl(moduleId);
+
+ function update() {
+ var src = getScriptSrc(options.filename);
+ var reloaded = reloadStyle(src);
+
+ if (options.locals) {
+ console.log('[HMR] Detected local css modules. Reload all css');
+ reloadAll();
+ return;
+ }
+
+ if (reloaded && !options.reloadAll) {
+ console.log('[HMR] css reload %s', src.join(' '));
+ } else {
+ console.log('[HMR] Reload all css');
+ reloadAll();
+ }
+ }
+
+ return debounce(update, 50);
+};
\ No newline at end of file

dist/index.js

@@ -1,35 +1,41 @@
-'use strict';
+"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
+exports.default = void 0;
-var _webpack = require('webpack');
+var _webpack = _interopRequireDefault(require("webpack"));
-var _webpack2 = _interopRequireDefault(_webpack);
-
-var _webpackSources = require('webpack-sources');
-
-var _webpackSources2 = _interopRequireDefault(_webpackSources);
+var _webpackSources = _interopRequireDefault(require("webpack-sources"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-const { ConcatSource, SourceMapSource, OriginalSource } = _webpackSources2.default;
+/* eslint-disable class-methods-use-this */
+const {
+ ConcatSource,
+ SourceMapSource,
+ OriginalSource
+} = _webpackSources.default;
const {
Template,
- util: { createHash }
-} = _webpack2.default;
-
+ util: {
+ createHash
+ }
+} = _webpack.default;
const MODULE_TYPE = 'css/mini-extract';
-
const pluginName = 'mini-css-extract-plugin';
-
const REGEXP_CHUNKHASH = /\[chunkhash(?::(\d+))?\]/i;
const REGEXP_CONTENTHASH = /\[contenthash(?::(\d+))?\]/i;
const REGEXP_NAME = /\[name\]/i;
-class CssDependency extends _webpack2.default.Dependency {
- constructor({ identifier, content, media, sourceMap }, context, identifierIndex) {
+class CssDependency extends _webpack.default.Dependency {
+ constructor({
+ identifier,
+ content,
+ media,
+ sourceMap
+ }, context, identifierIndex) {
super();
this.identifier = identifier;
this.identifierIndex = identifierIndex;
@@ -46,9 +53,10 @@
class CssDependencyTemplate {
apply() {}
+
}
-class CssModule extends _webpack2.default.Module {
+class CssModule extends _webpack.default.Module {
constructor(dependency) {
super(MODULE_TYPE, dependency.context);
this.id = '';
@@ -57,9 +65,8 @@
this.content = dependency.content;
this.media = dependency.media;
this.sourceMap = dependency.sourceMap;
- }
+ } // no source() so webpack doesn't do add stuff to the bundle
- // no source() so webpack doesn't do add stuff to the bundle
size() {
return this.content.length;
@@ -75,8 +82,13 @@
nameForCondition() {
const resource = this._identifier.split('!').pop();
+
const idx = resource.indexOf('?');
- if (idx >= 0) return resource.substring(0, idx);
+
+ if (idx >= 0) {
+ return resource.substring(0, idx);
+ }
+
return resource;
}
@@ -117,12 +131,15 @@
this.options = Object.assign({
filename: '[name].css'
}, options);
+
if (!this.options.chunkFilename) {
- const { filename } = this.options;
+ const {
+ filename
+ } = this.options;
const hasName = filename.includes('[name]');
const hasId = filename.includes('[id]');
- const hasChunkHash = filename.includes('[chunkhash]');
- // Anything changing depending on chunk is fine
+ const hasChunkHash = filename.includes('[chunkhash]'); // Anything changing depending on chunk is fine
+
if (hasChunkHash || hasName || hasId) {
this.options.chunkFilename = filename;
} else {
@@ -152,8 +171,11 @@
});
compilation.dependencyFactories.set(CssDependency, new CssModuleFactory());
compilation.dependencyTemplates.set(CssDependency, new CssDependencyTemplate());
- compilation.mainTemplate.hooks.renderManifest.tap(pluginName, (result, { chunk }) => {
+ compilation.mainTemplate.hooks.renderManifest.tap(pluginName, (result, {
+ chunk
+ }) => {
const renderedModules = Array.from(chunk.modulesIterable).filter(module => module.type === MODULE_TYPE);
+
if (renderedModules.length > 0) {
result.push({
render: () => this.renderContentAsset(compilation, chunk, renderedModules, compilation.runtimeTemplate.requestShortener),
@@ -167,8 +189,11 @@
});
}
});
- compilation.chunkTemplate.hooks.renderManifest.tap(pluginName, (result, { chunk }) => {
+ compilation.chunkTemplate.hooks.renderManifest.tap(pluginName, (result, {
+ chunk
+ }) => {
const renderedModules = Array.from(chunk.modulesIterable).filter(module => module.type === MODULE_TYPE);
+
if (renderedModules.length > 0) {
result.push({
render: () => this.renderContentAsset(compilation, chunk, renderedModules, compilation.runtimeTemplate.requestShortener),
@@ -183,7 +208,10 @@
}
});
compilation.mainTemplate.hooks.hashForChunk.tap(pluginName, (hash, chunk) => {
- const { chunkFilename } = this.options;
+ const {
+ chunkFilename
+ } = this.options;
+
if (REGEXP_CHUNKHASH.test(chunkFilename)) {
hash.update(JSON.stringify(chunk.getChunkMaps(true).hash));
}
@@ -190,25 +219,39 @@
if (REGEXP_CONTENTHASH.test(chunkFilename)) {
hash.update(JSON.stringify(chunk.getChunkMaps(true).contentHash[MODULE_TYPE] || {}));
}
+
if (REGEXP_NAME.test(chunkFilename)) {
hash.update(JSON.stringify(chunk.getChunkMaps(true).name));
}
});
compilation.hooks.contentHash.tap(pluginName, chunk => {
- const { outputOptions } = compilation;
- const { hashFunction, hashDigest, hashDigestLength } = outputOptions;
+ const {
+ outputOptions
+ } = compilation;
+ const {
+ hashFunction,
+ hashDigest,
+ hashDigestLength
+ } = outputOptions;
const hash = createHash(hashFunction);
+
for (const m of chunk.modulesIterable) {
if (m.type === MODULE_TYPE) {
m.updateHash(hash);
}
}
- const { contentHash } = chunk;
+
+ const {
+ contentHash
+ } = chunk;
contentHash[MODULE_TYPE] = hash.digest(hashDigest).substring(0, hashDigestLength);
});
- const { mainTemplate } = compilation;
+ const {
+ mainTemplate
+ } = compilation;
mainTemplate.hooks.localVars.tap(pluginName, (source, chunk) => {
const chunkMap = this.getCssChunkObject(chunk);
+
if (Object.keys(chunkMap).length > 0) {
return Template.asString([source, '', '// object to store loaded CSS chunks', 'var installedCssChunks = {', Template.indent(chunk.ids.map(id => `${JSON.stringify(id)}: 0`).join(',\n')), '}']);
}
@@ -216,8 +260,12 @@
});
mainTemplate.hooks.requireEnsure.tap(pluginName, (source, chunk, hash) => {
const chunkMap = this.getCssChunkObject(chunk);
+
if (Object.keys(chunkMap).length > 0) {
const chunkMaps = chunk.getChunkMaps();
+ const {
+ crossOriginLoading
+ } = mainTemplate.outputOptions;
const linkHrefPath = mainTemplate.getAssetPath(JSON.stringify(this.options.chunkFilename), {
hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`,
hashWithLength: length => `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`,
@@ -252,8 +306,9 @@
},
contentHashType: MODULE_TYPE
});
- return Template.asString([source, '', `// ${pluginName} CSS loading`, `var cssChunks = ${JSON.stringify(chunkMap)};`, 'if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);', 'else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {', Template.indent(['promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {', Template.indent([`var href = ${linkHrefPath};`, `var fullhref = ${mainTemplate.requireFn}.p + href;`, 'var existingLinkTags = document.getElementsByTagName("link");', 'for(var i = 0; i < existingLinkTags.length; i++) {', Template.indent(['var tag = existingLinkTags[i];', 'var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");', 'if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return resolve();']), '}', 'var existingStyleTags = document.getElementsByTagName("style");', 'for(var i = 0; i < existingStyleTags.length; i++) {', Template.indent(['var tag = existingStyleTags[i];', 'var dataHref = tag.getAttribute("data-href");', 'if(dataHref === href || dataHref === fullhref) return resolve();']), '}', 'var linkTag = document.createElement("link");', 'linkTag.rel = "stylesheet";', 'linkTag.type = "text/css";', 'linkTag.onload = resolve;', 'linkTag.onerror = function(event) {', Template.indent(['var request = event && event.target && event.target.src || fullhref;', 'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + request + ")");', 'err.request = request;', 'delete installedCssChunks[chunkId]', 'linkTag.parentNode.removeChild(linkTag)', 'reject(err);']), '};', 'linkTag.href = fullhref;', 'var head = document.getElementsByTagName("head")[0];', 'head.appendChild(linkTag);']), '}).then(function() {', Template.indent(['installedCssChunks[chunkId] = 0;']), '}));']), '}']);
+ return Template.asString([source, '', `// ${pluginName} CSS loading`, `var cssChunks = ${JSON.stringify(chunkMap)};`, 'if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);', 'else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {', Template.indent(['promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {', Template.indent([`var href = ${linkHrefPath};`, `var fullhref = ${mainTemplate.requireFn}.p + href;`, 'var existingLinkTags = document.getElementsByTagName("link");', 'for(var i = 0; i < existingLinkTags.length; i++) {', Template.indent(['var tag = existingLinkTags[i];', 'var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");', 'if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return resolve();']), '}', 'var existingStyleTags = document.getElementsByTagName("style");', 'for(var i = 0; i < existingStyleTags.length; i++) {', Template.indent(['var tag = existingStyleTags[i];', 'var dataHref = tag.getAttribute("data-href");', 'if(dataHref === href || dataHref === fullhref) return resolve();']), '}', 'var linkTag = document.createElement("link");', 'linkTag.rel = "stylesheet";', 'linkTag.type = "text/css";', 'linkTag.onload = resolve;', 'linkTag.onerror = function(event) {', Template.indent(['var request = event && event.target && event.target.src || fullhref;', 'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + request + ")");', 'err.code = "CSS_CHUNK_LOAD_FAILED";', 'err.request = request;', 'delete installedCssChunks[chunkId]', 'linkTag.parentNode.removeChild(linkTag)', 'reject(err);']), '};', 'linkTag.href = fullhref;', crossOriginLoading ? Template.asString([`if (linkTag.href.indexOf(window.location.origin + '/') !== 0) {`, Template.indent(`linkTag.crossOrigin = ${JSON.stringify(crossOriginLoading)};`), '}']) : '', 'var head = document.getElementsByTagName("head")[0];', 'head.appendChild(linkTag);']), '}).then(function() {', Template.indent(['installedCssChunks[chunkId] = 0;']), '}));']), '}']);
}
+
return source;
});
});
@@ -274,33 +331,34 @@
renderContentAsset(compilation, chunk, modules, requestShortener) {
let usedModules;
-
const [chunkGroup] = chunk.groupsIterable;
+
if (typeof chunkGroup.getModuleIndex2 === 'function') {
// Store dependencies for modules
- const moduleDependencies = new Map(modules.map(m => [m, new Set()]));
-
- // Get ordered list of modules per chunk group
+ const moduleDependencies = new Map(modules.map(m => [m, new Set()])); // Get ordered list of modules per chunk group
// This loop also gathers dependencies from the ordered lists
// Lists are in reverse order to allow to use Array.pop()
+
const modulesByChunkGroup = Array.from(chunk.groupsIterable, cg => {
const sortedModules = modules.map(m => {
return {
module: m,
index: cg.getModuleIndex2(m)
};
- }).filter(item => item.index !== undefined).sort((a, b) => b.index - a.index).map(item => item.module);
+ }) // eslint-disable-next-line no-undefined
+ .filter(item => item.index !== undefined).sort((a, b) => b.index - a.index).map(item => item.module);
+
for (let i = 0; i < sortedModules.length; i++) {
const set = moduleDependencies.get(sortedModules[i]);
+
for (let j = i + 1; j < sortedModules.length; j++) {
set.add(sortedModules[j]);
}
}
return sortedModules;
- });
+ }); // set with already included modules in correct order
- // set with already included modules in correct order
usedModules = new Set();
const unusedModulesFilter = m => !usedModules.has(m);
@@ -308,20 +366,21 @@
while (usedModules.size < modules.length) {
let success = false;
let bestMatch;
- let bestMatchDeps;
- // get first module where dependencies are fulfilled
+ let bestMatchDeps; // get first module where dependencies are fulfilled
+
for (const list of modulesByChunkGroup) {
// skip and remove already added modules
- while (list.length > 0 && usedModules.has(list[list.length - 1])) list.pop();
+ while (list.length > 0 && usedModules.has(list[list.length - 1])) {
+ list.pop();
+ } // skip empty lists
+
- // skip empty lists
if (list.length !== 0) {
const module = list[list.length - 1];
- const deps = moduleDependencies.get(module);
- // determine dependencies that are not yet included
- const failedDeps = Array.from(deps).filter(unusedModulesFilter);
+ const deps = moduleDependencies.get(module); // determine dependencies that are not yet included
+
+ const failedDeps = Array.from(deps).filter(unusedModulesFilter); // store best match for fallback behavior
- // store best match for fallback behavior
if (!bestMatchDeps || bestMatchDeps.length > failedDeps.length) {
bestMatch = list;
bestMatchDeps = failedDeps;
@@ -340,7 +400,7 @@
// use list with fewest failed deps
// and emit a warning
const fallbackModule = bestMatch.pop();
- compilation.warnings.push(new Error(`chunk ${chunk.name || chunk.id} [mini-css-extract-plugin]\n` + 'Conflicting order between:\n' + ` * ${fallbackModule.readableIdentifier(requestShortener)}\n` + `${bestMatchDeps.map(m => ` * ${m.readableIdentifier(requestShortener)}`).join('\n')}`));
+ compilation.warnings.push(new Error(`chunk ${chunk.name || chunk.id} [${pluginName}]\n` + 'Conflicting order between:\n' + ` * ${fallbackModule.readableIdentifier(requestShortener)}\n` + `${bestMatchDeps.map(m => ` * ${m.readableIdentifier(requestShortener)}`).join('\n')}`));
usedModules.add(fallbackModule);
}
}
@@ -352,13 +412,18 @@
modules.sort((a, b) => a.index2 - b.index2);
usedModules = modules;
}
+
const source = new ConcatSource();
const externalsSource = new ConcatSource();
+
for (const m of usedModules) {
if (/^@import url/.test(m.content)) {
// HACK for IE
// http://stackoverflow.com/a/14676665/1458162
- let { content } = m;
+ let {
+ content
+ } = m;
+
if (m.media) {
// insert media into the @import
// this is rar
@@ -382,10 +451,12 @@
}
}
}
+
return new ConcatSource(externalsSource, source);
}
+
}
MiniCssExtractPlugin.loader = require.resolve('./loader');
-
-exports.default = MiniCssExtractPlugin;
\ No newline at end of file
+var _default = MiniCssExtractPlugin;
+exports.default = _default;
\ No newline at end of file

dist/loader.js

@@ -1,50 +1,63 @@
-'use strict';
+"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.pitch = pitch;
+exports.default = _default;
-exports.default = function () {};
+var _module = _interopRequireDefault(require("module"));
-var _module = require('module');
+var _path = _interopRequireDefault(require("path"));
-var _module2 = _interopRequireDefault(_module);
+var _loaderUtils = _interopRequireDefault(require("loader-utils"));
-var _loaderUtils = require('loader-utils');
+var _NodeTemplatePlugin = _interopRequireDefault(require("webpack/lib/node/NodeTemplatePlugin"));
-var _loaderUtils2 = _interopRequireDefault(_loaderUtils);
+var _NodeTargetPlugin = _interopRequireDefault(require("webpack/lib/node/NodeTargetPlugin"));
-var _NodeTemplatePlugin = require('webpack/lib/node/NodeTemplatePlugin');
+var _LibraryTemplatePlugin = _interopRequireDefault(require("webpack/lib/LibraryTemplatePlugin"));
-var _NodeTemplatePlugin2 = _interopRequireDefault(_NodeTemplatePlugin);
+var _SingleEntryPlugin = _interopRequireDefault(require("webpack/lib/SingleEntryPlugin"));
-var _NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
+var _LimitChunkCountPlugin = _interopRequireDefault(require("webpack/lib/optimize/LimitChunkCountPlugin"));
-var _NodeTargetPlugin2 = _interopRequireDefault(_NodeTargetPlugin);
+var _schemaUtils = _interopRequireDefault(require("schema-utils"));
-var _LibraryTemplatePlugin = require('webpack/lib/LibraryTemplatePlugin');
+var _options = _interopRequireDefault(require("./options.json"));
-var _LibraryTemplatePlugin2 = _interopRequireDefault(_LibraryTemplatePlugin);
-
-var _SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
-
-var _SingleEntryPlugin2 = _interopRequireDefault(_SingleEntryPlugin);
-
-var _LimitChunkCountPlugin = require('webpack/lib/optimize/LimitChunkCountPlugin');
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-var _LimitChunkCountPlugin2 = _interopRequireDefault(_LimitChunkCountPlugin);
+function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
const MODULE_TYPE = 'css/mini-extract';
const pluginName = 'mini-css-extract-plugin';
+function hotLoader(content, context) {
+ const accept = context.locals ? '' : 'module.hot.accept(undefined, cssReload);';
+ return `${content}
+ if(module.hot) {
+ // ${Date.now()}
+ var cssReload = require(${_loaderUtils.default.stringifyRequest(context.context, _path.default.join(__dirname, 'hmr/hotModuleReplacement.js'))})(module.id, ${JSON.stringify(_objectSpread({}, context.options, {
+ locals: !!context.locals
+ }))});
+ module.hot.dispose(cssReload);
+ ${accept}
+ }
+ `;
+}
+
const exec = (loaderContext, code, filename) => {
- const module = new _module2.default(filename, loaderContext);
- module.paths = _module2.default._nodeModulePaths(loaderContext.context); // eslint-disable-line no-underscore-dangle
+ const module = new _module.default(filename, loaderContext);
+ module.paths = _module.default._nodeModulePaths(loaderContext.context); // eslint-disable-line no-underscore-dangle
+
module.filename = filename;
+
module._compile(code, filename); // eslint-disable-line no-underscore-dangle
+
+
return module.exports;
};
@@ -54,15 +67,18 @@
return module;
}
}
+
return null;
};
function pitch(request) {
- const query = _loaderUtils2.default.getOptions(this) || {};
+ const options = _loaderUtils.default.getOptions(this) || {};
+ (0, _schemaUtils.default)(_options.default, options, 'Mini CSS Extract Plugin Loader');
const loaders = this.loaders.slice(this.loaderIndex + 1);
this.addDependency(this.resourcePath);
const childFilename = '*'; // eslint-disable-line no-path-concat
- const publicPath = typeof query.publicPath === 'string' ? query.publicPath : this._compilation.outputOptions.publicPath;
+
+ const publicPath = typeof options.publicPath === 'string' ? options.publicPath.endsWith('/') ? options.publicPath : `${options.publicPath}/` : typeof options.publicPath === 'function' ? options.publicPath(this.resourcePath, this.rootContext) : this._compilation.outputOptions.publicPath;
const outputOptions = {
filename: childFilename,
publicPath
@@ -67,18 +83,24 @@
filename: childFilename,
publicPath
};
+
const childCompiler = this._compilation.createChildCompiler(`${pluginName} ${request}`, outputOptions);
- new _NodeTemplatePlugin2.default(outputOptions).apply(childCompiler);
- new _LibraryTemplatePlugin2.default(null, 'commonjs2').apply(childCompiler);
- new _NodeTargetPlugin2.default().apply(childCompiler);
- new _SingleEntryPlugin2.default(this.context, `!!${request}`, pluginName).apply(childCompiler);
- new _LimitChunkCountPlugin2.default({ maxChunks: 1 }).apply(childCompiler);
- // We set loaderContext[MODULE_TYPE] = false to indicate we already in
+
+ new _NodeTemplatePlugin.default(outputOptions).apply(childCompiler);
+ new _LibraryTemplatePlugin.default(null, 'commonjs2').apply(childCompiler);
+ new _NodeTargetPlugin.default().apply(childCompiler);
+ new _SingleEntryPlugin.default(this.context, `!!${request}`, pluginName).apply(childCompiler);
+ new _LimitChunkCountPlugin.default({
+ maxChunks: 1
+ }).apply(childCompiler); // We set loaderContext[MODULE_TYPE] = false to indicate we already in
// a child compiler so we don't spawn another child compilers from there.
+
childCompiler.hooks.thisCompilation.tap(`${pluginName} loader`, compilation => {
compilation.hooks.normalModuleLoader.tap(`${pluginName} loader`, (loaderContext, module) => {
+ // eslint-disable-next-line no-param-reassign
loaderContext.emitFile = this.emitFile;
loaderContext[MODULE_TYPE] = false; // eslint-disable-line no-param-reassign
+
if (module.request === request) {
// eslint-disable-next-line no-param-reassign
module.loaders = loaders.map(loader => {
@@ -91,12 +113,10 @@
}
});
});
-
let source;
childCompiler.hooks.afterCompile.tap(pluginName, compilation => {
- source = compilation.assets[childFilename] && compilation.assets[childFilename].source();
+ source = compilation.assets[childFilename] && compilation.assets[childFilename].source(); // Remove all chunk assets
- // Remove all chunk assets
compilation.chunks.forEach(chunk => {
chunk.files.forEach(file => {
delete compilation.assets[file]; // eslint-disable-line no-param-reassign
@@ -103,10 +123,11 @@
});
});
});
-
const callback = this.async();
childCompiler.runAsChild((err, entries, compilation) => {
- if (err) return callback(err);
+ if (err) {
+ return callback(err);
+ }
if (compilation.errors.length > 0) {
return callback(compilation.errors[0]);
@@ -138,15 +164,21 @@
};
});
}
+
this[MODULE_TYPE](text);
} catch (e) {
return callback(e);
}
- let resultSource = `// extracted by ${pluginName}`;
- if (locals && typeof resultSource !== 'undefined') {
- resultSource += `\nmodule.exports = ${JSON.stringify(locals)};`;
- }
+ let resultSource = `// extracted by ${pluginName}`;
+ const result = locals ? `\nmodule.exports = ${JSON.stringify(locals)};` : '';
+ resultSource += options.hmr ? hotLoader(result, {
+ context: this.context,
+ options,
+ locals
+ }) : result;
return callback(null, resultSource);
});
}
\ No newline at end of file
+
+function _default() {}
\ No newline at end of file

dist/options.json

@@ -0,0 +1,19 @@
+{
+ "additionalProperties": true,
+ "properties": {
+ "publicPath": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "instanceof": "Function"
+ }
+ ]
+ }
+ },
+ "errorMessages": {
+ "publicPath": "should be {String} or {Function} (https://github.com/webpack-contrib/mini-css-extract-plugin#publicpath)"
+ },
+ "type": "object"
+ }

package.json

@@ -1,39 +1,36 @@
{
"name": "mini-css-extract-plugin",
- "version": "0.4.5",
+ "version": "0.6.0",
"description": "extracts CSS into separate files",
"license": "MIT",
"repository": "webpack-contrib/mini-css-extract-plugin",
"author": "Tobias Koppers @sokra",
"homepage": "https://github.com/webpack-contrib/mini-css-extract-plugin",
"bugs": "https://github.com/webpack-contrib/mini-css-extract-plugin/issues",
- "bin": "",
"main": "dist/cjs.js",
"engines": {
- "node": ">= 6.9.0 <7.0.0 || >= 8.9.0"
+ "node": ">= 6.9.0"
},
"scripts": {
"start": "npm run build -- -w",
+ "prebuild": "npm run clean",
"build": "cross-env NODE_ENV=production babel src -d dist --ignore 'src/**/*.test.js' --copy-files",
+ "postbuild": "es-check es5 dist/hmr/hotModuleReplacement.js",
"clean": "del-cli dist",
- "commitlint": "commitlint",
- "commitmsg": "commitlint -e $GIT_PARAMS",
+ "commitlint": "commitlint --from=master",
"lint": "eslint --cache src test",
- "ci:lint:commits": "commitlint --from=${CIRCLE_BRANCH} --to=${CIRCLE_SHA1}",
- "lint-staged": "lint-staged",
- "prebuild": "npm run clean",
"prepublish": "npm run build",
"release": "standard-version",
- "release:ci": "conventional-github-releaser -p angular",
- "release:validate": "commitlint --from=$(git describe --tags --abbrev=0) --to=$(git rev-parse HEAD)",
- "security": "nsp check",
- "test": "jest",
+ "security": "npm audit",
+ "test:only": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --collectCoverageFrom='src/**/*.js' --coverage",
- "test:manual": "webpack-dev-server test/manual/src/index.js --open --config test/manual/webpack.config.js",
+ "pretest": "npm run lint",
+ "test": "npm run test:only",
"ci:lint": "npm run lint && npm run security",
- "ci:test": "npm run test -- --runInBand",
+ "ci:test": "npm run test:only -- --runInBand",
"ci:coverage": "npm run test:coverage -- --runInBand",
+ "ci:lint:commits": "commitlint --from=origin/master --to=${CIRCLE_SHA1}",
"defaults": "webpack-defaults"
},
"files": [
@@ -43,49 +40,80 @@
"webpack": "^4.4.0"
},
"dependencies": {
- "schema-utils": "^1.0.0",
"loader-utils": "^1.1.0",
+ "normalize-url": "^2.0.1",
+ "schema-utils": "^1.0.0",
"webpack-sources": "^1.1.0"
},
"devDependencies": {
- "@commitlint/cli": "^6.1.3",
- "@commitlint/config-conventional": "^6.1.3",
- "@webpack-contrib/eslint-config-webpack": "^2.0.4",
- "babel-cli": "^6.26.0",
- "babel-jest": "^22.2.2",
- "babel-plugin-transform-object-rest-spread": "^6.26.0",
- "babel-polyfill": "^6.26.0",
- "babel-preset-env": "^1.6.1",
- "conventional-github-releaser": "^2.0.2",
+ "@babel/cli": "^7.4.3",
+ "@babel/core": "^7.4.3",
+ "@babel/preset-env": "^7.4.3",
+ "@commitlint/cli": "^7.5.2",
+ "@commitlint/config-conventional": "^7.5.0",
+ "@webpack-contrib/defaults": "^3.1.1",
+ "@webpack-contrib/eslint-config-webpack": "^3.0.0",
+ "acorn": "^6.1.1",
+ "babel-eslint": "^10.0.1",
+ "babel-jest": "^24.7.1",
"cross-env": "^5.1.3",
- "css-loader": "^0.28.10",
- "del": "^3.0.0",
+ "css-loader": "^2.1.1",
+ "del": "^4.1.0",
"del-cli": "^1.1.0",
- "eslint": "^4.17.0",
- "eslint-plugin-import": "^2.8.0",
- "eslint-plugin-prettier": "^2.6.0",
- "file-loader": "^1.1.11",
- "husky": "^0.14.3",
- "jest": "^22.2.2",
- "lint-staged": "^6.1.0",
+ "es-check": "^5.0.0",
+ "eslint": "^5.16.0",
+ "eslint-plugin-import": "^2.16.0",
+ "eslint-plugin-prettier": "^3.0.1",
+ "file-loader": "^3.0.1",
+ "husky": "^1.3.1",
+ "jest": "^24.7.1",
+ "lint-staged": "^8.1.5",
"memory-fs": "^0.4.1",
- "nsp": "^3.1.0",
"pre-commit": "^1.2.2",
- "prettier": "^1.11.1",
- "standard-version": "^4.3.0",
- "webpack": "^4.14.0",
- "webpack-cli": "^2.0.13",
- "webpack-defaults": "^2.3.0",
- "webpack-dev-server": "^3.1.1"
+ "prettier": "^1.16.4",
+ "standard-version": "^5.0.2",
+ "webpack": "4.29.0",
+ "webpack-cli": "^3.3.0",
+ "webpack-dev-server": "^3.3.1"
},
"keywords": [
- "webpack"
+ "webpack",
+ "css",
+ "extract",
+ "hmr"
],
+ "babel": {
+ "presets": [
+ [
+ "@babel/preset-env",
+ {
+ "targets": {
+ "node": "6.9.0"
+ }
+ }
+ ]
+ ]
+ },
+ "husky": {
+ "hooks": {
"pre-commit": "lint-staged",
+ "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
+ }
+ },
"lint-staged": {
"*.js": [
"eslint --fix",
"git add"
]
+ },
+ "commitlint": {
+ "extends": [
+ "@commitlint/config-conventional"
+ ]
+ },
+ "prettier": {
+ "singleQuote": true,
+ "trailingComma": "es5",
+ "arrowParens": "always"
}
}

README.md

@@ -19,14 +19,10 @@
Compared to the extract-text-webpack-plugin:
-* Async loading
-* No duplicate compilation (performance)
-* Easier to use
-* Specific to CSS
-
-TODO:
-
-* HMR support
+- Async loading
+- No duplicate compilation (performance)
+- Easier to use
+- Specific to CSS
<h2 align="center">Install</h2>
@@ -38,20 +34,27 @@
### Configuration
+#### `publicPath`
+
+Type: `String|Function`
+Default: the `publicPath` in `webpackOptions.output`
+
+Specifies a custom public path for the target file(s).
+
#### Minimal example
**webpack.config.js**
```js
-const MiniCssExtractPlugin = require("mini-css-extract-plugin");
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
- filename: "[name].css",
- chunkFilename: "[id].css"
- })
+ filename: '[name].css',
+ chunkFilename: '[id].css',
+ }),
],
module: {
rules: [
@@ -62,16 +65,56 @@
loader: MiniCssExtractPlugin.loader,
options: {
// you can specify a publicPath here
- // by default it use publicPath in webpackOptions.output
- publicPath: '../'
- }
+ // by default it uses publicPath in webpackOptions.output
+ publicPath: '../',
+ hmr: process.env.NODE_ENV === 'development',
},
- "css-loader"
- ]
- }
- ]
- }
-}
+ },
+ 'css-loader',
+ ],
+ },
+ ],
+ },
+};
+```
+
+#### `publicPath` function example
+
+**webpack.config.js**
+
+```js
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+module.exports = {
+ plugins: [
+ new MiniCssExtractPlugin({
+ // Options similar to the same options in webpackOptions.output
+ // both options are optional
+ filename: '[name].css',
+ chunkFilename: '[id].css',
+ }),
+ ],
+ module: {
+ rules: [
+ {
+ test: /\.css$/,
+ use: [
+ {
+ loader: MiniCssExtractPlugin.loader,
+ options: {
+ publicPath: (resourcePath, context) => {
+ // publicPath is the relative path of the resource to the context
+ // e.g. for ./css/admin/main.css the publicPath will be ../../
+ // while for ./css/main.css the publicPath will be ../
+ return path.relative(path.dirname(resourcePath), context) + '/';
+ },
+ },
+ },
+ 'css-loader',
+ ],
+ },
+ ],
+ },
+};
```
#### Advanced configuration example
@@ -82,12 +125,11 @@
(Loaders options left out for clarity, adapt accordingly to your needs.)
-
**webpack.config.js**
```js
-const MiniCssExtractPlugin = require("mini-css-extract-plugin");
-const devMode = process.env.NODE_ENV !== 'production'
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+const devMode = process.env.NODE_ENV !== 'production';
module.exports = {
plugins: [
@@ -96,63 +138,99 @@
// both options are optional
filename: devMode ? '[name].css' : '[name].[hash].css',
chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
- })
+ }),
],
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
- devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
+ {
+ loader: MiniCssExtractPlugin.loader,
+ options: {
+ hmr: process.env.NODE_ENV === 'development',
+ },
+ },
'css-loader',
'postcss-loader',
'sass-loader',
],
- }
- ]
- }
-}
+ },
+ ],
+ },
+};
+```
+
+#### Hot Module Reloading (HMR)
+
+extract-mini-css-plugin supports hot reloading of actual css files in development. Some options are provided to enable HMR of both standard stylesheets and locally scoped CSS or CSS modules. Below is an example configuration of mini-css for HMR use with CSS modules.
+
+While we attempt to hmr css-modules. It is not easy to perform when code-splitting with custom chunk names. `reloadAll` is an option that should only be enabled if HMR isn't working correctly. The core challenge with css-modules is that when code-split, the chunk ids can and do end up different compared to the filename.
+
+**webpack.config.js**
+
+```js
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+module.exports = {
+ plugins: [
+ new MiniCssExtractPlugin({
+ // Options similar to the same options in webpackOptions.output
+ // both options are optional
+ filename: '[name].css',
+ chunkFilename: '[id].css',
+ }),
+ ],
+ module: {
+ rules: [
+ {
+ test: /\.css$/,
+ use: [
+ {
+ loader: MiniCssExtractPlugin.loader,
+ options: {
+ // only enable hot in development
+ hmr: process.env.NODE_ENV === 'development',
+ // if hmr does not work, this is a forceful method.
+ reloadAll: true,
+ },
+ },
+ 'css-loader',
+ ],
+ },
+ ],
+ },
+};
```
### Minimizing For Production
-While webpack 5 is likely to come with a CSS minimizer built-in, with webpack 4 you need to bring your own. To minify the output, use a plugin like [optimize-css-assets-webpack-plugin](https://github.com/NMFR/optimize-css-assets-webpack-plugin). Setting `optimization.minimizer` overrides the defaults provided by webpack, so make sure to also specify a JS minimizer:
+To minify the output, use a plugin like [optimize-css-assets-webpack-plugin](https://github.com/NMFR/optimize-css-assets-webpack-plugin). Setting `optimization.minimizer` overrides the defaults provided by webpack, so make sure to also specify a JS minimizer:
**webpack.config.js**
```js
-const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
-const MiniCssExtractPlugin = require("mini-css-extract-plugin");
-const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
+const TerserJSPlugin = require('terser-webpack-plugin');
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
optimization: {
- minimizer: [
- new UglifyJsPlugin({
- cache: true,
- parallel: true,
- sourceMap: true // set to true if you want JS source maps
- }),
- new OptimizeCSSAssetsPlugin({})
- ]
+ minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
},
plugins: [
new MiniCssExtractPlugin({
- filename: "[name].css",
- chunkFilename: "[id].css"
- })
+ filename: '[name].css',
+ chunkFilename: '[id].css',
+ }),
],
module: {
rules: [
{
test: /\.css$/,
- use: [
- MiniCssExtractPlugin.loader,
- "css-loader"
- ]
- }
- ]
- }
-}
+ use: [MiniCssExtractPlugin.loader, 'css-loader'],
+ },
+ ],
+ },
+};
```
### Features
@@ -173,7 +251,7 @@
**webpack.config.js**
```js
-const MiniCssExtractPlugin = require("mini-css-extract-plugin");
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
optimization: {
splitChunks: {
@@ -182,28 +260,25 @@
name: 'styles',
test: /\.css$/,
chunks: 'all',
- enforce: true
- }
- }
- }
+ enforce: true,
+ },
+ },
+ },
},
plugins: [
new MiniCssExtractPlugin({
- filename: "[name].css",
- })
+ filename: '[name].css',
+ }),
],
module: {
rules: [
{
test: /\.css$/,
- use: [
- MiniCssExtractPlugin.loader,
- "css-loader"
- ]
- }
- ]
- }
-}
+ use: [MiniCssExtractPlugin.loader, 'css-loader'],
+ },
+ ],
+ },
+};
```
#### Extracting CSS based on entry
@@ -214,7 +289,7 @@
```javascript
const path = require('path');
-const MiniCssExtractPlugin = require("mini-css-extract-plugin");
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
function recursiveIssuer(m) {
if (m.issuer) {
@@ -229,49 +304,52 @@
module.exports = {
entry: {
foo: path.resolve(__dirname, 'src/foo'),
- bar: path.resolve(__dirname, 'src/bar')
+ bar: path.resolve(__dirname, 'src/bar'),
},
optimization: {
splitChunks: {
cacheGroups: {
fooStyles: {
name: 'foo',
- test: (m,c,entry = 'foo') => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
+ test: (m, c, entry = 'foo') =>
+ m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
chunks: 'all',
- enforce: true
+ enforce: true,
},
barStyles: {
name: 'bar',
- test: (m,c,entry = 'bar') => m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
+ test: (m, c, entry = 'bar') =>
+ m.constructor.name === 'CssModule' && recursiveIssuer(m) === entry,
chunks: 'all',
- enforce: true
- }
- }
- }
+ enforce: true,
+ },
+ },
+ },
},
plugins: [
new MiniCssExtractPlugin({
- filename: "[name].css",
- })
+ filename: '[name].css',
+ }),
],
module: {
rules: [
{
test: /\.css$/,
- use: [
- MiniCssExtractPlugin.loader,
- "css-loader"
- ]
- }
- ]
- }
-}
+ use: [MiniCssExtractPlugin.loader, 'css-loader'],
+ },
+ ],
+ },
+};
```
#### Long Term Caching
For long term caching use `filename: "[contenthash].css"`. Optionally add `[name]`.
+### Remove Order Warnings
+
+If the terminal is getting bloated with chunk order warnings. You can filter by configuring [warningsFilter](https://webpack.js.org/configuration/stats/) withing the webpack stats option
+
### Media Query Plugin
If you'd like to extract the media queries from the extracted CSS (so mobile users don't need to load desktop or tablet specific CSS anymore) you should use one of the following plugins:
@@ -279,27 +357,9 @@
- [Media Query Plugin](https://github.com/SassNinja/media-query-plugin)
- [Media Query Splitting Plugin](https://github.com/mike-diamond/media-query-splitting-plugin)
-
-<h2 align="center">Maintainers</h2>
-
-<table>
- <tbody>
- <tr>
- <td align="center">
- <a href="https://github.com/sokra">
- <img width="150" height="150" src="https://github.com/sokra.png?size=150">
- </br>
- Tobias Koppers
- </a>
- </td>
- </tr>
- <tbody>
-</table>
-
-
## License
-#### [MIT](./LICENSE)
+[MIT](./LICENSE)
[npm]: https://img.shields.io/npm/v/mini-css-extract-plugin.svg
[npm-url]: https://npmjs.com/package/mini-css-extract-plugin