mini-css-extract-plugin
Advanced tools
Comparing version 2.8.1 to 2.9.0
@@ -21,3 +21,4 @@ "use strict"; | ||
getUndoPath, | ||
BASE_URI | ||
BASE_URI, | ||
compileBooleanMatcher | ||
} = require("./utils"); | ||
@@ -45,2 +46,3 @@ | ||
* @property {string} [layer] | ||
* @property {boolean} [defaultExport] | ||
*/ | ||
@@ -113,2 +115,4 @@ | ||
* @property {import("tapable").SyncWaterfallHook<[string, VarNames], string>} beforeTagInsert | ||
* @property {SyncWaterfallHook<[string, Chunk]>} linkPreload | ||
* @property {SyncWaterfallHook<[string, Chunk]>} linkPrefetch | ||
*/ | ||
@@ -476,3 +480,4 @@ | ||
* Returns all hooks for the given compilation | ||
* @param {Compilation} compilation | ||
* @param {Compilation} compilation the compilation | ||
* @returns {MiniCssExtractPluginCompilationHooks} hooks | ||
*/ | ||
@@ -483,3 +488,5 @@ static getCompilationHooks(compilation) { | ||
hooks = { | ||
beforeTagInsert: new SyncWaterfallHook(["source", "varNames"], "string") | ||
beforeTagInsert: new SyncWaterfallHook(["source", "varNames"], "string"), | ||
linkPreload: new SyncWaterfallHook(["source", "chunk"]), | ||
linkPrefetch: new SyncWaterfallHook(["source", "chunk"]) | ||
}; | ||
@@ -737,2 +744,13 @@ compilationHooksMap.set(compilation, hooks); | ||
}; | ||
/** | ||
* @param {Chunk} chunk chunk | ||
* @param {ChunkGraph} chunkGraph chunk graph | ||
* @returns {boolean} true, when the chunk has css | ||
*/ | ||
function chunkHasCss(chunk, chunkGraph) { | ||
// this function replace: | ||
// const chunkHasCss = require("webpack/lib/css/CssModulesPlugin").chunkHasCss; | ||
return !!chunkGraph.getChunkModulesIterableBySourceType(chunk, "css/mini-extract"); | ||
} | ||
class CssLoadingRuntimeModule extends RuntimeModule { | ||
@@ -750,2 +768,3 @@ /** | ||
const { | ||
chunkGraph, | ||
chunk, | ||
@@ -766,2 +785,10 @@ runtimeRequirements | ||
} | ||
const conditionMap = /** @type {ChunkGraph} */chunkGraph.getChunkConditionMap( /** @type {Chunk} */chunk, chunkHasCss); | ||
const hasCssMatcher = compileBooleanMatcher(conditionMap); | ||
const withPrefetch = runtimeRequirements.has(RuntimeGlobals.prefetchChunkHandlers); | ||
const withPreload = runtimeRequirements.has(RuntimeGlobals.preloadChunkHandlers); | ||
const { | ||
linkPreload, | ||
linkPrefetch | ||
} = MiniCssExtractPlugin.getCompilationHooks(compilation); | ||
return Template.asString(['if (typeof document === "undefined") return;', `var createStylesheet = ${runtimeTemplate.basicFunction("chunkId, fullhref, oldTag, resolve, reject", ['var linkTag = document.createElement("link");', this.runtimeOptions.attributes ? Template.asString(Object.entries(this.runtimeOptions.attributes).map(entry => { | ||
@@ -779,3 +806,3 @@ const [key, value] = entry; | ||
}) || "", typeof this.runtimeOptions.insert !== "undefined" ? typeof this.runtimeOptions.insert === "function" ? `(${this.runtimeOptions.insert.toString()})(linkTag)` : Template.asString([`var target = document.querySelector("${this.runtimeOptions.insert}");`, `target.parentNode.insertBefore(linkTag, target.nextSibling);`]) : Template.asString(["if (oldTag) {", Template.indent(["oldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);"]), "} else {", Template.indent(["document.head.appendChild(linkTag);"]), "}"]), "return linkTag;"])};`, `var findStylesheet = ${runtimeTemplate.basicFunction("href, fullhref", ['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 tag;']), "}", '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 tag;"]), "}"])};`, `var loadStylesheet = ${runtimeTemplate.basicFunction("chunkId", `return new Promise(${runtimeTemplate.basicFunction("resolve, reject", [`var href = ${RuntimeGlobals.require}.miniCssF(chunkId);`, `var fullhref = ${RuntimeGlobals.publicPath} + href;`, "if(findStylesheet(href, fullhref)) return resolve();", "createStylesheet(chunkId, fullhref, null, resolve, reject);"])});`)}`, withLoading ? Template.asString(["// object to store loaded CSS chunks", "var installedCssChunks = {", Template.indent( /** @type {string[]} */ | ||
( /** @type {Chunk} */chunk.ids).map(id => `${JSON.stringify(id)}: 0`).join(",\n")), "};", "", `${RuntimeGlobals.ensureChunkHandlers}.miniCss = ${runtimeTemplate.basicFunction("chunkId, promises", [`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] = loadStylesheet(chunkId).then(${runtimeTemplate.basicFunction("", "installedCssChunks[chunkId] = 0;")}, ${runtimeTemplate.basicFunction("e", ["delete installedCssChunks[chunkId];", "throw e;"])}));`]), "}"])};`]) : "// no chunk loading", "", withHmr ? Template.asString(["var oldTags = [];", "var newTags = [];", `var applyHandler = ${runtimeTemplate.basicFunction("options", [`return { dispose: ${runtimeTemplate.basicFunction("", ["for(var i = 0; i < oldTags.length; i++) {", Template.indent(["var oldTag = oldTags[i];", "if(oldTag.parentNode) oldTag.parentNode.removeChild(oldTag);"]), "}", "oldTags.length = 0;"])}, apply: ${runtimeTemplate.basicFunction("", ['for(var i = 0; i < newTags.length; i++) newTags[i].rel = "stylesheet";', "newTags.length = 0;"])} };`])}`, `${RuntimeGlobals.hmrDownloadUpdateHandlers}.miniCss = ${runtimeTemplate.basicFunction("chunkIds, removedChunks, removedModules, promises, applyHandlers, updatedModulesList", ["applyHandlers.push(applyHandler);", `chunkIds.forEach(${runtimeTemplate.basicFunction("chunkId", [`var href = ${RuntimeGlobals.require}.miniCssF(chunkId);`, `var fullhref = ${RuntimeGlobals.publicPath} + href;`, "var oldTag = findStylesheet(href, fullhref);", "if(!oldTag) return;", `promises.push(new Promise(${runtimeTemplate.basicFunction("resolve, reject", [`var tag = createStylesheet(chunkId, fullhref, oldTag, ${runtimeTemplate.basicFunction("", ['tag.as = "style";', 'tag.rel = "preload";', "resolve();"])}, reject);`, "oldTags.push(oldTag);", "newTags.push(tag);"])}));`])});`])}`]) : "// no hmr"]); | ||
( /** @type {Chunk} */chunk.ids).map(id => `${JSON.stringify(id)}: 0`).join(",\n")), "};", "", `${RuntimeGlobals.ensureChunkHandlers}.miniCss = ${runtimeTemplate.basicFunction("chunkId, promises", [`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] = loadStylesheet(chunkId).then(${runtimeTemplate.basicFunction("", "installedCssChunks[chunkId] = 0;")}, ${runtimeTemplate.basicFunction("e", ["delete installedCssChunks[chunkId];", "throw e;"])}));`]), "}"])};`]) : "// no chunk loading", "", withHmr ? Template.asString(["var oldTags = [];", "var newTags = [];", `var applyHandler = ${runtimeTemplate.basicFunction("options", [`return { dispose: ${runtimeTemplate.basicFunction("", ["for(var i = 0; i < oldTags.length; i++) {", Template.indent(["var oldTag = oldTags[i];", "if(oldTag.parentNode) oldTag.parentNode.removeChild(oldTag);"]), "}", "oldTags.length = 0;"])}, apply: ${runtimeTemplate.basicFunction("", ['for(var i = 0; i < newTags.length; i++) newTags[i].rel = "stylesheet";', "newTags.length = 0;"])} };`])}`, `${RuntimeGlobals.hmrDownloadUpdateHandlers}.miniCss = ${runtimeTemplate.basicFunction("chunkIds, removedChunks, removedModules, promises, applyHandlers, updatedModulesList", ["applyHandlers.push(applyHandler);", `chunkIds.forEach(${runtimeTemplate.basicFunction("chunkId", [`var href = ${RuntimeGlobals.require}.miniCssF(chunkId);`, `var fullhref = ${RuntimeGlobals.publicPath} + href;`, "var oldTag = findStylesheet(href, fullhref);", "if(!oldTag) return;", `promises.push(new Promise(${runtimeTemplate.basicFunction("resolve, reject", [`var tag = createStylesheet(chunkId, fullhref, oldTag, ${runtimeTemplate.basicFunction("", ['tag.as = "style";', 'tag.rel = "preload";', "resolve();"])}, reject);`, "oldTags.push(oldTag);", "newTags.push(tag);"])}));`])});`])}`]) : "// no hmr", "", withPrefetch && hasCssMatcher !== false ? `${RuntimeGlobals.prefetchChunkHandlers}.miniCss = ${runtimeTemplate.basicFunction("chunkId", [`if((!${RuntimeGlobals.hasOwnProperty}(installedCssChunks, chunkId) || installedCssChunks[chunkId] === undefined) && ${hasCssMatcher === true ? "true" : hasCssMatcher("chunkId")}) {`, Template.indent(["installedCssChunks[chunkId] = null;", linkPrefetch.call(Template.asString(["var link = document.createElement('link');", crossOriginLoading ? `link.crossOrigin = ${JSON.stringify(crossOriginLoading)};` : "", `if (${RuntimeGlobals.scriptNonce}) {`, Template.indent(`link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`), "}", 'link.rel = "prefetch";', 'link.as = "style";', `link.href = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.require}.miniCssF(chunkId);`]), /** @type {Chunk} */chunk), "document.head.appendChild(link);"]), "}"])};` : "// no prefetching", "", withPreload && hasCssMatcher !== false ? `${RuntimeGlobals.preloadChunkHandlers}.miniCss = ${runtimeTemplate.basicFunction("chunkId", [`if((!${RuntimeGlobals.hasOwnProperty}(installedCssChunks, chunkId) || installedCssChunks[chunkId] === undefined) && ${hasCssMatcher === true ? "true" : hasCssMatcher("chunkId")}) {`, Template.indent(["installedCssChunks[chunkId] = null;", linkPreload.call(Template.asString(["var link = document.createElement('link');", "link.charset = 'utf-8';", `if (${RuntimeGlobals.scriptNonce}) {`, Template.indent(`link.setAttribute("nonce", ${RuntimeGlobals.scriptNonce});`), "}", 'link.rel = "preload";', 'link.as = "style";', `link.href = ${RuntimeGlobals.publicPath} + ${RuntimeGlobals.require}.miniCssF(chunkId);`, crossOriginLoading ? crossOriginLoading === "use-credentials" ? 'link.crossOrigin = "use-credentials";' : Template.asString(["if (link.href.indexOf(window.location.origin + '/') !== 0) {", Template.indent(`link.crossOrigin = ${JSON.stringify(crossOriginLoading)};`), "}"]) : ""]), /** @type {Chunk} */chunk), "document.head.appendChild(link);"]), "}"])};` : "// no preloaded"]); | ||
} | ||
@@ -813,2 +840,4 @@ } | ||
compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.hmrDownloadUpdateHandlers).tap(pluginName, handler); | ||
compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.prefetchChunkHandlers).tap(pluginName, handler); | ||
compilation.hooks.runtimeRequirementInTree.for(RuntimeGlobals.preloadChunkHandlers).tap(pluginName, handler); | ||
}); | ||
@@ -815,0 +844,0 @@ } |
@@ -30,4 +30,9 @@ { | ||
"type": "string" | ||
}, | ||
"defaultExport": { | ||
"type": "boolean", | ||
"description": "Duplicate the named export with CSS modules locals to the default export (only when `esModules: true` for css-loader).", | ||
"link": "https://github.com/webpack-contrib/mini-css-extract-plugin#defaultexports" | ||
} | ||
} | ||
} |
@@ -47,12 +47,24 @@ "use strict"; | ||
function hotLoader(content, context) { | ||
const accept = context.locals ? "" : "module.hot.accept(undefined, cssReload);"; | ||
const localsJsonString = JSON.stringify(JSON.stringify(context.locals)); | ||
return `${content} | ||
if(module.hot) { | ||
// ${Date.now()} | ||
var cssReload = require(${stringifyRequest(context.loaderContext, path.join(__dirname, "hmr/hotModuleReplacement.js"))})(module.id, ${JSON.stringify({ | ||
...context.options, | ||
locals: !!context.locals | ||
})}); | ||
module.hot.dispose(cssReload); | ||
${accept} | ||
(function() { | ||
var localsJsonString = ${localsJsonString}; | ||
// ${Date.now()} | ||
var cssReload = require(${stringifyRequest(context.loaderContext, path.join(__dirname, "hmr/hotModuleReplacement.js"))})(module.id, ${JSON.stringify(context.options)}); | ||
// only invalidate when locals change | ||
if ( | ||
module.hot.data && | ||
module.hot.data.value && | ||
module.hot.data.value !== localsJsonString | ||
) { | ||
module.hot.invalidate(); | ||
} else { | ||
module.hot.accept(); | ||
} | ||
module.hot.dispose(function(data) { | ||
data.value = localsJsonString; | ||
cssReload(); | ||
}); | ||
})(); | ||
} | ||
@@ -197,3 +209,4 @@ `; | ||
const exportsString = `export { ${identifiers.map(([id, key]) => `${id} as ${JSON.stringify(key)}`).join(", ")} }`; | ||
return `${localsString}\n${exportsString}\n`; | ||
const defaultExport = typeof options.defaultExport !== "undefined" ? options.defaultExport : false; | ||
return defaultExport ? `${localsString}\n${exportsString}\nexport default { ${identifiers.map(([id, key]) => `${JSON.stringify(key)}: ${id}`).join(", ")} }\n` : `${localsString}\n${exportsString}\n`; | ||
} | ||
@@ -411,2 +424,3 @@ return `\n${esModule ? "export default" : "module.exports = "} ${JSON.stringify(locals)};`; | ||
module.exports = loader; | ||
module.exports.pitch = pitch; | ||
module.exports.pitch = pitch; | ||
module.exports.hotLoader = hotLoader; |
@@ -185,2 +185,219 @@ "use strict"; | ||
} | ||
/** | ||
* @param {string} str string | ||
* @returns {string} string | ||
*/ | ||
const toSimpleString = str => { | ||
if (`${+str}` === str) { | ||
return str; | ||
} | ||
return JSON.stringify(str); | ||
}; | ||
/** | ||
* @param {string} str string | ||
* @returns {string} quoted meta | ||
*/ | ||
const quoteMeta = str => str.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&"); | ||
/** | ||
* @param {Array<string>} items items | ||
* @returns {string} common prefix | ||
*/ | ||
const getCommonPrefix = items => { | ||
let prefix = items[0]; | ||
for (let i = 1; i < items.length; i++) { | ||
const item = items[i]; | ||
for (let p = 0; p < prefix.length; p++) { | ||
if (item[p] !== prefix[p]) { | ||
prefix = prefix.slice(0, p); | ||
break; | ||
} | ||
} | ||
} | ||
return prefix; | ||
}; | ||
/** | ||
* @param {Array<string>} items items | ||
* @returns {string} common suffix | ||
*/ | ||
const getCommonSuffix = items => { | ||
let suffix = items[0]; | ||
for (let i = 1; i < items.length; i++) { | ||
const item = items[i]; | ||
for (let p = item.length - 1, s = suffix.length - 1; s >= 0; p--, s--) { | ||
if (item[p] !== suffix[s]) { | ||
suffix = suffix.slice(s + 1); | ||
break; | ||
} | ||
} | ||
} | ||
return suffix; | ||
}; | ||
/** | ||
* @param {Set<string>} itemsSet items set | ||
* @param {(str: string) => string | false} getKey get key function | ||
* @param {(str: Array<string>) => boolean} condition condition | ||
* @returns {Array<Array<string>>} list of common items | ||
*/ | ||
const popCommonItems = (itemsSet, getKey, condition) => { | ||
/** @type {Map<string, Array<string>>} */ | ||
const map = new Map(); | ||
for (const item of itemsSet) { | ||
const key = getKey(item); | ||
if (key) { | ||
let list = map.get(key); | ||
if (list === undefined) { | ||
/** @type {Array<string>} */ | ||
list = []; | ||
map.set(key, list); | ||
} | ||
list.push(item); | ||
} | ||
} | ||
/** @type {Array<Array<string>>} */ | ||
const result = []; | ||
for (const list of map.values()) { | ||
if (condition(list)) { | ||
for (const item of list) { | ||
itemsSet.delete(item); | ||
} | ||
result.push(list); | ||
} | ||
} | ||
return result; | ||
}; | ||
/** | ||
* @param {Array<string>} itemsArr array of items | ||
* @returns {string} regexp | ||
*/ | ||
const itemsToRegexp = itemsArr => { | ||
if (itemsArr.length === 1) { | ||
return quoteMeta(itemsArr[0]); | ||
} | ||
/** @type {Array<string>} */ | ||
const finishedItems = []; | ||
// merge single char items: (a|b|c|d|ef) => ([abcd]|ef) | ||
let countOfSingleCharItems = 0; | ||
for (const item of itemsArr) { | ||
if (item.length === 1) { | ||
// eslint-disable-next-line no-plusplus | ||
countOfSingleCharItems++; | ||
} | ||
} | ||
// special case for only single char items | ||
if (countOfSingleCharItems === itemsArr.length) { | ||
return `[${quoteMeta(itemsArr.sort().join(""))}]`; | ||
} | ||
const items = new Set(itemsArr.sort()); | ||
if (countOfSingleCharItems > 2) { | ||
let singleCharItems = ""; | ||
for (const item of items) { | ||
if (item.length === 1) { | ||
singleCharItems += item; | ||
items.delete(item); | ||
} | ||
} | ||
finishedItems.push(`[${quoteMeta(singleCharItems)}]`); | ||
} | ||
// special case for 2 items with common prefix/suffix | ||
if (finishedItems.length === 0 && items.size === 2) { | ||
const prefix = getCommonPrefix(itemsArr); | ||
const suffix = getCommonSuffix(itemsArr.map(item => item.slice(prefix.length))); | ||
if (prefix.length > 0 || suffix.length > 0) { | ||
return `${quoteMeta(prefix)}${itemsToRegexp(itemsArr.map(i => i.slice(prefix.length, -suffix.length || undefined)))}${quoteMeta(suffix)}`; | ||
} | ||
} | ||
// special case for 2 items with common suffix | ||
if (finishedItems.length === 0 && items.size === 2) { | ||
/** @type {Iterator<string>} */ | ||
const it = items[Symbol.iterator](); | ||
const a = it.next().value; | ||
const b = it.next().value; | ||
if (a.length > 0 && b.length > 0 && a.slice(-1) === b.slice(-1)) { | ||
return `${itemsToRegexp([a.slice(0, -1), b.slice(0, -1)])}${quoteMeta(a.slice(-1))}`; | ||
} | ||
} | ||
// find common prefix: (a1|a2|a3|a4|b5) => (a(1|2|3|4)|b5) | ||
const prefixed = popCommonItems(items, item => item.length >= 1 ? item[0] : false, list => { | ||
if (list.length >= 3) return true; | ||
if (list.length <= 1) return false; | ||
return list[0][1] === list[1][1]; | ||
}); | ||
for (const prefixedItems of prefixed) { | ||
const prefix = getCommonPrefix(prefixedItems); | ||
finishedItems.push(`${quoteMeta(prefix)}${itemsToRegexp(prefixedItems.map(i => i.slice(prefix.length)))}`); | ||
} | ||
// find common suffix: (a1|b1|c1|d1|e2) => ((a|b|c|d)1|e2) | ||
const suffixed = popCommonItems(items, item => item.length >= 1 ? item.slice(-1) : false, list => { | ||
if (list.length >= 3) return true; | ||
if (list.length <= 1) return false; | ||
return list[0].slice(-2) === list[1].slice(-2); | ||
}); | ||
for (const suffixedItems of suffixed) { | ||
const suffix = getCommonSuffix(suffixedItems); | ||
finishedItems.push(`${itemsToRegexp(suffixedItems.map(i => i.slice(0, -suffix.length)))}${quoteMeta(suffix)}`); | ||
} | ||
// TODO further optimize regexp, i. e. | ||
// use ranges: (1|2|3|4|a) => [1-4a] | ||
const conditional = finishedItems.concat(Array.from(items, quoteMeta)); | ||
if (conditional.length === 1) return conditional[0]; | ||
return `(${conditional.join("|")})`; | ||
}; | ||
/** | ||
* @param {string[]} positiveItems positive items | ||
* @param {string[]} negativeItems negative items | ||
* @returns {function(string): string} a template function to determine the value at runtime | ||
*/ | ||
const compileBooleanMatcherFromLists = (positiveItems, negativeItems) => { | ||
if (positiveItems.length === 0) { | ||
return () => "false"; | ||
} | ||
if (negativeItems.length === 0) { | ||
return () => "true"; | ||
} | ||
if (positiveItems.length === 1) { | ||
return value => `${toSimpleString(positiveItems[0])} == ${value}`; | ||
} | ||
if (negativeItems.length === 1) { | ||
return value => `${toSimpleString(negativeItems[0])} != ${value}`; | ||
} | ||
const positiveRegexp = itemsToRegexp(positiveItems); | ||
const negativeRegexp = itemsToRegexp(negativeItems); | ||
if (positiveRegexp.length <= negativeRegexp.length) { | ||
return value => `/^${positiveRegexp}$/.test(${value})`; | ||
} | ||
return value => `!/^${negativeRegexp}$/.test(${value})`; | ||
}; | ||
// TODO simplify in the next major release and use it from webpack | ||
/** | ||
* @param {Record<string|number, boolean>} map value map | ||
* @returns {boolean|(function(string): string)} true/false, when unconditionally true/false, or a template function to determine the value at runtime | ||
*/ | ||
const compileBooleanMatcher = map => { | ||
const positiveItems = Object.keys(map).filter(i => map[i]); | ||
const negativeItems = Object.keys(map).filter(i => !map[i]); | ||
if (positiveItems.length === 0) { | ||
return false; | ||
} | ||
if (negativeItems.length === 0) { | ||
return true; | ||
} | ||
return compileBooleanMatcherFromLists(positiveItems, negativeItems); | ||
}; | ||
module.exports = { | ||
@@ -198,3 +415,4 @@ trueFn, | ||
stringifyLocal, | ||
getUndoPath | ||
getUndoPath, | ||
compileBooleanMatcher | ||
}; |
{ | ||
"name": "mini-css-extract-plugin", | ||
"version": "2.8.1", | ||
"version": "2.9.0", | ||
"description": "extracts CSS into separate files", | ||
@@ -59,6 +59,6 @@ "license": "MIT", | ||
"devDependencies": { | ||
"@babel/cli": "^7.21.0", | ||
"@babel/core": "^7.21.4", | ||
"@babel/eslint-parser": "^7.19.1", | ||
"@babel/preset-env": "^7.21.4", | ||
"@babel/cli": "^7.24.1", | ||
"@babel/core": "^7.24.4", | ||
"@babel/eslint-parser": "^7.24.1", | ||
"@babel/preset-env": "^7.24.4", | ||
"@commitlint/cli": "^17.5.1", | ||
@@ -88,7 +88,7 @@ "@commitlint/config-conventional": "^17.4.4", | ||
"prettier": "^2.8.7", | ||
"sass": "^1.60.0", | ||
"sass": "^1.74.1", | ||
"sass-loader": "^12.6.0", | ||
"standard-version": "^9.3.0", | ||
"typescript": "^4.9.5", | ||
"webpack": "^5.83.1", | ||
"webpack": "^5.91.0", | ||
"webpack-cli": "^4.9.2", | ||
@@ -95,0 +95,0 @@ "webpack-dev-server": "^4.13.2" |
@@ -410,2 +410,3 @@ <div align="center"> | ||
- **[`esModule`](#esModule)** | ||
- **[`defaultExport`](#defaultExport)** | ||
@@ -553,2 +554,56 @@ #### `publicPath` | ||
#### `defaultExport` | ||
Type: | ||
```ts | ||
type defaultExport = boolean; | ||
``` | ||
Default: `false` | ||
> **Note** | ||
> | ||
> This option will work only when you set `namedExport` to `true` in `css-loader` | ||
By default, `mini-css-extract-plugin` generates JS modules based on the `esModule` and `namedExport` options in `css-loader`. | ||
Using the `esModule` and `namedExport` options will allow you to better optimize your code. | ||
If you set `esModule: true` and `namedExport: true` for `css-loader` `mini-css-extract-plugin` will generate **only** a named export. | ||
Our official recommendation is to use only named export for better future compatibility. | ||
But for some applications, it is not easy to quickly rewrite the code from the default export to a named export. | ||
In case you need both default and named exports, you can enable this option: | ||
**webpack.config.js** | ||
```js | ||
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); | ||
module.exports = { | ||
plugins: [new MiniCssExtractPlugin()], | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.css$/i, | ||
use: [ | ||
{ | ||
loader: MiniCssExtractPlugin.loader, | ||
options: { | ||
defaultExport: true, | ||
}, | ||
}, | ||
{ | ||
loader: "css-loader", | ||
esModule: true, | ||
modules: { | ||
namedExport: true, | ||
}, | ||
}, | ||
], | ||
}, | ||
], | ||
}, | ||
}; | ||
``` | ||
## Examples | ||
@@ -555,0 +610,0 @@ |
@@ -17,3 +17,4 @@ export = MiniCssExtractPlugin; | ||
* Returns all hooks for the given compilation | ||
* @param {Compilation} compilation | ||
* @param {Compilation} compilation the compilation | ||
* @returns {MiniCssExtractPluginCompilationHooks} hooks | ||
*/ | ||
@@ -122,2 +123,4 @@ static getCompilationHooks( | ||
>; | ||
linkPreload: SyncWaterfallHook<[string, Chunk]>; | ||
linkPrefetch: SyncWaterfallHook<[string, Chunk]>; | ||
}; | ||
@@ -153,2 +156,3 @@ type PluginOptions = { | ||
* @property {string} [layer] | ||
* @property {boolean} [defaultExport] | ||
*/ | ||
@@ -206,2 +210,3 @@ /** | ||
layer?: string | undefined; | ||
defaultExport?: boolean | undefined; | ||
}; | ||
@@ -262,1 +267,2 @@ type NormalizedPluginOptions = { | ||
}; | ||
import { SyncWaterfallHook } from "tapable"; |
@@ -13,2 +13,3 @@ export = loader; | ||
pitch, | ||
hotLoader, | ||
Schema, | ||
@@ -37,2 +38,36 @@ Compiler, | ||
): void; | ||
/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */ | ||
/** @typedef {import("webpack").Compiler} Compiler */ | ||
/** @typedef {import("webpack").Compilation} Compilation */ | ||
/** @typedef {import("webpack").Chunk} Chunk */ | ||
/** @typedef {import("webpack").Module} Module */ | ||
/** @typedef {import("webpack").sources.Source} Source */ | ||
/** @typedef {import("webpack").AssetInfo} AssetInfo */ | ||
/** @typedef {import("webpack").NormalModule} NormalModule */ | ||
/** @typedef {import("./index.js").LoaderOptions} LoaderOptions */ | ||
/** @typedef {{ [key: string]: string | function }} Locals */ | ||
/** @typedef {any} TODO */ | ||
/** | ||
* @typedef {Object} Dependency | ||
* @property {string} identifier | ||
* @property {string | null} context | ||
* @property {Buffer} content | ||
* @property {string} media | ||
* @property {string} [supports] | ||
* @property {string} [layer] | ||
* @property {Buffer} [sourceMap] | ||
*/ | ||
/** | ||
* @param {string} content | ||
* @param {{ loaderContext: import("webpack").LoaderContext<LoaderOptions>, options: LoaderOptions, locals: Locals | undefined }} context | ||
* @returns {string} | ||
*/ | ||
declare function hotLoader( | ||
content: string, | ||
context: { | ||
loaderContext: import("webpack").LoaderContext<LoaderOptions>; | ||
options: LoaderOptions; | ||
locals: Locals | undefined; | ||
} | ||
): string; | ||
type Schema = import("schema-utils/declarations/validate").Schema; | ||
@@ -39,0 +74,0 @@ type Compiler = import("webpack").Compiler; |
@@ -68,1 +68,8 @@ export type Compilation = import("webpack").Compilation; | ||
): string; | ||
/** | ||
* @param {Record<string|number, boolean>} map value map | ||
* @returns {boolean|(function(string): string)} true/false, when unconditionally true/false, or a template function to determine the value at runtime | ||
*/ | ||
export function compileBooleanMatcher( | ||
map: Record<string | number, boolean> | ||
): boolean | ((arg0: string) => string); |
133496
2644
1295