diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml
index a3f31c9b..1053483a 100644
--- a/.github/workflows/nodejs.yml
+++ b/.github/workflows/nodejs.yml
@@ -56,7 +56,7 @@ jobs:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [10.x, 12.x, 14.x]
- webpack-version: [4, latest]
+ webpack-version: [latest]
runs-on: ${{ matrix.os }}
diff --git a/jest.config.js b/jest.config.js
index 0cff348b..9d9cc847 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -3,5 +3,4 @@ module.exports = {
transformIgnorePatterns: ['/node_modules/', '/dist/'],
watchPathIgnorePatterns: ['/test/js'],
setupFilesAfterEnv: ['/setupTest.js'],
- snapshotResolver: './test/helpers/snapshotResolver.js',
};
diff --git a/package-lock.json b/package-lock.json
index 2558dec5..7067dafe 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,6 +5,7 @@
"requires": true,
"packages": {
"": {
+ "name": "mini-css-extract-plugin",
"version": "1.6.0",
"license": "MIT",
"dependencies": {
@@ -51,7 +52,7 @@
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
- "webpack": "^4.4.0 || ^5.0.0"
+ "webpack": "^5.0.0"
}
},
"node_modules/@babel/cli": {
diff --git a/package.json b/package.json
index 404527e9..6cc59a27 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,7 @@
"dist"
],
"peerDependencies": {
- "webpack": "^4.4.0 || ^5.0.0"
+ "webpack": "^5.0.0"
},
"dependencies": {
"loader-utils": "^2.0.0",
diff --git a/src/index.js b/src/index.js
index 4c1b009a..91bafed3 100644
--- a/src/index.js
+++ b/src/index.js
@@ -2,17 +2,19 @@
import { validate } from 'schema-utils';
+import { getUndoPath } from 'webpack/lib/util/identifier';
+
import schema from './plugin-options.json';
-import { MODULE_TYPE, compareModulesByIdentifier } from './utils';
+import {
+ MODULE_TYPE,
+ AUTO_PUBLIC_PATH,
+ compareModulesByIdentifier,
+} from './utils';
export const pluginName = 'mini-css-extract-plugin';
export const pluginSymbol = Symbol(pluginName);
-const REGEXP_CHUNKHASH = /\[chunkhash(?::(\d+))?\]/i;
-const REGEXP_CONTENTHASH = /\[contenthash(?::(\d+))?\]/i;
-const REGEXP_NAME = /\[name\]/i;
const DEFAULT_FILENAME = '[name].css';
-
const TYPES = new Set([MODULE_TYPE]);
const CODE_GENERATION_RESULT = {
sources: new Map(),
@@ -152,48 +154,42 @@ class MiniCssExtractPlugin {
cssModuleCache.set(webpack, CssModule);
- if (
- webpack.util &&
- webpack.util.serialization &&
- webpack.util.serialization.register
- ) {
- webpack.util.serialization.register(
- CssModule,
- 'mini-css-extract-plugin/dist/CssModule',
- null,
- {
- serialize(instance, context) {
- instance.serialize(context);
- },
- deserialize(context) {
- const { read } = context;
-
- const contextModule = read();
- const identifier = read();
- const identifierIndex = read();
- const content = read();
- const media = read();
- const sourceMap = read();
- const { assets, assetsInfo } = read();
-
- const dep = new CssModule({
- context: contextModule,
- identifier,
- identifierIndex,
- content,
- media,
- sourceMap,
- assets,
- assetsInfo,
- });
-
- dep.deserialize(context);
-
- return dep;
- },
- }
- );
- }
+ webpack.util.serialization.register(
+ CssModule,
+ 'mini-css-extract-plugin/dist/CssModule',
+ null,
+ {
+ serialize(instance, context) {
+ instance.serialize(context);
+ },
+ deserialize(context) {
+ const { read } = context;
+
+ const contextModule = read();
+ const identifier = read();
+ const identifierIndex = read();
+ const content = read();
+ const media = read();
+ const sourceMap = read();
+ const { assets, assetsInfo } = read();
+
+ const dep = new CssModule({
+ context: contextModule,
+ identifier,
+ identifierIndex,
+ content,
+ media,
+ sourceMap,
+ assets,
+ assetsInfo,
+ });
+
+ dep.deserialize(context);
+
+ return dep;
+ },
+ }
+ );
return CssModule;
}
@@ -257,45 +253,39 @@ class MiniCssExtractPlugin {
cssDependencyCache.set(webpack, CssDependency);
- if (
- webpack.util &&
- webpack.util.serialization &&
- webpack.util.serialization.register
- ) {
- webpack.util.serialization.register(
- CssDependency,
- 'mini-css-extract-plugin/dist/CssDependency',
- null,
- {
- serialize(instance, context) {
- instance.serialize(context);
- },
- deserialize(context) {
- const { read } = context;
- const dep = new CssDependency(
- {
- identifier: read(),
- content: read(),
- media: read(),
- sourceMap: read(),
- },
- read(),
- read()
- );
-
- const assets = read();
- const assetsInfo = read();
-
- dep.assets = assets;
- dep.assetsInfo = assetsInfo;
-
- dep.deserialize(context);
-
- return dep;
- },
- }
- );
- }
+ webpack.util.serialization.register(
+ CssDependency,
+ 'mini-css-extract-plugin/dist/CssDependency',
+ null,
+ {
+ serialize(instance, context) {
+ instance.serialize(context);
+ },
+ deserialize(context) {
+ const { read } = context;
+ const dep = new CssDependency(
+ {
+ identifier: read(),
+ content: read(),
+ media: read(),
+ sourceMap: read(),
+ },
+ read(),
+ read()
+ );
+
+ const assets = read();
+ const assetsInfo = read();
+
+ dep.assets = assets;
+ dep.assetsInfo = assetsInfo;
+
+ dep.deserialize(context);
+
+ return dep;
+ },
+ }
+ );
return CssDependency;
}
@@ -354,10 +344,7 @@ class MiniCssExtractPlugin {
/** @param {import("webpack").Compiler} compiler */
apply(compiler) {
- const webpack = compiler.webpack
- ? compiler.webpack
- : // eslint-disable-next-line global-require
- require('webpack');
+ const { webpack } = compiler;
if (this.options.experimentalUseImportModule) {
if (!compiler.options.experiments) {
@@ -373,45 +360,27 @@ class MiniCssExtractPlugin {
// TODO bug in webpack, remove it after it will be fixed
// webpack tries to `require` loader firstly when serializer doesn't found
- if (
- webpack.util &&
- webpack.util.serialization &&
- webpack.util.serialization.registerLoader
- ) {
- webpack.util.serialization.registerLoader(
- /^mini-css-extract-plugin\//,
- () => true
- );
- }
-
- const isWebpack4 = compiler.webpack
- ? false
- : typeof compiler.resolvers !== 'undefined';
+ webpack.util.serialization.registerLoader(
+ /^mini-css-extract-plugin\//,
+ () => true
+ );
- if (!isWebpack4) {
- const { splitChunks } = compiler.options.optimization;
+ const { splitChunks } = compiler.options.optimization;
- if (splitChunks) {
- if (splitChunks.defaultSizeTypes.includes('...')) {
- splitChunks.defaultSizeTypes.push(MODULE_TYPE);
- }
+ if (splitChunks) {
+ if (splitChunks.defaultSizeTypes.includes('...')) {
+ splitChunks.defaultSizeTypes.push(MODULE_TYPE);
}
}
const CssModule = MiniCssExtractPlugin.getCssModule(webpack);
const CssDependency = MiniCssExtractPlugin.getCssDependency(webpack);
- const NormalModule =
- compiler.webpack && compiler.webpack.NormalModule
- ? compiler.webpack.NormalModule
- : // eslint-disable-next-line global-require
- require('webpack/lib/NormalModule');
+ const { NormalModule } = compiler.webpack;
compiler.hooks.compilation.tap(pluginName, (compilation) => {
- const normalModuleHook =
- typeof NormalModule.getCompilationHooks !== 'undefined'
- ? NormalModule.getCompilationHooks(compilation).loader
- : compilation.hooks.normalModuleLoader;
+ const { loader: normalModuleHook } =
+ NormalModule.getCompilationHooks(compilation);
normalModuleHook.tap(pluginName, (loaderContext) => {
// eslint-disable-next-line no-param-reassign
@@ -444,168 +413,62 @@ class MiniCssExtractPlugin {
new CssDependencyTemplate()
);
- if (isWebpack4) {
- compilation.mainTemplate.hooks.renderManifest.tap(
- pluginName,
- (result, { chunk }) => {
- const { chunkGraph } = compilation;
-
- const renderedModules = Array.from(
- this.getChunkModules(chunk, chunkGraph)
- ).filter((module) => module.type === MODULE_TYPE);
-
- const filenameTemplate =
- chunk.filenameTemplate || this.options.filename;
-
- if (renderedModules.length > 0) {
- result.push({
- render: () =>
- this.renderContentAsset(
- compiler,
- compilation,
- chunk,
- renderedModules,
- compilation.runtimeTemplate.requestShortener
- ),
- filenameTemplate,
- pathOptions: {
- chunk,
- contentHashType: MODULE_TYPE,
- },
- identifier: `${pluginName}.${chunk.id}`,
- hash: chunk.contentHash[MODULE_TYPE],
- });
- }
- }
- );
-
- compilation.chunkTemplate.hooks.renderManifest.tap(
- pluginName,
- (result, { chunk }) => {
- const { chunkGraph } = compilation;
-
- const renderedModules = Array.from(
- this.getChunkModules(chunk, chunkGraph)
- ).filter((module) => module.type === MODULE_TYPE);
-
- const filenameTemplate =
- chunk.filenameTemplate || this.options.chunkFilename;
-
- if (renderedModules.length > 0) {
- result.push({
- render: () =>
- this.renderContentAsset(
- compiler,
- compilation,
- chunk,
- renderedModules,
- compilation.runtimeTemplate.requestShortener
- ),
- filenameTemplate,
- pathOptions: {
- chunk,
- contentHashType: MODULE_TYPE,
- },
- identifier: `${pluginName}.${chunk.id}`,
- hash: chunk.contentHash[MODULE_TYPE],
- });
- }
- }
- );
- } else {
- compilation.hooks.renderManifest.tap(
- pluginName,
- (result, { chunk }) => {
- const { chunkGraph } = compilation;
- const { HotUpdateChunk } = webpack;
-
- // We don't need hot update chunks for css
- // We will use the real asset instead to update
- if (chunk instanceof HotUpdateChunk) {
- return;
- }
+ compilation.hooks.renderManifest.tap(pluginName, (result, { chunk }) => {
+ const { chunkGraph } = compilation;
+ const { HotUpdateChunk } = webpack;
- const renderedModules = Array.from(
- this.getChunkModules(chunk, chunkGraph)
- ).filter((module) => module.type === MODULE_TYPE);
-
- const filenameTemplate = chunk.canBeInitial()
- ? this.options.filename
- : this.options.chunkFilename;
-
- if (renderedModules.length > 0) {
- result.push({
- render: () =>
- this.renderContentAsset(
- compiler,
- compilation,
- chunk,
- renderedModules,
- compilation.runtimeTemplate.requestShortener
- ),
- filenameTemplate,
- pathOptions: {
- chunk,
- contentHashType: MODULE_TYPE,
- },
- identifier: `${pluginName}.${chunk.id}`,
- hash: chunk.contentHash[MODULE_TYPE],
- });
- }
- }
- );
- }
+ // We don't need hot update chunks for css
+ // We will use the real asset instead to update
+ if (chunk instanceof HotUpdateChunk) {
+ return;
+ }
- /*
- * For webpack 5 this will be unneeded once the logic uses a RuntimeModule
- * as the content of runtime modules is hashed and added to the chunk hash automatically
- * */
- if (isWebpack4) {
- compilation.mainTemplate.hooks.hashForChunk.tap(
- pluginName,
- (hash, chunk) => {
- const { chunkFilename } = this.options;
-
- if (REGEXP_CHUNKHASH.test(chunkFilename)) {
- hash.update(JSON.stringify(chunk.getChunkMaps(true).hash));
- }
+ const renderedModules = Array.from(
+ this.getChunkModules(chunk, chunkGraph)
+ ).filter((module) => module.type === MODULE_TYPE);
- if (REGEXP_CONTENTHASH.test(chunkFilename)) {
- hash.update(
- JSON.stringify(
- chunk.getChunkMaps(true).contentHash[MODULE_TYPE] || {}
- )
- );
- }
+ const filenameTemplate = chunk.canBeInitial()
+ ? this.options.filename
+ : this.options.chunkFilename;
- if (REGEXP_NAME.test(chunkFilename)) {
- hash.update(JSON.stringify(chunk.getChunkMaps(true).name));
- }
- }
- );
- }
+ if (renderedModules.length > 0) {
+ result.push({
+ render: () =>
+ this.renderContentAsset(
+ compiler,
+ compilation,
+ chunk,
+ renderedModules,
+ compilation.runtimeTemplate.requestShortener,
+ filenameTemplate,
+ {
+ contentHashType: MODULE_TYPE,
+ chunk,
+ }
+ ),
+ filenameTemplate,
+ pathOptions: {
+ chunk,
+ contentHashType: MODULE_TYPE,
+ },
+ identifier: `${pluginName}.${chunk.id}`,
+ hash: chunk.contentHash[MODULE_TYPE],
+ });
+ }
+ });
compilation.hooks.contentHash.tap(pluginName, (chunk) => {
const { outputOptions, chunkGraph } = compilation;
- const modules = isWebpack4
- ? Array.from(this.getChunkModules(chunk, chunkGraph)).filter(
- (module) => module.type === MODULE_TYPE
- )
- : this.sortModules(
- compilation,
- chunk,
- chunkGraph.getChunkModulesIterableBySourceType(
- chunk,
- MODULE_TYPE
- ),
- compilation.runtimeTemplate.requestShortener
- );
+ const modules = this.sortModules(
+ compilation,
+ chunk,
+ chunkGraph.getChunkModulesIterableBySourceType(chunk, MODULE_TYPE),
+ compilation.runtimeTemplate.requestShortener
+ );
if (modules) {
const { hashFunction, hashDigest, hashDigestLength } = outputOptions;
- const createHash = compiler.webpack
- ? compiler.webpack.util.createHash
- : webpack.util.createHash;
+ const { createHash } = compiler.webpack.util;
const hash = createHash(hashFunction);
for (const m of modules) {
@@ -620,498 +483,300 @@ class MiniCssExtractPlugin {
});
const { Template } = webpack;
- const { mainTemplate } = compilation;
-
- if (isWebpack4) {
- mainTemplate.hooks.localVars.tap(pluginName, (source, chunk) => {
- const chunkMap = this.getCssChunkObject(chunk, compilation);
-
- 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')
- ),
- '};',
- ]);
- }
- return source;
- });
+ const { RuntimeGlobals, runtime } = webpack;
- mainTemplate.hooks.requireEnsure.tap(
- pluginName,
- (source, chunk, hash) => {
- const chunkMap = this.getCssChunkObject(chunk, compilation);
+ // eslint-disable-next-line no-shadow
+ const getCssChunkObject = (mainChunk, compilation) => {
+ const obj = {};
+ const { chunkGraph } = compilation;
- 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
- )} + "`,
- chunk: {
- id: '" + chunkId + "',
- hash: `" + ${JSON.stringify(chunkMaps.hash)}[chunkId] + "`,
- hashWithLength(length) {
- const shortChunkHashMap = Object.create(null);
-
- for (const chunkId of Object.keys(chunkMaps.hash)) {
- if (typeof chunkMaps.hash[chunkId] === 'string') {
- shortChunkHashMap[chunkId] = chunkMaps.hash[
- chunkId
- ].substring(0, length);
- }
- }
-
- return `" + ${JSON.stringify(
- shortChunkHashMap
- )}[chunkId] + "`;
- },
- contentHash: {
- [MODULE_TYPE]: `" + ${JSON.stringify(
- chunkMaps.contentHash[MODULE_TYPE]
- )}[chunkId] + "`,
- },
- contentHashWithLength: {
- [MODULE_TYPE]: (length) => {
- const shortContentHashMap = {};
- const contentHash = chunkMaps.contentHash[MODULE_TYPE];
-
- for (const chunkId of Object.keys(contentHash)) {
- if (typeof contentHash[chunkId] === 'string') {
- shortContentHashMap[chunkId] = contentHash[
- chunkId
- ].substring(0, length);
- }
- }
-
- return `" + ${JSON.stringify(
- shortContentHashMap
- )}[chunkId] + "`;
- },
- },
- name: `" + (${JSON.stringify(
- chunkMaps.name
- )}[chunkId]||chunkId) + "`,
- },
- 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");',
- this.runtimeOptions.attributes
- ? Template.asString(
- Object.entries(this.runtimeOptions.attributes).map(
- (entry) => {
- const [key, value] = entry;
-
- return `linkTag.setAttribute(${JSON.stringify(
- key
- )}, ${JSON.stringify(value)});`;
- }
- )
- )
- : '',
- 'linkTag.rel = "stylesheet";',
- this.runtimeOptions.linkType
- ? `linkTag.type = ${JSON.stringify(
- this.runtimeOptions.linkType
- )};`
- : '',
- 'var onLinkComplete = function (event) {',
- Template.indent([
- '// avoid mem leaks.',
- 'linkTag.onerror = linkTag.onload = null;',
- "if (event.type === 'load') {",
- Template.indent(['resolve();']),
- '} else {',
- Template.indent([
- "var errorType = event && (event.type === 'load' ? 'missing' : event.type);",
- 'var realHref = event && event.target && event.target.href || fullhref;',
- 'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + realHref + ")");',
- 'err.code = "CSS_CHUNK_LOAD_FAILED";',
- 'err.type = errorType;',
- 'err.request = realHref;',
- 'delete installedCssChunks[chunkId]',
- 'linkTag.parentNode.removeChild(linkTag)',
- 'reject(err);',
- ]),
- '}',
- ]),
- '};',
- 'linkTag.onerror = linkTag.onload = onLinkComplete;',
- 'linkTag.href = fullhref;',
- crossOriginLoading
- ? Template.asString([
- `if (linkTag.href.indexOf(window.location.origin + '/') !== 0) {`,
- Template.indent(
- `linkTag.crossOrigin = ${JSON.stringify(
- crossOriginLoading
- )};`
- ),
- '}',
- ])
- : '',
- 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([
- 'document.head.appendChild(linkTag);',
- ]),
- ]),
- '}).then(function() {',
- Template.indent(['installedCssChunks[chunkId] = 0;']),
- '}));',
- ]),
- '}',
- ]);
+ for (const chunk of mainChunk.getAllAsyncChunks()) {
+ const modules = chunkGraph.getOrderedChunkModulesIterable(
+ chunk,
+ compareModulesByIdentifier
+ );
+ for (const module of modules) {
+ if (module.type === MODULE_TYPE) {
+ obj[chunk.id] = 1;
+ break;
}
-
- return source;
}
- );
- } else {
- const { RuntimeGlobals, runtime } = webpack;
+ }
- // eslint-disable-next-line no-shadow
- const getCssChunkObject = (mainChunk, compilation) => {
- const obj = {};
- const { chunkGraph } = compilation;
+ return obj;
+ };
- for (const chunk of mainChunk.getAllAsyncChunks()) {
- const modules = chunkGraph.getOrderedChunkModulesIterable(
- chunk,
- compareModulesByIdentifier
- );
- for (const module of modules) {
- if (module.type === MODULE_TYPE) {
- obj[chunk.id] = 1;
- break;
- }
- }
- }
+ const { RuntimeModule } = webpack;
- return obj;
- };
+ class CssLoadingRuntimeModule extends RuntimeModule {
+ constructor(runtimeRequirements, runtimeOptions) {
+ super('css loading', 10);
- const { RuntimeModule } = webpack;
+ this.runtimeRequirements = runtimeRequirements;
+ this.runtimeOptions = runtimeOptions;
+ }
- class CssLoadingRuntimeModule extends RuntimeModule {
- constructor(runtimeRequirements, runtimeOptions) {
- super('css loading', 10);
+ generate() {
+ const { chunk, runtimeRequirements } = this;
+ const {
+ runtimeTemplate,
+ outputOptions: { crossOriginLoading },
+ } = this.compilation;
+ const chunkMap = getCssChunkObject(chunk, this.compilation);
+
+ const withLoading =
+ runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers) &&
+ Object.keys(chunkMap).length > 0;
+ const withHmr = runtimeRequirements.has(
+ RuntimeGlobals.hmrDownloadUpdateHandlers
+ );
- this.runtimeRequirements = runtimeRequirements;
- this.runtimeOptions = runtimeOptions;
+ if (!withLoading && !withHmr) {
+ return null;
}
- generate() {
- const { chunk, runtimeRequirements } = this;
- const {
- runtimeTemplate,
- outputOptions: { crossOriginLoading },
- } = this.compilation;
- const chunkMap = getCssChunkObject(chunk, this.compilation);
-
- const withLoading =
- runtimeRequirements.has(RuntimeGlobals.ensureChunkHandlers) &&
- Object.keys(chunkMap).length > 0;
- const withHmr = runtimeRequirements.has(
- RuntimeGlobals.hmrDownloadUpdateHandlers
- );
-
- if (!withLoading && !withHmr) {
- return null;
- }
-
- return Template.asString([
- `var createStylesheet = ${runtimeTemplate.basicFunction(
- 'chunkId, fullhref, resolve, reject',
- [
- 'var linkTag = document.createElement("link");',
- this.runtimeOptions.attributes
- ? Template.asString(
- Object.entries(this.runtimeOptions.attributes).map(
- (entry) => {
- const [key, value] = entry;
-
- return `linkTag.setAttribute(${JSON.stringify(
- key
- )}, ${JSON.stringify(value)});`;
- }
- )
+ return Template.asString([
+ `var createStylesheet = ${runtimeTemplate.basicFunction(
+ 'chunkId, fullhref, resolve, reject',
+ [
+ 'var linkTag = document.createElement("link");',
+ this.runtimeOptions.attributes
+ ? Template.asString(
+ Object.entries(this.runtimeOptions.attributes).map(
+ (entry) => {
+ const [key, value] = entry;
+
+ return `linkTag.setAttribute(${JSON.stringify(
+ key
+ )}, ${JSON.stringify(value)});`;
+ }
)
- : '',
- 'linkTag.rel = "stylesheet";',
- this.runtimeOptions.linkType
- ? `linkTag.type = ${JSON.stringify(
- this.runtimeOptions.linkType
- )};`
- : '',
- `var onLinkComplete = ${runtimeTemplate.basicFunction(
- 'event',
+ )
+ : '',
+ 'linkTag.rel = "stylesheet";',
+ this.runtimeOptions.linkType
+ ? `linkTag.type = ${JSON.stringify(
+ this.runtimeOptions.linkType
+ )};`
+ : '',
+ `var onLinkComplete = ${runtimeTemplate.basicFunction('event', [
+ '// avoid mem leaks.',
+ 'linkTag.onerror = linkTag.onload = null;',
+ "if (event.type === 'load') {",
+ Template.indent(['resolve();']),
+ '} else {',
+ Template.indent([
+ "var errorType = event && (event.type === 'load' ? 'missing' : event.type);",
+ 'var realHref = event && event.target && event.target.href || fullhref;',
+ 'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + realHref + ")");',
+ 'err.code = "CSS_CHUNK_LOAD_FAILED";',
+ 'err.type = errorType;',
+ 'err.request = realHref;',
+ 'linkTag.parentNode.removeChild(linkTag)',
+ 'reject(err);',
+ ]),
+ '}',
+ ])}`,
+ 'linkTag.onerror = linkTag.onload = onLinkComplete;',
+ 'linkTag.href = fullhref;',
+ crossOriginLoading
+ ? Template.asString([
+ `if (linkTag.href.indexOf(window.location.origin + '/') !== 0) {`,
+ Template.indent(
+ `linkTag.crossOrigin = ${JSON.stringify(
+ crossOriginLoading
+ )};`
+ ),
+ '}',
+ ])
+ : '',
+ 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(['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, resolve, reject);',
+ ]
+ )});`
+ )}`,
+ withLoading
+ ? Template.asString([
+ '// object to store loaded CSS chunks',
+ 'var installedCssChunks = {',
+ Template.indent(
+ chunk.ids
+ .map((id) => `${JSON.stringify(id)}: 0`)
+ .join(',\n')
+ ),
+ '};',
+ '',
+ `${
+ RuntimeGlobals.ensureChunkHandlers
+ }.miniCss = ${runtimeTemplate.basicFunction(
+ 'chunkId, promises',
[
- '// avoid mem leaks.',
- 'linkTag.onerror = linkTag.onload = null;',
- "if (event.type === 'load') {",
- Template.indent(['resolve();']),
- '} else {',
+ `var cssChunks = ${JSON.stringify(chunkMap)};`,
+ 'if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);',
+ 'else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {',
Template.indent([
- "var errorType = event && (event.type === 'load' ? 'missing' : event.type);",
- 'var realHref = event && event.target && event.target.href || fullhref;',
- 'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + realHref + ")");',
- 'err.code = "CSS_CHUNK_LOAD_FAILED";',
- 'err.type = errorType;',
- 'err.request = realHref;',
- 'linkTag.parentNode.removeChild(linkTag)',
- 'reject(err);',
+ `promises.push(installedCssChunks[chunkId] = loadStylesheet(chunkId).then(${runtimeTemplate.basicFunction(
+ '',
+ 'installedCssChunks[chunkId] = 0;'
+ )}, ${runtimeTemplate.basicFunction('e', [
+ 'delete installedCssChunks[chunkId];',
+ 'throw e;',
+ ])}));`,
]),
'}',
]
- )}`,
- 'linkTag.onerror = linkTag.onload = onLinkComplete;',
- 'linkTag.href = fullhref;',
- crossOriginLoading
- ? Template.asString([
- `if (linkTag.href.indexOf(window.location.origin + '/') !== 0) {`,
- Template.indent(
- `linkTag.crossOrigin = ${JSON.stringify(
- crossOriginLoading
- )};`
- ),
- '}',
- ])
- : '',
- 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([
- '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, resolve, reject);',
- ]
- )});`
- )}`,
- withLoading
- ? Template.asString([
- '// object to store loaded CSS chunks',
- 'var installedCssChunks = {',
- Template.indent(
- 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]) {',
+ )};`,
+ ])
+ : '// 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([
- `promises.push(installedCssChunks[chunkId] = loadStylesheet(chunkId).then(${runtimeTemplate.basicFunction(
- '',
- 'installedCssChunks[chunkId] = 0;'
- )}, ${runtimeTemplate.basicFunction('e', [
- 'delete installedCssChunks[chunkId];',
- 'throw e;',
- ])}));`,
+ 'var oldTag = oldTags[i];',
+ 'if(oldTag.parentNode) oldTag.parentNode.removeChild(oldTag);',
]),
'}',
- ]
- )};`,
- ])
- : '// 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, ${runtimeTemplate.basicFunction(
- '',
- [
- 'tag.as = "style";',
- 'tag.rel = "preload";',
- 'resolve();',
- ]
- )}, reject);`,
- 'oldTags.push(oldTag);',
- 'newTags.push(tag);',
- ]
- )}));`,
- ]
- )});`,
- ]
- )}`,
- ])
- : '// no hmr',
- ]);
- }
+ '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, ${runtimeTemplate.basicFunction(
+ '',
+ [
+ 'tag.as = "style";',
+ 'tag.rel = "preload";',
+ 'resolve();',
+ ]
+ )}, reject);`,
+ 'oldTags.push(oldTag);',
+ 'newTags.push(tag);',
+ ]
+ )}));`,
+ ]
+ )});`,
+ ]
+ )}`,
+ ])
+ : '// no hmr',
+ ]);
}
+ }
- const enabledChunks = new WeakSet();
-
- const handler = (chunk, set) => {
- if (enabledChunks.has(chunk)) {
- return;
- }
+ const enabledChunks = new WeakSet();
- enabledChunks.add(chunk);
+ const handler = (chunk, set) => {
+ if (enabledChunks.has(chunk)) {
+ return;
+ }
- if (
- typeof this.options.chunkFilename === 'string' &&
- /\[(full)?hash(:\d+)?\]/.test(this.options.chunkFilename)
- ) {
- set.add(RuntimeGlobals.getFullHash);
- }
+ enabledChunks.add(chunk);
- set.add(RuntimeGlobals.publicPath);
+ if (
+ typeof this.options.chunkFilename === 'string' &&
+ /\[(full)?hash(:\d+)?\]/.test(this.options.chunkFilename)
+ ) {
+ set.add(RuntimeGlobals.getFullHash);
+ }
- compilation.addRuntimeModule(
- chunk,
- new runtime.GetChunkFilenameRuntimeModule(
- MODULE_TYPE,
- 'mini-css',
- `${RuntimeGlobals.require}.miniCssF`,
- (referencedChunk) => {
- if (!referencedChunk.contentHash[MODULE_TYPE]) {
- return false;
- }
+ set.add(RuntimeGlobals.publicPath);
- return referencedChunk.canBeInitial()
- ? this.options.filename
- : this.options.chunkFilename;
- },
- true
- )
- );
+ compilation.addRuntimeModule(
+ chunk,
+ new runtime.GetChunkFilenameRuntimeModule(
+ MODULE_TYPE,
+ 'mini-css',
+ `${RuntimeGlobals.require}.miniCssF`,
+ (referencedChunk) => {
+ if (!referencedChunk.contentHash[MODULE_TYPE]) {
+ return false;
+ }
- compilation.addRuntimeModule(
- chunk,
- new CssLoadingRuntimeModule(set, this.runtimeOptions)
- );
- };
+ return referencedChunk.canBeInitial()
+ ? this.options.filename
+ : this.options.chunkFilename;
+ },
+ true
+ )
+ );
- compilation.hooks.runtimeRequirementInTree
- .for(RuntimeGlobals.ensureChunkHandlers)
- .tap(pluginName, handler);
- compilation.hooks.runtimeRequirementInTree
- .for(RuntimeGlobals.hmrDownloadUpdateHandlers)
- .tap(pluginName, handler);
- }
+ compilation.addRuntimeModule(
+ chunk,
+ new CssLoadingRuntimeModule(set, this.runtimeOptions)
+ );
+ };
+
+ compilation.hooks.runtimeRequirementInTree
+ .for(RuntimeGlobals.ensureChunkHandlers)
+ .tap(pluginName, handler);
+ compilation.hooks.runtimeRequirementInTree
+ .for(RuntimeGlobals.hmrDownloadUpdateHandlers)
+ .tap(pluginName, handler);
});
}
@@ -1124,22 +789,6 @@ class MiniCssExtractPlugin {
: chunk.modulesIterable;
}
- getCssChunkObject(mainChunk, compilation) {
- const obj = {};
- const { chunkGraph } = compilation;
-
- for (const chunk of mainChunk.getAllAsyncChunks()) {
- for (const module of this.getChunkModules(chunk, chunkGraph)) {
- if (module.type === MODULE_TYPE) {
- obj[chunk.id] = 1;
- break;
- }
- }
- }
-
- return obj;
- }
-
sortModules(compilation, chunk, modules, requestShortener) {
let usedModules = this._sortedModulesCache.get(chunk);
@@ -1148,143 +797,128 @@ class MiniCssExtractPlugin {
}
const modulesList = [...modules];
-
- const [chunkGroup] = chunk.groupsIterable;
const moduleIndexFunctionName =
typeof compilation.chunkGraph !== 'undefined'
? 'getModulePostOrderIndex'
: 'getModuleIndex2';
-
- if (typeof chunkGroup[moduleIndexFunctionName] === 'function') {
- // Store dependencies for modules
- const moduleDependencies = new Map(
- modulesList.map((m) => [m, new Set()])
- );
- const moduleDependenciesReasons = new Map(
- modulesList.map((m) => [m, new Map()])
- );
-
- // 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 = modulesList
- .map((m) => {
- return {
- module: m,
- index: cg[moduleIndexFunctionName](m),
- };
- })
- // 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]);
- const reasons = moduleDependenciesReasons.get(sortedModules[i]);
-
- for (let j = i + 1; j < sortedModules.length; j++) {
- const module = sortedModules[j];
- set.add(module);
- const reason = reasons.get(module) || new Set();
- reason.add(cg);
- reasons.set(module, reason);
- }
+ // Store dependencies for modules
+ const moduleDependencies = new Map(modulesList.map((m) => [m, new Set()]));
+ const moduleDependenciesReasons = new Map(
+ modulesList.map((m) => [m, new Map()])
+ );
+ // 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 = modulesList
+ .map((m) => {
+ return {
+ module: m,
+ index: cg[moduleIndexFunctionName](m),
+ };
+ })
+ // 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]);
+ const reasons = moduleDependenciesReasons.get(sortedModules[i]);
+
+ for (let j = i + 1; j < sortedModules.length; j++) {
+ const module = sortedModules[j];
+ set.add(module);
+ const reason = reasons.get(module) || new Set();
+ reason.add(cg);
+ reasons.set(module, reason);
}
+ }
- return sortedModules;
- });
-
- // set with already included modules in correct order
- usedModules = new Set();
+ return sortedModules;
+ });
- const unusedModulesFilter = (m) => !usedModules.has(m);
+ // set with already included modules in correct order
+ usedModules = new Set();
- while (usedModules.size < modulesList.length) {
- let success = false;
- let bestMatch;
- let bestMatchDeps;
+ const unusedModulesFilter = (m) => !usedModules.has(m);
- // 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 (usedModules.size < modulesList.length) {
+ let success = false;
+ let bestMatch;
+ let bestMatchDeps;
- // 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);
-
- // store best match for fallback behavior
- if (!bestMatchDeps || bestMatchDeps.length > failedDeps.length) {
- bestMatch = list;
- bestMatchDeps = failedDeps;
- }
-
- if (failedDeps.length === 0) {
- // use this module and remove it from list
- usedModules.add(list.pop());
- success = true;
- break;
- }
- }
+ // 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();
}
- if (!success) {
- // no module found => there is a conflict
- // use list with fewest failed deps
- // and emit a warning
- const fallbackModule = bestMatch.pop();
+ // 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);
+
+ // store best match for fallback behavior
+ if (!bestMatchDeps || bestMatchDeps.length > failedDeps.length) {
+ bestMatch = list;
+ bestMatchDeps = failedDeps;
+ }
- if (!this.options.ignoreOrder) {
- const reasons = moduleDependenciesReasons.get(fallbackModule);
- compilation.warnings.push(
- new Error(
- [
- `chunk ${chunk.name || chunk.id} [${pluginName}]`,
- 'Conflicting order. Following module has been added:',
- ` * ${fallbackModule.readableIdentifier(requestShortener)}`,
- 'despite it was not able to fulfill desired ordering with these modules:',
- ...bestMatchDeps.map((m) => {
- const goodReasonsMap = moduleDependenciesReasons.get(m);
- const goodReasons =
- goodReasonsMap && goodReasonsMap.get(fallbackModule);
- const failedChunkGroups = Array.from(
- reasons.get(m),
- (cg) => cg.name
- ).join(', ');
- const goodChunkGroups =
- goodReasons &&
- Array.from(goodReasons, (cg) => cg.name).join(', ');
- return [
- ` * ${m.readableIdentifier(requestShortener)}`,
- ` - couldn't fulfill desired order of chunk group(s) ${failedChunkGroups}`,
- goodChunkGroups &&
- ` - while fulfilling desired order of chunk group(s) ${goodChunkGroups}`,
- ]
- .filter(Boolean)
- .join('\n');
- }),
- ].join('\n')
- )
- );
+ if (failedDeps.length === 0) {
+ // use this module and remove it from list
+ usedModules.add(list.pop());
+ success = true;
+ break;
}
+ }
+ }
- usedModules.add(fallbackModule);
+ if (!success) {
+ // no module found => there is a conflict
+ // use list with fewest failed deps
+ // and emit a warning
+ const fallbackModule = bestMatch.pop();
+
+ if (!this.options.ignoreOrder) {
+ const reasons = moduleDependenciesReasons.get(fallbackModule);
+ compilation.warnings.push(
+ new Error(
+ [
+ `chunk ${chunk.name || chunk.id} [${pluginName}]`,
+ 'Conflicting order. Following module has been added:',
+ ` * ${fallbackModule.readableIdentifier(requestShortener)}`,
+ 'despite it was not able to fulfill desired ordering with these modules:',
+ ...bestMatchDeps.map((m) => {
+ const goodReasonsMap = moduleDependenciesReasons.get(m);
+ const goodReasons =
+ goodReasonsMap && goodReasonsMap.get(fallbackModule);
+ const failedChunkGroups = Array.from(
+ reasons.get(m),
+ (cg) => cg.name
+ ).join(', ');
+ const goodChunkGroups =
+ goodReasons &&
+ Array.from(goodReasons, (cg) => cg.name).join(', ');
+ return [
+ ` * ${m.readableIdentifier(requestShortener)}`,
+ ` - couldn't fulfill desired order of chunk group(s) ${failedChunkGroups}`,
+ goodChunkGroups &&
+ ` - while fulfilling desired order of chunk group(s) ${goodChunkGroups}`,
+ ]
+ .filter(Boolean)
+ .join('\n');
+ }),
+ ].join('\n')
+ )
+ );
}
+
+ usedModules.add(fallbackModule);
}
- } else {
- // fallback for older webpack versions
- // (to avoid a breaking change)
- // TODO remove this in next major version
- // and increase minimum webpack version to 4.12.0
- modulesList.sort((a, b) => a.index2 - b.index2);
- usedModules = modulesList;
}
this._sortedModulesCache.set(chunk, usedModules);
@@ -1292,7 +926,15 @@ class MiniCssExtractPlugin {
return usedModules;
}
- renderContentAsset(compiler, compilation, chunk, modules, requestShortener) {
+ renderContentAsset(
+ compiler,
+ compilation,
+ chunk,
+ modules,
+ requestShortener,
+ filenameTemplate,
+ pathData
+ ) {
const usedModules = this.sortModules(
compilation,
chunk,
@@ -1300,12 +942,8 @@ class MiniCssExtractPlugin {
requestShortener
);
- // TODO remove after drop webpack v4
- const { ConcatSource, SourceMapSource, RawSource } = compiler.webpack
- ? compiler.webpack.sources
- : // eslint-disable-next-line global-require
- require('webpack-sources');
-
+ const { ConcatSource, SourceMapSource, RawSource } =
+ compiler.webpack.sources;
const source = new ConcatSource();
const externalsSource = new ConcatSource();
@@ -1329,6 +967,15 @@ class MiniCssExtractPlugin {
source.add(`@media ${m.media} {\n`);
}
+ const { path: filename } = compilation.getPathWithInfo(
+ filenameTemplate,
+ pathData
+ );
+
+ const undoPath = getUndoPath(filename, compiler.outputPath, false);
+
+ content = content.replace(new RegExp(AUTO_PUBLIC_PATH, 'g'), undoPath);
+
if (m.sourceMap) {
source.add(
new SourceMapSource(
diff --git a/src/loader.js b/src/loader.js
index c6a5cecf..9400366f 100644
--- a/src/loader.js
+++ b/src/loader.js
@@ -3,7 +3,7 @@ import path from 'path';
import loaderUtils from 'loader-utils';
import { validate } from 'schema-utils';
-import { findModuleById, evalModuleCode } from './utils';
+import { findModuleById, evalModuleCode, AUTO_PUBLIC_PATH } from './utils';
import schema from './loader-options.json';
import MiniCssExtractPlugin, { pluginName, pluginSymbol } from './index';
@@ -50,9 +50,7 @@ export function pitch(request) {
return;
}
- // TODO simplify after drop webpack v4
- // eslint-disable-next-line global-require
- const webpack = this._compiler.webpack || require('webpack');
+ const { webpack } = this._compiler;
const handleExports = (originalExports, compilation, assets, assetsInfo) => {
let locals;
@@ -176,18 +174,18 @@ export function pitch(request) {
return callback(null, resultSource);
};
- const publicPath =
- typeof options.publicPath === 'string'
- ? options.publicPath === 'auto'
- ? ''
- : options.publicPath === '' || options.publicPath.endsWith('/')
- ? options.publicPath
- : `${options.publicPath}/`
- : typeof options.publicPath === 'function'
- ? options.publicPath(this.resourcePath, this.rootContext)
- : this._compilation.outputOptions.publicPath === 'auto'
- ? ''
- : this._compilation.outputOptions.publicPath;
+ let { publicPath } = this._compilation.outputOptions;
+
+ if (typeof options.publicPath === 'string') {
+ // eslint-disable-next-line prefer-destructuring
+ publicPath = options.publicPath;
+ } else if (typeof options.publicPath === 'function') {
+ publicPath = options.publicPath(this.resourcePath, this.rootContext);
+ }
+
+ if (publicPath === 'auto') {
+ publicPath = AUTO_PUBLIC_PATH;
+ }
if (optionsFromPlugin.experimentalUseImportModule) {
if (!this.importModule) {
@@ -246,56 +244,38 @@ export function pitch(request) {
};
const { NodeTemplatePlugin } = webpack.node;
- const NodeTargetPlugin = webpack.node.NodeTargetPlugin
- ? webpack.node.NodeTargetPlugin
- : // eslint-disable-next-line global-require
- require('webpack/lib/node/NodeTargetPlugin');
+ const { NodeTargetPlugin } = webpack.node;
new NodeTemplatePlugin(outputOptions).apply(childCompiler);
new NodeTargetPlugin().apply(childCompiler);
const { EntryOptionPlugin } = webpack;
- if (EntryOptionPlugin) {
- const {
- library: { EnableLibraryPlugin },
- } = webpack;
+ const {
+ library: { EnableLibraryPlugin },
+ } = webpack;
- new EnableLibraryPlugin('commonjs2').apply(childCompiler);
+ new EnableLibraryPlugin('commonjs2').apply(childCompiler);
- EntryOptionPlugin.applyEntryOption(childCompiler, this.context, {
- child: {
- library: {
- type: 'commonjs2',
- },
- import: [`!!${request}`],
+ EntryOptionPlugin.applyEntryOption(childCompiler, this.context, {
+ child: {
+ library: {
+ type: 'commonjs2',
},
- });
- } else {
- const { LibraryTemplatePlugin, SingleEntryPlugin } = webpack;
-
- new LibraryTemplatePlugin(null, 'commonjs2').apply(childCompiler);
- new SingleEntryPlugin(this.context, `!!${request}`, pluginName).apply(
- childCompiler
- );
- }
-
+ import: [`!!${request}`],
+ },
+ });
const { LimitChunkCountPlugin } = webpack.optimize;
new LimitChunkCountPlugin({ maxChunks: 1 }).apply(childCompiler);
- const NormalModule = webpack.NormalModule
- ? webpack.NormalModule
- : // eslint-disable-next-line global-require
- require('webpack/lib/NormalModule');
+ const { NormalModule } = webpack;
childCompiler.hooks.thisCompilation.tap(
`${pluginName} loader`,
(compilation) => {
const normalModuleHook =
- typeof NormalModule.getCompilationHooks !== 'undefined'
- ? NormalModule.getCompilationHooks(compilation).loader
- : compilation.hooks.normalModuleLoader;
+ NormalModule.getCompilationHooks(compilation).loader;
normalModuleHook.tap(`${pluginName} loader`, (loaderContext, module) => {
if (module.request === request) {
@@ -314,12 +294,8 @@ export function pitch(request) {
let source;
- const isWebpack4 = childCompiler.webpack
- ? false
- : typeof childCompiler.resolvers !== 'undefined';
-
- if (isWebpack4) {
- childCompiler.hooks.afterCompile.tap(pluginName, (compilation) => {
+ childCompiler.hooks.compilation.tap(pluginName, (compilation) => {
+ compilation.hooks.processAssets.tap(pluginName, () => {
source =
compilation.assets[childFilename] &&
compilation.assets[childFilename].source();
@@ -327,28 +303,11 @@ export function pitch(request) {
// Remove all chunk assets
compilation.chunks.forEach((chunk) => {
chunk.files.forEach((file) => {
- delete compilation.assets[file]; // eslint-disable-line no-param-reassign
- });
- });
- });
- } else {
- childCompiler.hooks.compilation.tap(pluginName, (compilation) => {
- compilation.hooks.processAssets.tap(pluginName, () => {
- source =
- compilation.assets[childFilename] &&
- compilation.assets[childFilename].source();
-
- // console.log(source);
-
- // Remove all chunk assets
- compilation.chunks.forEach((chunk) => {
- chunk.files.forEach((file) => {
- compilation.deleteAsset(file);
- });
+ compilation.deleteAsset(file);
});
});
});
- }
+ });
childCompiler.runAsChild((error, entries, compilation) => {
const assets = Object.create(null);
diff --git a/src/utils.js b/src/utils.js
index 772cd22d..38f983ee 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1,6 +1,7 @@
import NativeModule from 'module';
const MODULE_TYPE = 'css/mini-extract';
+const AUTO_PUBLIC_PATH = '__MINI_CSS_EXTRACT_PLUGIN_PUBLIC_PATH__';
function findModuleById(compilation, id) {
const { modules, chunkGraph } = compilation;
@@ -51,6 +52,7 @@ function compareModulesByIdentifier(a, b) {
export {
MODULE_TYPE,
+ AUTO_PUBLIC_PATH,
findModuleById,
evalModuleCode,
compareModulesByIdentifier,
diff --git a/test/TestCache.test.js b/test/TestCache.test.js
index c1409b94..7ebb2cd2 100644
--- a/test/TestCache.test.js
+++ b/test/TestCache.test.js
@@ -13,541 +13,521 @@ describe('TestCache', () => {
});
it('should work without cache', async () => {
- if (webpack.version[0] !== '4') {
- const casesDirectory = path.resolve(__dirname, 'cases');
- const directoryForCase = path.resolve(casesDirectory, 'asset-modules');
- // eslint-disable-next-line import/no-dynamic-require, global-require
- const webpackConfig = require(path.resolve(
- directoryForCase,
- 'webpack.config.js'
- ));
- const outputPath = path.resolve(__dirname, 'js/cache-false');
-
- await del([outputPath]);
-
- const compiler1 = webpack({
- ...webpackConfig,
- mode: 'development',
- context: directoryForCase,
- cache: false,
- output: {
- path: outputPath,
- },
- });
-
- await new Promise((resolve, reject) => {
- compiler1.run((error, stats) => {
- if (error) {
- reject(error);
-
- return;
- }
-
- compiler1.close(() => {
- expect(Object.keys(stats.compilation.assets).sort())
- .toMatchInlineSnapshot(`
+ const casesDirectory = path.resolve(__dirname, 'cases');
+ const directoryForCase = path.resolve(casesDirectory, 'asset-modules');
+ // eslint-disable-next-line import/no-dynamic-require, global-require
+ const webpackConfig = require(path.resolve(
+ directoryForCase,
+ 'webpack.config.js'
+ ));
+ const outputPath = path.resolve(__dirname, 'js/cache-false');
+
+ await del([outputPath]);
+
+ const compiler1 = webpack({
+ ...webpackConfig,
+ mode: 'development',
+ context: directoryForCase,
+ cache: false,
+ output: {
+ path: outputPath,
+ },
+ });
+
+ await new Promise((resolve, reject) => {
+ compiler1.run((error, stats) => {
+ if (error) {
+ reject(error);
+
+ return;
+ }
+
+ compiler1.close(() => {
+ expect(Object.keys(stats.compilation.assets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
"static/react.svg",
]
`);
- expect(Array.from(stats.compilation.emittedAssets).sort())
- .toMatchInlineSnapshot(`
+ expect(Array.from(stats.compilation.emittedAssets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
"static/react.svg",
]
`);
- expect(stats.compilation.warnings).toHaveLength(0);
- expect(stats.compilation.errors).toHaveLength(0);
+ expect(stats.compilation.warnings).toHaveLength(0);
+ expect(stats.compilation.errors).toHaveLength(0);
- resolve();
- });
+ resolve();
});
});
-
- const compiler2 = webpack({
- ...webpackConfig,
- mode: 'development',
- context: directoryForCase,
- cache: false,
- output: {
- path: outputPath,
- },
- });
-
- await new Promise((resolve, reject) => {
- compiler2.run((error, stats) => {
- if (error) {
- reject(error);
-
- return;
- }
-
- compiler2.close(() => {
- expect(Object.keys(stats.compilation.assets).sort())
- .toMatchInlineSnapshot(`
+ });
+
+ const compiler2 = webpack({
+ ...webpackConfig,
+ mode: 'development',
+ context: directoryForCase,
+ cache: false,
+ output: {
+ path: outputPath,
+ },
+ });
+
+ await new Promise((resolve, reject) => {
+ compiler2.run((error, stats) => {
+ if (error) {
+ reject(error);
+
+ return;
+ }
+
+ compiler2.close(() => {
+ expect(Object.keys(stats.compilation.assets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
"static/react.svg",
]
`);
- expect(
- Array.from(stats.compilation.emittedAssets).sort()
- ).toMatchInlineSnapshot(`Array []`);
- expect(stats.compilation.warnings).toHaveLength(0);
- expect(stats.compilation.errors).toHaveLength(0);
-
- resolve();
- });
+ expect(
+ Array.from(stats.compilation.emittedAssets).sort()
+ ).toMatchInlineSnapshot(`Array []`);
+ expect(stats.compilation.warnings).toHaveLength(0);
+ expect(stats.compilation.errors).toHaveLength(0);
+
+ resolve();
});
});
- } else {
- expect(true).toBe(true);
- }
+ });
});
it('should work with the "memory" cache', async () => {
- if (webpack.version[0] !== '4') {
- const casesDirectory = path.resolve(__dirname, 'cases');
- const directoryForCase = path.resolve(casesDirectory, 'asset-modules');
- // eslint-disable-next-line import/no-dynamic-require, global-require
- const webpackConfig = require(path.resolve(
- directoryForCase,
- 'webpack.config.js'
- ));
- const outputPath = path.resolve(__dirname, 'js/cache-memory');
-
- await del([outputPath]);
-
- const compiler1 = webpack({
- ...webpackConfig,
- mode: 'development',
- context: directoryForCase,
- cache: {
- type: 'memory',
- },
- output: {
- path: outputPath,
- },
- });
-
- await new Promise((resolve, reject) => {
- compiler1.run((error, stats) => {
- if (error) {
- reject(error);
-
- return;
- }
-
- compiler1.close(() => {
- expect(Object.keys(stats.compilation.assets).sort())
- .toMatchInlineSnapshot(`
+ const casesDirectory = path.resolve(__dirname, 'cases');
+ const directoryForCase = path.resolve(casesDirectory, 'asset-modules');
+ // eslint-disable-next-line import/no-dynamic-require, global-require
+ const webpackConfig = require(path.resolve(
+ directoryForCase,
+ 'webpack.config.js'
+ ));
+ const outputPath = path.resolve(__dirname, 'js/cache-memory');
+
+ await del([outputPath]);
+
+ const compiler1 = webpack({
+ ...webpackConfig,
+ mode: 'development',
+ context: directoryForCase,
+ cache: {
+ type: 'memory',
+ },
+ output: {
+ path: outputPath,
+ },
+ });
+
+ await new Promise((resolve, reject) => {
+ compiler1.run((error, stats) => {
+ if (error) {
+ reject(error);
+
+ return;
+ }
+
+ compiler1.close(() => {
+ expect(Object.keys(stats.compilation.assets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
"static/react.svg",
]
`);
- expect(Array.from(stats.compilation.emittedAssets).sort())
- .toMatchInlineSnapshot(`
+ expect(Array.from(stats.compilation.emittedAssets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
"static/react.svg",
]
`);
- expect(stats.compilation.warnings).toHaveLength(0);
- expect(stats.compilation.errors).toHaveLength(0);
+ expect(stats.compilation.warnings).toHaveLength(0);
+ expect(stats.compilation.errors).toHaveLength(0);
- resolve();
- });
+ resolve();
});
});
-
- const compiler2 = webpack({
- ...webpackConfig,
- mode: 'development',
- context: directoryForCase,
- cache: {
- type: 'memory',
- },
- output: {
- path: outputPath,
- },
- });
-
- await new Promise((resolve, reject) => {
- compiler2.run((error, stats) => {
- if (error) {
- reject(error);
-
- return;
- }
-
- compiler2.close(() => {
- expect(Object.keys(stats.compilation.assets).sort())
- .toMatchInlineSnapshot(`
+ });
+
+ const compiler2 = webpack({
+ ...webpackConfig,
+ mode: 'development',
+ context: directoryForCase,
+ cache: {
+ type: 'memory',
+ },
+ output: {
+ path: outputPath,
+ },
+ });
+
+ await new Promise((resolve, reject) => {
+ compiler2.run((error, stats) => {
+ if (error) {
+ reject(error);
+
+ return;
+ }
+
+ compiler2.close(() => {
+ expect(Object.keys(stats.compilation.assets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
"static/react.svg",
]
`);
- expect(
- Array.from(stats.compilation.emittedAssets).sort()
- ).toMatchInlineSnapshot(`Array []`);
- expect(stats.compilation.warnings).toHaveLength(0);
- expect(stats.compilation.errors).toHaveLength(0);
-
- resolve();
- });
+ expect(
+ Array.from(stats.compilation.emittedAssets).sort()
+ ).toMatchInlineSnapshot(`Array []`);
+ expect(stats.compilation.warnings).toHaveLength(0);
+ expect(stats.compilation.errors).toHaveLength(0);
+
+ resolve();
});
});
- } else {
- expect(true).toBe(true);
- }
+ });
});
it('should work with the "filesystem" cache', async () => {
- if (webpack.version[0] !== '4') {
- const casesDirectory = path.resolve(__dirname, 'cases');
- const directoryForCase = path.resolve(casesDirectory, 'simple');
- // eslint-disable-next-line import/no-dynamic-require, global-require
- const webpackConfig = require(path.resolve(
- directoryForCase,
- 'webpack.config.js'
- ));
- const outputPath = path.resolve(__dirname, 'js/cache-filesystem');
- const fileSystemCacheDirectory = path.resolve(
- __dirname,
- './js/.cache/type-filesystem'
- );
-
- await del([outputPath, fileSystemCacheDirectory]);
-
- const compiler1 = webpack({
- ...webpackConfig,
- mode: 'development',
- context: directoryForCase,
- cache: {
- type: 'filesystem',
- cacheDirectory: fileSystemCacheDirectory,
- idleTimeout: 0,
- idleTimeoutForInitialStore: 0,
- },
- output: {
- path: outputPath,
- },
- });
-
- await new Promise((resolve, reject) => {
- compiler1.run((error, stats) => {
- if (error) {
- reject(error);
-
- return;
- }
-
- compiler1.close(() => {
- expect(Object.keys(stats.compilation.assets).sort())
- .toMatchInlineSnapshot(`
+ const casesDirectory = path.resolve(__dirname, 'cases');
+ const directoryForCase = path.resolve(casesDirectory, 'simple');
+ // eslint-disable-next-line import/no-dynamic-require, global-require
+ const webpackConfig = require(path.resolve(
+ directoryForCase,
+ 'webpack.config.js'
+ ));
+ const outputPath = path.resolve(__dirname, 'js/cache-filesystem');
+ const fileSystemCacheDirectory = path.resolve(
+ __dirname,
+ './js/.cache/type-filesystem'
+ );
+
+ await del([outputPath, fileSystemCacheDirectory]);
+
+ const compiler1 = webpack({
+ ...webpackConfig,
+ mode: 'development',
+ context: directoryForCase,
+ cache: {
+ type: 'filesystem',
+ cacheDirectory: fileSystemCacheDirectory,
+ idleTimeout: 0,
+ idleTimeoutForInitialStore: 0,
+ },
+ output: {
+ path: outputPath,
+ },
+ });
+
+ await new Promise((resolve, reject) => {
+ compiler1.run((error, stats) => {
+ if (error) {
+ reject(error);
+
+ return;
+ }
+
+ compiler1.close(() => {
+ expect(Object.keys(stats.compilation.assets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
]
`);
- expect(Array.from(stats.compilation.emittedAssets).sort())
- .toMatchInlineSnapshot(`
+ expect(Array.from(stats.compilation.emittedAssets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
]
`);
- expect(stats.compilation.warnings).toHaveLength(0);
- expect(stats.compilation.errors).toHaveLength(0);
+ expect(stats.compilation.warnings).toHaveLength(0);
+ expect(stats.compilation.errors).toHaveLength(0);
- resolve();
- });
+ resolve();
});
});
-
- const compiler2 = webpack({
- ...webpackConfig,
- mode: 'development',
- context: directoryForCase,
- cache: {
- type: 'filesystem',
- cacheDirectory: fileSystemCacheDirectory,
- idleTimeout: 0,
- idleTimeoutForInitialStore: 0,
- },
- output: {
- path: outputPath,
- },
- });
-
- await new Promise((resolve, reject) => {
- compiler2.run((error, stats) => {
- if (error) {
- reject(error);
-
- return;
- }
-
- compiler2.close(() => {
- expect(Object.keys(stats.compilation.assets).sort())
- .toMatchInlineSnapshot(`
+ });
+
+ const compiler2 = webpack({
+ ...webpackConfig,
+ mode: 'development',
+ context: directoryForCase,
+ cache: {
+ type: 'filesystem',
+ cacheDirectory: fileSystemCacheDirectory,
+ idleTimeout: 0,
+ idleTimeoutForInitialStore: 0,
+ },
+ output: {
+ path: outputPath,
+ },
+ });
+
+ await new Promise((resolve, reject) => {
+ compiler2.run((error, stats) => {
+ if (error) {
+ reject(error);
+
+ return;
+ }
+
+ compiler2.close(() => {
+ expect(Object.keys(stats.compilation.assets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
]
`);
- expect(
- Array.from(stats.compilation.emittedAssets).sort()
- ).toMatchInlineSnapshot(`Array []`);
- expect(stats.compilation.warnings).toHaveLength(0);
- expect(stats.compilation.errors).toHaveLength(0);
-
- resolve();
- });
+ expect(
+ Array.from(stats.compilation.emittedAssets).sort()
+ ).toMatchInlineSnapshot(`Array []`);
+ expect(stats.compilation.warnings).toHaveLength(0);
+ expect(stats.compilation.errors).toHaveLength(0);
+
+ resolve();
});
});
- } else {
- expect(true).toBe(true);
- }
+ });
});
it('should work with the "filesystem" cache and asset modules', async () => {
- if (webpack.version[0] !== '4') {
- const casesDirectory = path.resolve(__dirname, 'cases');
- const directoryForCase = path.resolve(casesDirectory, 'asset-modules');
- // eslint-disable-next-line import/no-dynamic-require, global-require
- const webpackConfig = require(path.resolve(
- directoryForCase,
- 'webpack.config.js'
- ));
- const outputPath = path.resolve(
- __dirname,
- 'js/cache-filesystem-asset-modules'
- );
- const fileSystemCacheDirectory = path.resolve(
- __dirname,
- './js/.cache/type-filesystem'
- );
-
- await del([outputPath, fileSystemCacheDirectory]);
-
- const compiler1 = webpack({
- ...webpackConfig,
- mode: 'development',
- context: directoryForCase,
- cache: {
- type: 'filesystem',
- cacheDirectory: fileSystemCacheDirectory,
- idleTimeout: 0,
- idleTimeoutForInitialStore: 0,
- },
- output: {
- path: outputPath,
- },
- });
-
- await new Promise((resolve, reject) => {
- compiler1.run((error, stats) => {
- if (error) {
- reject(error);
-
- return;
- }
-
- compiler1.close(() => {
- expect(Object.keys(stats.compilation.assets).sort())
- .toMatchInlineSnapshot(`
+ const casesDirectory = path.resolve(__dirname, 'cases');
+ const directoryForCase = path.resolve(casesDirectory, 'asset-modules');
+ // eslint-disable-next-line import/no-dynamic-require, global-require
+ const webpackConfig = require(path.resolve(
+ directoryForCase,
+ 'webpack.config.js'
+ ));
+ const outputPath = path.resolve(
+ __dirname,
+ 'js/cache-filesystem-asset-modules'
+ );
+ const fileSystemCacheDirectory = path.resolve(
+ __dirname,
+ './js/.cache/type-filesystem'
+ );
+
+ await del([outputPath, fileSystemCacheDirectory]);
+
+ const compiler1 = webpack({
+ ...webpackConfig,
+ mode: 'development',
+ context: directoryForCase,
+ cache: {
+ type: 'filesystem',
+ cacheDirectory: fileSystemCacheDirectory,
+ idleTimeout: 0,
+ idleTimeoutForInitialStore: 0,
+ },
+ output: {
+ path: outputPath,
+ },
+ });
+
+ await new Promise((resolve, reject) => {
+ compiler1.run((error, stats) => {
+ if (error) {
+ reject(error);
+
+ return;
+ }
+
+ compiler1.close(() => {
+ expect(Object.keys(stats.compilation.assets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
"static/react.svg",
]
`);
- expect(Array.from(stats.compilation.emittedAssets).sort())
- .toMatchInlineSnapshot(`
+ expect(Array.from(stats.compilation.emittedAssets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
"static/react.svg",
]
`);
- expect(stats.compilation.warnings).toHaveLength(0);
- expect(stats.compilation.errors).toHaveLength(0);
+ expect(stats.compilation.warnings).toHaveLength(0);
+ expect(stats.compilation.errors).toHaveLength(0);
- resolve();
- });
+ resolve();
});
});
-
- const compiler2 = webpack({
- ...webpackConfig,
- mode: 'development',
- context: directoryForCase,
- cache: {
- type: 'filesystem',
- cacheDirectory: fileSystemCacheDirectory,
- idleTimeout: 0,
- idleTimeoutForInitialStore: 0,
- },
- output: {
- path: outputPath,
- },
- });
-
- await new Promise((resolve, reject) => {
- compiler2.run((error, stats) => {
- if (error) {
- reject(error);
-
- return;
- }
-
- compiler2.close(() => {
- expect(Object.keys(stats.compilation.assets).sort())
- .toMatchInlineSnapshot(`
+ });
+
+ const compiler2 = webpack({
+ ...webpackConfig,
+ mode: 'development',
+ context: directoryForCase,
+ cache: {
+ type: 'filesystem',
+ cacheDirectory: fileSystemCacheDirectory,
+ idleTimeout: 0,
+ idleTimeoutForInitialStore: 0,
+ },
+ output: {
+ path: outputPath,
+ },
+ });
+
+ await new Promise((resolve, reject) => {
+ compiler2.run((error, stats) => {
+ if (error) {
+ reject(error);
+
+ return;
+ }
+
+ compiler2.close(() => {
+ expect(Object.keys(stats.compilation.assets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
"static/react.svg",
]
`);
- expect(
- Array.from(stats.compilation.emittedAssets).sort()
- ).toMatchInlineSnapshot(`Array []`);
- expect(stats.compilation.warnings).toHaveLength(0);
- expect(stats.compilation.errors).toHaveLength(0);
-
- resolve();
- });
+ expect(
+ Array.from(stats.compilation.emittedAssets).sort()
+ ).toMatchInlineSnapshot(`Array []`);
+ expect(stats.compilation.warnings).toHaveLength(0);
+ expect(stats.compilation.errors).toHaveLength(0);
+
+ resolve();
});
});
- } else {
- expect(true).toBe(true);
- }
+ });
});
it('should work with the "filesystem" cache and file-loader', async () => {
- if (webpack.version[0] !== '4') {
- const casesDirectory = path.resolve(__dirname, 'cases');
- const directoryForCase = path.resolve(casesDirectory, 'file-loader');
- // eslint-disable-next-line import/no-dynamic-require, global-require
- const webpackConfig = require(path.resolve(
- directoryForCase,
- 'webpack.config.js'
- ));
- const outputPath = path.resolve(
- __dirname,
- 'js/cache-filesystem-file-loader'
- );
- const fileSystemCacheDirectory = path.resolve(
- __dirname,
- './js/.cache/type-filesystem'
- );
-
- await del([outputPath, fileSystemCacheDirectory]);
-
- const compiler1 = webpack({
- ...webpackConfig,
- mode: 'development',
- context: directoryForCase,
- cache: {
- type: 'filesystem',
- cacheDirectory: fileSystemCacheDirectory,
- idleTimeout: 0,
- idleTimeoutForInitialStore: 0,
- },
- output: {
- path: outputPath,
- },
- });
-
- await new Promise((resolve, reject) => {
- compiler1.run((error, stats) => {
- if (error) {
- reject(error);
-
- return;
- }
-
- compiler1.close(() => {
- expect(Object.keys(stats.compilation.assets).sort())
- .toMatchInlineSnapshot(`
+ const casesDirectory = path.resolve(__dirname, 'cases');
+ const directoryForCase = path.resolve(casesDirectory, 'file-loader');
+ // eslint-disable-next-line import/no-dynamic-require, global-require
+ const webpackConfig = require(path.resolve(
+ directoryForCase,
+ 'webpack.config.js'
+ ));
+ const outputPath = path.resolve(
+ __dirname,
+ 'js/cache-filesystem-file-loader'
+ );
+ const fileSystemCacheDirectory = path.resolve(
+ __dirname,
+ './js/.cache/type-filesystem'
+ );
+
+ await del([outputPath, fileSystemCacheDirectory]);
+
+ const compiler1 = webpack({
+ ...webpackConfig,
+ mode: 'development',
+ context: directoryForCase,
+ cache: {
+ type: 'filesystem',
+ cacheDirectory: fileSystemCacheDirectory,
+ idleTimeout: 0,
+ idleTimeoutForInitialStore: 0,
+ },
+ output: {
+ path: outputPath,
+ },
+ });
+
+ await new Promise((resolve, reject) => {
+ compiler1.run((error, stats) => {
+ if (error) {
+ reject(error);
+
+ return;
+ }
+
+ compiler1.close(() => {
+ expect(Object.keys(stats.compilation.assets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
"static/react.svg",
]
`);
- expect(Array.from(stats.compilation.emittedAssets).sort())
- .toMatchInlineSnapshot(`
+ expect(Array.from(stats.compilation.emittedAssets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
"static/react.svg",
]
`);
- expect(stats.compilation.warnings).toHaveLength(0);
- expect(stats.compilation.errors).toHaveLength(0);
+ expect(stats.compilation.warnings).toHaveLength(0);
+ expect(stats.compilation.errors).toHaveLength(0);
- resolve();
- });
+ resolve();
});
});
-
- const compiler2 = webpack({
- ...webpackConfig,
- mode: 'development',
- context: directoryForCase,
- cache: {
- type: 'filesystem',
- cacheDirectory: fileSystemCacheDirectory,
- idleTimeout: 0,
- idleTimeoutForInitialStore: 0,
- },
- output: {
- path: outputPath,
- },
- });
-
- await new Promise((resolve, reject) => {
- compiler2.run((error, stats) => {
- if (error) {
- reject(error);
-
- return;
- }
-
- compiler2.close(() => {
- expect(Object.keys(stats.compilation.assets).sort())
- .toMatchInlineSnapshot(`
+ });
+
+ const compiler2 = webpack({
+ ...webpackConfig,
+ mode: 'development',
+ context: directoryForCase,
+ cache: {
+ type: 'filesystem',
+ cacheDirectory: fileSystemCacheDirectory,
+ idleTimeout: 0,
+ idleTimeoutForInitialStore: 0,
+ },
+ output: {
+ path: outputPath,
+ },
+ });
+
+ await new Promise((resolve, reject) => {
+ compiler2.run((error, stats) => {
+ if (error) {
+ reject(error);
+
+ return;
+ }
+
+ compiler2.close(() => {
+ expect(Object.keys(stats.compilation.assets).sort())
+ .toMatchInlineSnapshot(`
Array [
"main.css",
"main.js",
"static/react.svg",
]
`);
- expect(
- Array.from(stats.compilation.emittedAssets).sort()
- ).toMatchInlineSnapshot(`Array []`);
- expect(stats.compilation.warnings).toHaveLength(0);
- expect(stats.compilation.errors).toHaveLength(0);
-
- resolve();
- });
+ expect(
+ Array.from(stats.compilation.emittedAssets).sort()
+ ).toMatchInlineSnapshot(`Array []`);
+ expect(stats.compilation.warnings).toHaveLength(0);
+ expect(stats.compilation.errors).toHaveLength(0);
+
+ resolve();
});
});
- } else {
- expect(true).toBe(true);
- }
+ });
});
});
diff --git a/test/TestCases.test.js b/test/TestCases.test.js
index 99e99b75..f9d70513 100644
--- a/test/TestCases.test.js
+++ b/test/TestCases.test.js
@@ -206,28 +206,16 @@ describe('TestCases', () => {
res = res.replace(dateRegexp, '');
- if (webpack.version[0] === '4') {
- const matchAll = res.match(/var hotCurrentHash = "([\d\w].*)"/i);
- const replacer = new Array(matchAll[1].length);
-
- res = res.replace(
- /var hotCurrentHash = "([\d\w].*)"/i,
- `var hotCurrentHash = "${replacer.fill('x').join('')}"`
- );
- } else {
- const matchAll = res.match(
- /__webpack_require__\.h = \(\) => \(("[\d\w].*")\)/i
- );
+ const matchAll = res.match(
+ /__webpack_require__\.h = \(\) => \(("[\d\w].*")\)/i
+ );
- const replacer = new Array(matchAll[1].length);
+ const replacer = new Array(matchAll[1].length);
- res = res.replace(
- /__webpack_require__\.h = \(\) => \(("[\d\w].*")\)/i,
- `__webpack_require__.h = () => ("${replacer
- .fill('x')
- .join('')}")`
- );
- }
+ res = res.replace(
+ /__webpack_require__\.h = \(\) => \(("[\d\w].*")\)/i,
+ `__webpack_require__.h = () => ("${replacer.fill('x').join('')}")`
+ );
fs.writeFileSync(
path.resolve(outputDirectoryForCase, 'main.js'),
diff --git a/test/TestMemoryFS.test.js b/test/TestMemoryFS.test.js
index 8d55a166..db79d4f9 100644
--- a/test/TestMemoryFS.test.js
+++ b/test/TestMemoryFS.test.js
@@ -20,11 +20,8 @@ describe('TestMemoryFS', () => {
context: directoryForCase,
cache: false,
});
- const outputFileSystem = createFsFromVolume(new Volume());
- // Todo remove when we drop webpack@4 support
- outputFileSystem.join = path.join.bind(path);
- compiler.outputFileSystem = outputFileSystem;
+ compiler.outputFileSystem = createFsFromVolume(new Volume());
compiler.run((err1, stats1) => {
if (err1) {
diff --git a/test/__snapshots__/HMR.test.js.snap.webpack4 b/test/__snapshots__/HMR.test.js.snap
similarity index 100%
rename from test/__snapshots__/HMR.test.js.snap.webpack4
rename to test/__snapshots__/HMR.test.js.snap
diff --git a/test/__snapshots__/HMR.test.js.snap.webpack5 b/test/__snapshots__/HMR.test.js.snap.webpack5
deleted file mode 100644
index bf306c32..00000000
--- a/test/__snapshots__/HMR.test.js.snap.webpack5
+++ /dev/null
@@ -1,43 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`HMR should handle error event 1`] = `"[HMR] css reload %s"`;
-
-exports[`HMR should handle error event 2`] = `""`;
-
-exports[`HMR should reloads with # link href 1`] = `"[HMR] css reload %s"`;
-
-exports[`HMR should reloads with # link href 2`] = `""`;
-
-exports[`HMR should reloads with absolute remove url 1`] = `"[HMR] css reload %s"`;
-
-exports[`HMR should reloads with absolute remove url 2`] = `""`;
-
-exports[`HMR should reloads with link without href 1`] = `"[HMR] css reload %s"`;
-
-exports[`HMR should reloads with link without href 2`] = `""`;
-
-exports[`HMR should reloads with locals 1`] = `"[HMR] Detected local css modules. Reload all css"`;
-
-exports[`HMR should reloads with locals 2`] = `""`;
-
-exports[`HMR should reloads with non http/https link href 1`] = `"[HMR] css reload %s"`;
-
-exports[`HMR should reloads with non http/https link href 2`] = `""`;
-
-exports[`HMR should reloads with non-file script in the end of page 1`] = `"[HMR] Reload all css"`;
-
-exports[`HMR should reloads with non-file script in the end of page 2`] = `""`;
-
-exports[`HMR should work reload all css 1`] = `"[HMR] Reload all css"`;
-
-exports[`HMR should work reload all css 2`] = `""`;
-
-exports[`HMR should works 1`] = `"[HMR] css reload %s"`;
-
-exports[`HMR should works 2`] = `""`;
-
-exports[`HMR should works with multiple updates 1`] = `"[HMR] css reload %s"`;
-
-exports[`HMR should works with multiple updates 2`] = `""`;
-
-exports[`HMR should works with multiple updates 3`] = `""`;
diff --git a/test/__snapshots__/attributes-option.test.js.snap.webpack4 b/test/__snapshots__/attributes-option.test.js.snap
similarity index 100%
rename from test/__snapshots__/attributes-option.test.js.snap.webpack4
rename to test/__snapshots__/attributes-option.test.js.snap
diff --git a/test/__snapshots__/attributes-option.test.js.snap.webpack5 b/test/__snapshots__/attributes-option.test.js.snap.webpack5
deleted file mode 100644
index 84007ca0..00000000
--- a/test/__snapshots__/attributes-option.test.js.snap.webpack5
+++ /dev/null
@@ -1,37 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`attributes option should work with attributes option: DOM 1`] = `
-"
- style-loader test
-
-
-
- Body
-
-