From 03be38be97dfd9f03e14aa27be3b6065eb057ae6 Mon Sep 17 00:00:00 2001 From: zackjackson Date: Sat, 22 Dec 2018 23:18:00 -0800 Subject: [PATCH 1/4] feat(hotLoading): Addressing some issues in HMR CSS modules should have better HMR. Updates and renames were also done that appear to have gotton lost Fixed up CSS reloadAll Dont assume CSS modules be default Also fixing css loading order issues that appear during HMR Pulling in a handful of fixes from webpack --- src/hotLoader.js | 23 +- src/hotModuleReplacement.js | 187 ++++--- src/index.js | 1053 +++++++++++++++++++---------------- src/loader.js | 187 ++++--- 4 files changed, 791 insertions(+), 659 deletions(-) diff --git a/src/hotLoader.js b/src/hotLoader.js index c7c0364c..e4e9471b 100644 --- a/src/hotLoader.js +++ b/src/hotLoader.js @@ -1,24 +1,29 @@ const path = require('path'); + const loaderUtils = require('loader-utils'); const defaultOptions = { - fileMap: '{fileName}', - cssModules: true, + fileMap: '{fileName}', }; -module.exports = function (content) { - this.cacheable(); - const options = Object.assign( +module.exports = function(content) { + this.cacheable(); + const options = Object.assign( {}, defaultOptions, - loaderUtils.getOptions(this), + loaderUtils.getOptions(this) ); - const accept = options.cssModules ? '' : 'module.hot.accept(undefined, cssReload);'; - return content + ` + const accept = options.cssModules + ? '' + : 'module.hot.accept(undefined, cssReload);'; + return `${content} if(module.hot) { // ${Date.now()} - var cssReload = require(${loaderUtils.stringifyRequest(this, path.join(__dirname, 'hotModuleReplacement.js'))})(module.id, ${JSON.stringify(options)}); + var cssReload = require(${loaderUtils.stringifyRequest( + this, + path.join(__dirname, 'hotModuleReplacement.js') + )})(module.id, ${JSON.stringify(options)}); module.hot.dispose(cssReload); ${accept}; } diff --git a/src/hotModuleReplacement.js b/src/hotModuleReplacement.js index 9becca5c..0b6aa04c 100644 --- a/src/hotModuleReplacement.js +++ b/src/hotModuleReplacement.js @@ -6,121 +6,128 @@ const debounce = require('lodash/debounce'); const noDocument = typeof document === 'undefined'; const forEach = Array.prototype.forEach; -const noop = function () {}; - -const getCurrentScriptUrl = function (moduleId) { - let src = srcByModuleId[moduleId]; - - if (!src) { - if (document.currentScript) { - src = document.currentScript.src; - } else { - const scripts = document.getElementsByTagName('script'); - const lastScriptTag = scripts[scripts.length - 1]; - - if (lastScriptTag) { - src = lastScriptTag.src; - } +const noop = function() {}; + +const getCurrentScriptUrl = function(moduleId) { + let src = srcByModuleId[moduleId]; + + if (!src) { + if (document.currentScript) { + src = document.currentScript.src; + } else { + const scripts = document.getElementsByTagName('script'); + const lastScriptTag = scripts[scripts.length - 1]; + + if (lastScriptTag) { + src = lastScriptTag.src; + } + } + srcByModuleId[moduleId] = src; } - srcByModuleId[moduleId] = src; - } - - return function (fileMap) { - const splitResult = /([^\\/]+)\.js$/.exec(src); - const filename = splitResult && splitResult[1]; - if (!filename) { - return [src.replace('.js', '.css')]; - } - return fileMap.split(',').map(function (mapRule) { - const reg = new RegExp(filename + '\\.js$', 'g'); - return normalizeUrl(src.replace(reg, mapRule.replace(/{fileName}/g, filename) + '.css'), { stripWWW: false }); - }); - }; + + return function(fileMap) { + const splitResult = /([^\\/]+)\.js$/.exec(src); + const filename = splitResult && splitResult[1]; + if (!filename) { + return [src.replace('.js', '.css')]; + } + return fileMap.split(',').map((mapRule) => { + const reg = new RegExp(`${filename}\\.js$`, 'g'); + return normalizeUrl( + src.replace( + reg, + `${mapRule.replace(/{fileName}/g, filename)}.css` + ), + { stripWWW: false } + ); + }); + }; }; function updateCss(el, url) { - if (!url) { - url = el.href.split('?')[0]; - } - if (el.isLoaded === false) { + if (!url) { + url = el.href.split('?')[0]; + } + if (el.isLoaded === false) { // We seem to be about to replace a css link that hasn't loaded yet. // We're probably changing the same file more than once. - return; - } - if (!url || !(url.indexOf('.css') > -1)) return; + return; + } + if (!url || !(url.indexOf('.css') > -1)) return; - el.visited = true; - const newEl = el.cloneNode(); + el.visited = true; + const newEl = el.cloneNode(); - newEl.isLoaded = false; + newEl.isLoaded = false; - newEl.addEventListener('load', function () { - newEl.isLoaded = true; - el.parentNode.removeChild(el); - }); + newEl.addEventListener('load', () => { + newEl.isLoaded = true; + el.parentNode.removeChild(el); + }); - newEl.addEventListener('error', function () { - newEl.isLoaded = true; - el.parentNode.removeChild(el); - }); + newEl.addEventListener('error', () => { + newEl.isLoaded = true; + el.parentNode.removeChild(el); + }); - newEl.href = url + '?' + Date.now(); - el.parentNode.appendChild(newEl); + newEl.href = `${url}?${Date.now()}`; + el.parentNode.appendChild(newEl); } function getReloadUrl(href, src) { - href = normalizeUrl(href, { stripWWW: false }); - let ret; - src.some(function (url) { - if (href.indexOf(src) > -1) { - ret = url; - } - }); - return ret; + href = normalizeUrl(href, { stripWWW: false }); + let ret; + // eslint-disable-next-line array-callback-return + src.some((url) => { + if (href.indexOf(src) > -1) { + ret = url; + } + }); + return ret; } function reloadStyle(src) { - const elements = document.querySelectorAll('link'); - let loaded = false; + const elements = document.querySelectorAll('link'); + let loaded = false; - forEach.call(elements, function (el) { - if (el.visited === true) return; + forEach.call(elements, (el) => { + if (el.visited === true) return; - const url = getReloadUrl(el.href, src); - if (url) { - updateCss(el, url); - loaded = true; - } - }); + const url = getReloadUrl(el.href, src); + if (url) { + updateCss(el, url); + loaded = true; + } + }); - return loaded; + return loaded; } function reloadAll() { - const elements = document.querySelectorAll('link'); - forEach.call(elements, function (el) { - if (el.visited === true) return; - updateCss(el); - }); + const elements = document.querySelectorAll('link'); + forEach.call(elements, (el) => { + if (el.visited === true) return; + updateCss(el); + }); } -module.exports = function (moduleId, options) { - if (noDocument) { - return noop; - } - - const getScriptSrc = getCurrentScriptUrl(moduleId); - - function update() { - const src = getScriptSrc(options.fileMap); - const reloaded = reloadStyle(src); - if (reloaded && !options.reloadAll) { - console.log('[HMR] css reload %s', src.join(' ')); - } else { - console.log('[HMR] Reload all css'); - reloadAll(); +module.exports = function(moduleId, options) { + if (noDocument) { + return noop; + } + + const getScriptSrc = getCurrentScriptUrl(moduleId); + + function update() { + const src = getScriptSrc(options.fileMap); + const reloaded = reloadStyle(src); + if (reloaded && !options.reloadAll) { + console.log('[HMR] css reload %s', src.join(' ')); + } else { + console.log('[HMR] Reload all css'); + reloadAll(); + } } - } - return debounce(update, 10); + return debounce(update, 10); }; diff --git a/src/index.js b/src/index.js index e2a77449..dfaab46c 100644 --- a/src/index.js +++ b/src/index.js @@ -20,591 +20,708 @@ const REGEXP_CONTENTHASH = /\[contenthash(?::(\d+))?\]/i; const REGEXP_NAME = /\[name\]/i; const isHMR = (compiler) => { - if (compiler && compiler.options) { - if (compiler.options.devServer && compiler.options.devServer.hot) { - return true; - } + if (compiler && compiler.options) { + if (compiler.options.devServer && compiler.options.devServer.hot) { + return true; + } - if (compiler.options.entry) { - const entry = typeof compiler.options.entry === 'function' ? compiler.options.entry() : compiler.options.entry; - const entryString = JSON.stringify(entry); - return entryString.includes('hot') || entryString.includes('hmr'); + if (compiler.options.entry) { + const entry = + typeof compiler.options.entry === 'function' + ? compiler.options.entry() + : compiler.options.entry; + const entryString = JSON.stringify(entry); + return entryString.includes('hot') || entryString.includes('hmr'); + } } - } - return false; + return false; }; class CssDependency extends webpack.Dependency { - constructor( - { identifier, content, media, sourceMap }, - context, - identifierIndex, + constructor( + { identifier, content, media, sourceMap }, + context, + identifierIndex ) { - super(); - this.identifier = identifier; - this.identifierIndex = identifierIndex; - this.content = content; - this.media = media; - this.sourceMap = sourceMap; - this.context = context; - } - - getResourceIdentifier() { - return `css-module-${this.identifier}-${this.identifierIndex}`; - } + super(); + this.identifier = identifier; + this.identifierIndex = identifierIndex; + this.content = content; + this.media = media; + this.sourceMap = sourceMap; + this.context = context; + } + + getResourceIdentifier() { + return `css-module-${this.identifier}-${this.identifierIndex}`; + } } class CssDependencyTemplate { - apply() {} + apply() {} } class CssModule extends webpack.Module { - constructor(dependency) { - super(MODULE_TYPE, dependency.context); - this._identifier = dependency.identifier; - this._identifierIndex = dependency.identifierIndex; - this.content = dependency.content; - this.media = dependency.media; - this.sourceMap = dependency.sourceMap; - } + constructor(dependency) { + super(MODULE_TYPE, dependency.context); + this.id = ''; + this._identifier = dependency.identifier; + this._identifierIndex = dependency.identifierIndex; + this.content = dependency.content; + this.media = dependency.media; + this.sourceMap = dependency.sourceMap; + } // no source() so webpack doesn't do add stuff to the bundle - size() { - return this.content.length; - } + size() { + return this.content.length; + } - identifier() { - return `css ${this._identifier} ${this._identifierIndex}`; - } + identifier() { + return `css ${this._identifier} ${this._identifierIndex}`; + } - readableIdentifier(requestShortener) { - return `css ${requestShortener.shorten(this._identifier)}${ + readableIdentifier(requestShortener) { + return `css ${requestShortener.shorten(this._identifier)}${ this._identifierIndex ? ` (${this._identifierIndex})` : '' - }`; - } - - nameForCondition() { - const resource = this._identifier.split('!').pop(); - const idx = resource.indexOf('?'); - if (idx >= 0) return resource.substring(0, idx); - return resource; - } - - updateCacheModule(module) { - this.content = module.content; - this.media = module.media; - this.sourceMap = module.sourceMap; - } - - needRebuild() { - return true; - } - - build(options, compilation, resolver, fileSystem, callback) { - this.buildInfo = {}; - this.buildMeta = {}; - callback(); - } - - updateHash(hash) { - super.updateHash(hash); - hash.update(this.content); - hash.update(this.media || ''); - hash.update(JSON.stringify(this.sourceMap || '')); - } + }`; + } + + nameForCondition() { + const resource = this._identifier.split('!').pop(); + const idx = resource.indexOf('?'); + if (idx >= 0) return resource.substring(0, idx); + return resource; + } + + updateCacheModule(module) { + this.content = module.content; + this.media = module.media; + this.sourceMap = module.sourceMap; + } + + needRebuild() { + return true; + } + + build(options, compilation, resolver, fileSystem, callback) { + this.buildInfo = {}; + this.buildMeta = {}; + callback(); + } + + updateHash(hash) { + super.updateHash(hash); + hash.update(this.content); + hash.update(this.media || ''); + hash.update(this.sourceMap ? JSON.stringify(this.sourceMap) : ''); + } } class CssModuleFactory { - create( - { + create( + { dependencies: [dependency], }, - callback, + callback ) { - callback(null, new CssModule(dependency)); - } + callback(null, new CssModule(dependency)); + } } class ExtractCssChunks { - constructor(options) { - this.options = Object.assign({ filename: '[name].css', orderWarning: true }, options); - const { cssModules, reloadAll } = this.options; - - if (!this.options.chunkFilename) { - const { filename } = this.options; - const hasName = filename.includes('[name]'); - const hasId = filename.includes('[id]'); - const hasChunkHash = filename.includes('[chunkhash]'); - - // Anything changing depending on chunk is fine - if (hasChunkHash || hasName || hasId) { - this.options.chunkFilename = filename; - } else { - // Elsewise prefix '[id].' in front of the basename to make it changing - this.options.chunkFilename = filename.replace(/(^|\/)([^/]*(?:\?|$))/, '$1[id].$2'); - } - } + constructor(options) { + this.options = Object.assign( + { + filename: '[name].css', + }, + options + ); + const { cssModules, reloadAll } = this.options; + + if (!this.options.chunkFilename) { + const { filename } = this.options; + const hasName = filename.includes('[name]'); + const hasId = filename.includes('[id]'); + const hasChunkHash = filename.includes('[chunkhash]'); + // Anything changing depending on chunk is fine + if (hasChunkHash || hasName || hasId) { + this.options.chunkFilename = filename; + } else { + // Elsewise prefix '[id].' in front of the basename to make it changing + this.options.chunkFilename = filename.replace( + /(^|\/)([^/]*(?:\?|$))/, + '$1[id].$2' + ); + } + } - this.hotLoaderObject = Object.assign({ - loader: hotLoader, - options: { - cssModules: false, - reloadAll: false, - }, - }, { - options: { - cssModules, - reloadAll, - }, - }); - } - - apply(compiler) { - try { - const isHOT = this.options.hot ? true : isHMR(compiler); - - if (isHOT && compiler.options.module && compiler.options.module.rules) { - compiler.options.module.rules = this.updateWebpackConfig(compiler.options.module.rules); - } - } catch (e) { - throw new Error(`Something went wrong: contact the author: ${JSON.stringify(e)}`); + this.hotLoaderObject = Object.assign( + { + loader: hotLoader, + options: { + cssModules: false, + reloadAll: false, + }, + }, + { + options: { + cssModules, + reloadAll, + }, + } + ); } - compiler.hooks.thisCompilation.tap(pluginName, (compilation) => { - compilation.hooks.normalModuleLoader.tap(pluginName, (lc, m) => { - const loaderContext = lc; - const module = m; - loaderContext[MODULE_TYPE] = (content) => { - if (!Array.isArray(content) && content != null) { - throw new Error(`Exported value was not extracted as an array: ${JSON.stringify(content)}`); - } - const identifierCountMap = new Map(); - for (const line of content) { - const count = identifierCountMap.get(line.identifier) || 0; - module.addDependency(new CssDependency(line, m.context, count)); - identifierCountMap.set(line.identifier, count + 1); - } - }; - }); - compilation.dependencyFactories.set( + apply(compiler) { + try { + const isHOT = this.options.hot ? true : isHMR(compiler); + + if ( + isHOT && + compiler.options.module && + compiler.options.module.rules + ) { + compiler.options.module.rules = this.updateWebpackConfig( + compiler.options.module.rules + ); + } + } catch (e) { + throw new Error( + `Something went wrong: contact the author: ${JSON.stringify(e)}` + ); + } + + compiler.hooks.thisCompilation.tap(pluginName, (compilation) => { + compilation.hooks.normalModuleLoader.tap(pluginName, (lc, m) => { + const loaderContext = lc; + const module = m; + loaderContext[MODULE_TYPE] = (content) => { + if (!Array.isArray(content) && content != null) { + throw new Error( + `Exported value was not extracted as an array: ${JSON.stringify( + content + )}` + ); + } + + const identifierCountMap = new Map(); + for (const line of content) { + const count = + identifierCountMap.get(line.identifier) || 0; + module.addDependency( + new CssDependency(line, m.context, count) + ); + identifierCountMap.set(line.identifier, count + 1); + } + }; + }); + compilation.dependencyFactories.set( CssDependency, - new CssModuleFactory(), + new CssModuleFactory() ); - compilation.dependencyTemplates.set( + compilation.dependencyTemplates.set( CssDependency, - new CssDependencyTemplate(), + new CssDependencyTemplate() ); - compilation.mainTemplate.hooks.renderManifest.tap( + compilation.mainTemplate.hooks.renderManifest.tap( pluginName, (result, { chunk }) => { - const renderedModules = Array.from(chunk.modulesIterable).filter( - module => module.type === MODULE_TYPE, - ); - if (renderedModules.length > 0) { - result.push({ - render: () => + const renderedModules = Array.from( + chunk.modulesIterable + ).filter((module) => module.type === MODULE_TYPE); + if (renderedModules.length > 0) { + result.push({ + render: () => this.renderContentAsset( compilation, chunk, renderedModules, - compilation.runtimeTemplate.requestShortener, + compilation.runtimeTemplate.requestShortener ), - filenameTemplate: this.options.filename, - pathOptions: { - chunk, - contentHashType: MODULE_TYPE, - }, - identifier: `${pluginName}.${chunk.id}`, - hash: chunk.contentHash[MODULE_TYPE], - }); - } - }, + filenameTemplate: this.options.filename, + pathOptions: { + chunk, + contentHashType: MODULE_TYPE, + }, + identifier: `${pluginName}.${chunk.id}`, + hash: chunk.contentHash[MODULE_TYPE], + }); + } + } ); - compilation.chunkTemplate.hooks.renderManifest.tap( + compilation.chunkTemplate.hooks.renderManifest.tap( pluginName, (result, { chunk }) => { - const renderedModules = Array.from(chunk.modulesIterable).filter( - module => module.type === MODULE_TYPE, - ); - if (renderedModules.length > 0) { - result.push({ - render: () => + const renderedModules = Array.from( + chunk.modulesIterable + ).filter((module) => module.type === MODULE_TYPE); + if (renderedModules.length > 0) { + result.push({ + render: () => this.renderContentAsset( compilation, chunk, renderedModules, - compilation.runtimeTemplate.requestShortener, + compilation.runtimeTemplate.requestShortener ), - filenameTemplate: this.options.chunkFilename, - pathOptions: { - chunk, - contentHashType: MODULE_TYPE, - }, - identifier: `${pluginName}.${chunk.id}`, - hash: chunk.contentHash[MODULE_TYPE], - }); - } - }, + filenameTemplate: this.options.chunkFilename, + pathOptions: { + chunk, + contentHashType: MODULE_TYPE, + }, + identifier: `${pluginName}.${chunk.id}`, + hash: chunk.contentHash[MODULE_TYPE], + }); + } + } ); - compilation.mainTemplate.hooks.hashForChunk.tap( + 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)); - } - if (REGEXP_CONTENTHASH.test(chunkFilename)) { - hash.update( - JSON.stringify(chunk.getChunkMaps(true).contentHash[MODULE_TYPE] || {}), + const { chunkFilename } = this.options; + if (REGEXP_CHUNKHASH.test(chunkFilename)) { + hash.update( + JSON.stringify(chunk.getChunkMaps(true).hash) ); - } - if (REGEXP_NAME.test(chunkFilename)) { - hash.update(JSON.stringify(chunk.getChunkMaps(true).name)); - } - }, + } + if (REGEXP_CONTENTHASH.test(chunkFilename)) { + hash.update( + JSON.stringify( + chunk.getChunkMaps(true).contentHash[ + MODULE_TYPE + ] || {} + ) + ); + } + if (REGEXP_NAME.test(chunkFilename)) { + hash.update( + JSON.stringify(chunk.getChunkMaps(true).name) + ); + } + } ); - compilation.hooks.contentHash.tap(pluginName, (chunk) => { - const { outputOptions } = compilation; - const { hashFunction, hashDigest, hashDigestLength } = outputOptions; - const hash = createHash(hashFunction); - for (const m of chunk.modulesIterable) { - if (m.type === MODULE_TYPE) { - m.updateHash(hash); - } - } - const { contentHash } = chunk; - contentHash[MODULE_TYPE] = hash + compilation.hooks.contentHash.tap(pluginName, (chunk) => { + const { outputOptions } = compilation; + const { + hashFunction, + hashDigest, + hashDigestLength, + } = outputOptions; + const hash = createHash(hashFunction); + for (const m of chunk.modulesIterable) { + if (m.type === MODULE_TYPE) { + m.updateHash(hash); + } + } + const { contentHash } = chunk; + contentHash[MODULE_TYPE] = hash .digest(hashDigest) .substring(0, hashDigestLength); - }); - const { mainTemplate } = compilation; - mainTemplate.hooks.localVars.tap(pluginName, (source, chunk) => { - const chunkMap = this.getCssChunkObject(chunk); - if (Object.keys(chunkMap).length > 0) { - return Template.asString([ - source, - '', - '// object to store loaded CSS chunks', - 'var installedCssChunks = {', - Template.indent(chunk.ids.map(id => `${JSON.stringify(id)}: 0`).join(',\n')), - '}', - ]); - } - return source; - }); - mainTemplate.hooks.requireEnsure.tap( + }); + const { mainTemplate } = compilation; + mainTemplate.hooks.localVars.tap(pluginName, (source, chunk) => { + const chunkMap = this.getCssChunkObject(chunk); + if (Object.keys(chunkMap).length > 0) { + return Template.asString([ + source, + '', + '// object to store loaded CSS chunks', + 'var installedCssChunks = {', + Template.indent( + chunk.ids + .map((id) => `${JSON.stringify(id)}: 0`) + .join(',\n') + ), + '}', + ]); + } + return source; + }); + mainTemplate.hooks.requireEnsure.tap( pluginName, (source, chunk, hash) => { - const chunkMap = this.getCssChunkObject(chunk); - if (Object.keys(chunkMap).length > 0) { - const chunkMaps = chunk.getChunkMaps(); - const linkHrefPath = mainTemplate.getAssetPath( + const chunkMap = this.getCssChunkObject(chunk); + if (Object.keys(chunkMap).length > 0) { + const chunkMaps = chunk.getChunkMaps(); + const { + crossOriginLoading, + } = mainTemplate.outputOptions; + const linkHrefPath = mainTemplate.getAssetPath( JSON.stringify(this.options.chunkFilename), - { - hash: `" + ${mainTemplate.renderCurrentHashCode(hash)} + "`, - hashWithLength: length => - `" + ${mainTemplate.renderCurrentHashCode(hash, length)} + "`, - 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[ + { + 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 - ].substring(0, length); - } - } - return `" + ${JSON.stringify( - shortChunkHashMap, + ] === 'string' + ) { + shortChunkHashMap[ + chunkId + ] = chunkMaps.hash[ + chunkId + ].substring(0, length); + } + } + return `" + ${JSON.stringify( + shortChunkHashMap )}[chunkId] + "`; - }, - contentHash: { - [MODULE_TYPE]: `" + ${JSON.stringify( - chunkMaps.contentHash[MODULE_TYPE], + }, + 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[ + }, + 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, + ].substring(0, length); + } + } + return `" + ${JSON.stringify( + shortContentHashMap )}[chunkId] + "`; - }, - }, - name: `" + (${JSON.stringify( - chunkMaps.name, + }, + }, + name: `" + (${JSON.stringify( + chunkMaps.name )}[chunkId]||chunkId) + "`, - }, - contentHashType: MODULE_TYPE, - }, + }, + contentHashType: MODULE_TYPE, + } ); - return Template.asString([ - source, - '', - `// ${pluginName} CSS loading`, - `var cssChunks = ${JSON.stringify(chunkMap)};`, - 'if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);', - 'else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {', - Template.indent([ - 'promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {', - Template.indent([ - `var href = ${linkHrefPath};`, - `var fullhref = ${mainTemplate.requireFn}.p + href;`, - 'var existingLinkTags = document.getElementsByTagName("link");', - 'for(var i = 0; i < existingLinkTags.length; i++) {', - Template.indent([ - 'var tag = existingLinkTags[i];', - 'var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");', - 'if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return resolve();', - ]), - '}', - 'var existingStyleTags = document.getElementsByTagName("style");', - 'for(var i = 0; i < existingStyleTags.length; i++) {', - Template.indent([ - 'var tag = existingStyleTags[i];', - 'var dataHref = tag.getAttribute("data-href");', - 'if(dataHref === href || dataHref === fullhref) return resolve();', - ]), - '}', - 'var linkTag = document.createElement("link");', - 'linkTag.rel = "stylesheet";', - 'linkTag.type = "text/css";', - 'linkTag.onload = resolve;', - 'linkTag.onerror = function(event) {', - Template.indent([ - 'var request = event && event.target && event.target.src || fullhref;', - 'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + request + ")");', - 'err.request = request;', - 'reject(err);', - ]), - '};', - 'linkTag.href = fullhref;', - 'var head = document.getElementsByTagName("head")[0];', - 'head.appendChild(linkTag);', - ]), - '}).then(function() {', - Template.indent(['installedCssChunks[chunkId] = 0;']), - '}));', - ]), - '}', - ]); - } - return source; - }, + return Template.asString([ + source, + '', + `// ${pluginName} CSS loading`, + `var cssChunks = ${JSON.stringify(chunkMap)};`, + 'if(installedCssChunks[chunkId]) promises.push(installedCssChunks[chunkId]);', + 'else if(installedCssChunks[chunkId] !== 0 && cssChunks[chunkId]) {', + Template.indent([ + 'promises.push(installedCssChunks[chunkId] = new Promise(function(resolve, reject) {', + Template.indent([ + `var href = ${linkHrefPath};`, + `var fullhref = ${ + mainTemplate.requireFn + }.p + href;`, + 'var existingLinkTags = document.getElementsByTagName("link");', + 'for(var i = 0; i < existingLinkTags.length; i++) {', + Template.indent([ + 'var tag = existingLinkTags[i];', + 'var dataHref = tag.getAttribute("data-href") || tag.getAttribute("href");', + 'if(tag.rel === "stylesheet" && (dataHref === href || dataHref === fullhref)) return resolve();', + ]), + '}', + 'var existingStyleTags = document.getElementsByTagName("style");', + 'for(var i = 0; i < existingStyleTags.length; i++) {', + Template.indent([ + 'var tag = existingStyleTags[i];', + 'var dataHref = tag.getAttribute("data-href");', + 'if(dataHref === href || dataHref === fullhref) return resolve();', + ]), + '}', + 'var linkTag = document.createElement("link");', + 'linkTag.rel = "stylesheet";', + 'linkTag.type = "text/css";', + 'linkTag.onload = resolve;', + 'linkTag.onerror = function(event) {', + Template.indent([ + 'var request = event && event.target && event.target.src || fullhref;', + 'var err = new Error("Loading CSS chunk " + chunkId + " failed.\\n(" + request + ")");', + 'err.request = request;', + 'delete installedCssChunks[chunkId]', + 'linkTag.parentNode.removeChild(linkTag)', + 'reject(err);', + ]), + '};', + 'linkTag.href = fullhref;', + crossOriginLoading + ? Template.asString([ + "if (linkTag.href.indexOf(window.location.origin + '/') !== 0) {", + Template.indent( + `linkTag.crossOrigin = ${JSON.stringify( + crossOriginLoading + )};` + ), + '}', + ]) + : '', + 'var head = document.getElementsByTagName("head")[0];', + 'head.appendChild(linkTag);', + ]), + '}).then(function() {', + Template.indent([ + 'installedCssChunks[chunkId] = 0;', + ]), + '}));', + ]), + '}', + ]); + } + return source; + } ); - }); - } - - traverseDepthFirst(root, visit) { - let nodesToVisit = [root]; + }); + } - while (nodesToVisit.length > 0) { - const currentNode = nodesToVisit.shift(); + traverseDepthFirst(root, visit) { + let nodesToVisit = [root]; - if (currentNode !== null && typeof currentNode === 'object') { - const children = Object.values(currentNode); - nodesToVisit = [...children, ...nodesToVisit]; - } + while (nodesToVisit.length > 0) { + const currentNode = nodesToVisit.shift(); - visit(currentNode); - } - } - - updateWebpackConfig(rulez) { - return rulez.reduce((rules, rule) => { - this.traverseDepthFirst(rule, (node) => { - if (node && node.use && Array.isArray(node.use)) { - const isMiniCss = node.use.some((l) => { - const needle = l.loader || l; - if (typeof l === 'function') { - return false; + if (currentNode !== null && typeof currentNode === 'object') { + const children = Object.values(currentNode); + nodesToVisit = [...children, ...nodesToVisit]; } - return needle.includes(pluginName); - }); - if (isMiniCss) { - node.use.unshift(this.hotLoaderObject); - } - } - if (node && node.loader && Array.isArray(node.loader)) { - const isMiniCss = node.loader.some((l) => { - const needle = l.loader || l; - if (typeof l === 'function') { - return false; - } - return needle.includes(pluginName); - }); - if (isMiniCss) { - node.loader.unshift(this.hotLoaderObject); - } + + visit(currentNode); } - }); + } + + updateWebpackConfig(rulez) { + return rulez.reduce((rules, rule) => { + this.traverseDepthFirst(rule, (node) => { + if (node && node.use && Array.isArray(node.use)) { + const isExtractCss = node.use.some((l) => { + const needle = l.loader || l; + if (typeof l === 'function') { + return false; + } + return needle.includes(pluginName); + }); + if (isExtractCss) { + node.use.unshift(this.hotLoaderObject); + } + } + if (node && node.loader && Array.isArray(node.loader)) { + const isExtractCss = node.loader.some((l) => { + const needle = l.loader || l; + if (typeof l === 'function') { + return false; + } + return needle.includes(pluginName); + }); + if (isExtractCss) { + node.loader.unshift(this.hotLoaderObject); + } + } + }); - rules.push(rule); + rules.push(rule); - return rules; - }, []); - } + return rules; + }, []); + } - getCssChunkObject(mainChunk) { - const obj = {}; - for (const chunk of mainChunk.getAllAsyncChunks()) { - for (const module of chunk.modulesIterable) { - if (module.type === MODULE_TYPE) { - obj[chunk.id] = 1; - break; + getCssChunkObject(mainChunk) { + const obj = {}; + for (const chunk of mainChunk.getAllAsyncChunks()) { + for (const module of chunk.modulesIterable) { + if (module.type === MODULE_TYPE) { + obj[chunk.id] = 1; + break; + } + } } - } + return obj; } - return obj; - } - renderContentAsset(compilation, chunk, modules, requestShortener) { - let usedModules; + renderContentAsset(compilation, chunk, modules, requestShortener) { + let usedModules; - const [chunkGroup] = chunk.groupsIterable; - if (typeof chunkGroup.getModuleIndex2 === 'function') { + const [chunkGroup] = chunk.groupsIterable; + if (typeof chunkGroup.getModuleIndex2 === 'function') { // Store dependencies for modules - const moduleDependencies = new Map(modules.map(m => [m, new Set()])); + const moduleDependencies = new Map( + modules.map((m) => [m, new Set()]) + ); // Get ordered list of modules per chunk group // This loop also gathers dependencies from the ordered lists // Lists are in reverse order to allow to use Array.pop() - const modulesByChunkGroup = Array.from(chunk.groupsIterable, (cg) => { - const sortedModules = modules - .map(m => ({ - module: m, - index: cg.getModuleIndex2(m), - })) - .filter(item => item.index !== undefined) - .sort((a, b) => b.index - a.index) - .map(item => item.module); - for (let i = 0; i < sortedModules.length; i++) { - const set = moduleDependencies.get(sortedModules[i]); - for (let j = i + 1; j < sortedModules.length; j++) { - set.add(sortedModules[j]); - } - } - - return sortedModules; - }); + const modulesByChunkGroup = Array.from( + chunk.groupsIterable, + (cg) => { + const sortedModules = modules + .map((m) => { + return { + module: m, + index: cg.getModuleIndex2(m), + }; + }) + .filter((item) => item.index !== undefined) + .sort((a, b) => b.index - a.index) + .map((item) => item.module); + for (let i = 0; i < sortedModules.length; i++) { + const set = moduleDependencies.get(sortedModules[i]); + for (let j = i + 1; j < sortedModules.length; j++) { + set.add(sortedModules[j]); + } + } + + return sortedModules; + } + ); // set with already included modules in correct order - usedModules = new Set(); + usedModules = new Set(); - const unusedModulesFilter = m => !usedModules.has(m); + const unusedModulesFilter = (m) => !usedModules.has(m); - while (usedModules.size < modules.length) { - let success = false; - let bestMatch; - let bestMatchDeps; + while (usedModules.size < modules.length) { + let success = false; + let bestMatch; + let bestMatchDeps; // get first module where dependencies are fulfilled - for (const list of modulesByChunkGroup) { + for (const list of modulesByChunkGroup) { // skip and remove already added modules - while (list.length > 0 && usedModules.has(list[list.length - 1])) { list.pop(); } + while ( + list.length > 0 && + usedModules.has(list[list.length - 1]) + ) { + list.pop(); + } // skip empty lists - if (list.length !== 0) { - const module = list[list.length - 1]; - const deps = moduleDependencies.get(module); + if (list.length !== 0) { + const module = list[list.length - 1]; + const deps = moduleDependencies.get(module); // determine dependencies that are not yet included - const failedDeps = Array.from(deps).filter(unusedModulesFilter); + const 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) { + 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; - } - } - } - - if (!success) { + usedModules.add(list.pop()); + success = true; + break; + } + } + } + + 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.orderWarning) { - compilation.warnings.push( - new Error( - `chunk ${chunk.name || chunk.id} [mini-css-extract-plugin]\n` + - 'Conflicting order between:\n' + - ` * ${fallbackModule.readableIdentifier(requestShortener)}\n` + - `${bestMatchDeps - .map(m => ` * ${m.readableIdentifier(requestShortener)}`) - .join('\n')}`, - ), - ); - } - usedModules.add(fallbackModule); - } - } - } else { + const fallbackModule = bestMatch.pop(); + compilation.warnings.push( + new Error( + `chunk ${chunk.name || + chunk.id} [extract-css-chunks-plugin]\n` + + 'Conflicting order between:\n' + + ` * ${fallbackModule.readableIdentifier( + requestShortener + )}\n` + + `${bestMatchDeps + .map( + (m) => + ` * ${m.readableIdentifier( + requestShortener + )}` + ) + .join('\n')}` + ) + ); + usedModules.add(fallbackModule); + } + } + } else { // fallback for older webpack versions // (to avoid a breaking change) // TODO remove this in next mayor version // and increase minimum webpack version to 4.12.0 - modules.sort((a, b) => a.index2 - b.index2); - usedModules = modules; - } - const source = new ConcatSource(); - const externalsSource = new ConcatSource(); - for (const m of usedModules) { - if (/^@import url/.test(m.content)) { + modules.sort((a, b) => a.index2 - b.index2); + usedModules = modules; + } + const source = new ConcatSource(); + const externalsSource = new ConcatSource(); + for (const m of usedModules) { + if (/^@import url/.test(m.content)) { // HACK for IE // http://stackoverflow.com/a/14676665/1458162 - let { content } = m; - if (m.media) { + let { content } = m; + if (m.media) { // insert media into the @import // this is rar // TODO improve this and parse the CSS to support multiple medias - content = content.replace(/;|\s*$/, m.media); - } - externalsSource.add(content); - externalsSource.add('\n'); - } else { - if (m.media) { - source.add(`@media ${m.media} {\n`); - } - if (m.sourceMap) { - source.add( + content = content.replace(/;|\s*$/, m.media); + } + externalsSource.add(content); + externalsSource.add('\n'); + } else { + if (m.media) { + source.add(`@media ${m.media} {\n`); + } + if (m.sourceMap) { + source.add( new SourceMapSource( m.content, m.readableIdentifier(requestShortener), - m.sourceMap, - ), + m.sourceMap + ) ); - } else { - source.add( + } else { + source.add( new OriginalSource( m.content, - m.readableIdentifier(requestShortener), - ), + m.readableIdentifier(requestShortener) + ) ); + } + source.add('\n'); + if (m.media) { + source.add('}\n'); + } + } } - source.add('\n'); - if (m.media) { - source.add('}\n'); - } - } + return new ConcatSource(externalsSource, source); } - return new ConcatSource(externalsSource, source); - } } ExtractCssChunks.loader = require.resolve('./loader'); diff --git a/src/loader.js b/src/loader.js index f5d0b97d..94627edd 100644 --- a/src/loader.js +++ b/src/loader.js @@ -11,127 +11,130 @@ const MODULE_TYPE = 'css/extract-chunks'; const pluginName = 'extract-css-chunks-webpack-plugin'; const exec = (loaderContext, code, filename) => { - const module = new NativeModule(filename, loaderContext); - // eslint-disable-line no-underscore-dangle - module.paths = NativeModule._nodeModulePaths(loaderContext.context); - module.filename = filename; - module._compile(code, filename); // eslint-disable-line no-underscore-dangle - return module.exports; + const module = new NativeModule(filename, loaderContext); + module.paths = NativeModule._nodeModulePaths(loaderContext.context); // eslint-disable-line no-underscore-dangle + module.filename = filename; + module._compile(code, filename); // eslint-disable-line no-underscore-dangle + return module.exports; }; const findModuleById = (modules, id) => { - for (const module of modules) { - if (module.id === id) { - return module; + for (const module of modules) { + if (module.id === id) { + return module; + } } - } - return null; + return null; }; export function pitch(request) { - const query = loaderUtils.getOptions(this) || {}; - const loaders = this.loaders.slice(this.loaderIndex + 1); - this.addDependency(this.resourcePath); - const childFilename = '*'; // eslint-disable-line no-path-concat - const publicPath = + const query = loaderUtils.getOptions(this) || {}; + const loaders = this.loaders.slice(this.loaderIndex + 1); + this.addDependency(this.resourcePath); + const childFilename = '*'; // eslint-disable-line no-path-concat + const publicPath = typeof query.publicPath === 'string' ? query.publicPath : this._compilation.outputOptions.publicPath; - const outputOptions = { - filename: childFilename, - publicPath, - }; - const childCompiler = this._compilation.createChildCompiler( + const outputOptions = { + filename: childFilename, + publicPath, + }; + const childCompiler = this._compilation.createChildCompiler( `${pluginName} ${request}`, - outputOptions, + outputOptions ); - new NodeTemplatePlugin(outputOptions).apply(childCompiler); - new LibraryTemplatePlugin(null, 'commonjs2').apply(childCompiler); - new NodeTargetPlugin().apply(childCompiler); - new SingleEntryPlugin(this.context, `!!${request}`, pluginName).apply( - childCompiler, + new NodeTemplatePlugin(outputOptions).apply(childCompiler); + new LibraryTemplatePlugin(null, 'commonjs2').apply(childCompiler); + new NodeTargetPlugin().apply(childCompiler); + new SingleEntryPlugin(this.context, `!!${request}`, pluginName).apply( + childCompiler ); - new LimitChunkCountPlugin({ maxChunks: 1 }).apply(childCompiler); + new LimitChunkCountPlugin({ maxChunks: 1 }).apply(childCompiler); // We set loaderContext[MODULE_TYPE] = false to indicate we already in // a child compiler so we don't spawn another child compilers from there. - childCompiler.hooks.thisCompilation.tap( + childCompiler.hooks.thisCompilation.tap( `${pluginName} loader`, (compilation) => { - compilation.hooks.normalModuleLoader.tap( + compilation.hooks.normalModuleLoader.tap( `${pluginName} loader`, (loaderContext, module) => { - loaderContext[MODULE_TYPE] = false; // eslint-disable-line no-param-reassign - if (module.request === request) { + loaderContext[MODULE_TYPE] = false; // eslint-disable-line no-param-reassign + if (module.request === request) { // eslint-disable-next-line no-param-reassign - module.loaders = loaders.map(loader => ({ - loader: loader.path, - options: loader.options, - ident: loader.ident, - })); - } - }, + module.loaders = loaders.map((loader) => { + return { + loader: loader.path, + options: loader.options, + ident: loader.ident, + }; + }); + } + } ); - }, + } ); - let source; - childCompiler.hooks.afterCompile.tap(pluginName, (compilation) => { - source = + let source; + childCompiler.hooks.afterCompile.tap(pluginName, (compilation) => { + source = compilation.assets[childFilename] && compilation.assets[childFilename].source(); // Remove all chunk assets - compilation.chunks.forEach((chunk) => { - chunk.files.forEach((file) => { - delete compilation.assets[file]; // eslint-disable-line no-param-reassign - }); + compilation.chunks.forEach((chunk) => { + chunk.files.forEach((file) => { + delete compilation.assets[file]; // eslint-disable-line no-param-reassign + }); + }); }); - }); - const callback = this.async(); - childCompiler.runAsChild((err, entries, compilation) => { - if (err) return callback(err); + const callback = this.async(); + childCompiler.runAsChild((err, entries, compilation) => { + if (err) return callback(err); - if (compilation.errors.length > 0) { - return callback(compilation.errors[0]); - } - compilation.fileDependencies.forEach((dep) => { - this.addDependency(dep); - }, this); - compilation.contextDependencies.forEach((dep) => { - this.addContextDependency(dep); - }, this); - if (!source) { - return callback(new Error("Didn't get a result from child compiler")); - } - let text; - let locals; - try { - text = exec(this, source, request); - locals = text && text.locals; - if (!Array.isArray(text)) { - text = [[null, text]]; - } else { - text = text.map((line) => { - const module = findModuleById(compilation.modules, line[0]); - return { - identifier: module.identifier(), - content: line[1], - media: line[2], - sourceMap: line[3], - }; - }); - } - this[MODULE_TYPE](text); - } catch (e) { - return callback(e); - } - let resultSource = `// extracted by ${pluginName}`; - if (locals && typeof resultSource !== 'undefined') { - resultSource += `\nmodule.exports = ${JSON.stringify(locals)};`; - } + if (compilation.errors.length > 0) { + return callback(compilation.errors[0]); + } + compilation.fileDependencies.forEach((dep) => { + this.addDependency(dep); + }, this); + compilation.contextDependencies.forEach((dep) => { + this.addContextDependency(dep); + }, this); + if (!source) { + return callback( + new Error("Didn't get a result from child compiler") + ); + } + let text; + let locals; + try { + text = exec(this, source, request); + locals = text && text.locals; + if (!Array.isArray(text)) { + text = [[null, text]]; + } else { + text = text.map((line) => { + const module = findModuleById(compilation.modules, line[0]); + return { + identifier: module.identifier(), + content: line[1], + media: line[2], + sourceMap: line[3], + }; + }); + } + this[MODULE_TYPE](text); + } catch (e) { + return callback(e); + } + let resultSource = `// extracted by ${pluginName}`; + if (locals && typeof resultSource !== 'undefined') { + resultSource += `\nmodule.exports = ${JSON.stringify(locals)};`; + } - return callback(null, resultSource); - }); + return callback(null, resultSource); + }); } -export default function () {} +export default function() {} From 354b48f7a811a364183adaf655d9c63e2ba78500 Mon Sep 17 00:00:00 2001 From: zackjackson Date: Sat, 22 Dec 2018 23:20:34 -0800 Subject: [PATCH 2/4] test: adding and fixing broken tests Following webpack here and getting my tests passing again --- test/TestCases.test.js | 54 ++++++++++++++++--- test/TestMemoryFS.test.js | 40 ++++++++++++++ test/cases/at-import/a.css | 9 ++++ test/cases/at-import/aa.css | 3 ++ test/cases/at-import/ab.css | 3 ++ test/cases/at-import/ac.css | 3 ++ test/cases/at-import/ad.css | 3 ++ test/cases/at-import/ae.css | 3 ++ test/cases/at-import/b.css | 6 +++ test/cases/at-import/ba.css | 3 ++ test/cases/at-import/bb.css | 3 ++ test/cases/at-import/expected/main.css | 36 +++++++++++++ test/cases/at-import/index.js | 2 + test/cases/at-import/webpack.config.js | 21 ++++++++ test/cases/composes-async/expected/1.css | 4 +- test/cases/composes-async/expected/2.css | 4 ++ test/cases/composes-async/webpack.config.js | 14 ++--- .../contenthash-multiple-entries/entryA.js | 2 + .../contenthash-multiple-entries/entryB.js | 1 + .../contenthash-multiple-entries/entryC.js | 0 .../contenthash-multiple-entries/entryD.js | 2 + .../contenthash-multiple-entries/entryE.js | 2 + .../expected/10adcc6fa8f8a3cf8d8d.css | 4 ++ .../expected/3023a4e1067adc5b1950.css | 2 + .../contenthash-multiple-entries/styleA.css | 1 + .../contenthash-multiple-entries/styleB.css | 1 + .../contenthash-multiple-entries/styleC.css | 1 + .../contenthash-multiple-entries/styleD.css | 1 + .../webpack.config.js | 30 +++++++++++ .../expected/1.main.e0d1c5b21d098a0a371f.css | 2 + .../expected/2.main.9728193f8673cfdafd0e.css | 2 + test/cases/contenthash/index.js | 2 +- test/cases/contenthash/webpack.config.js | 6 +-- test/cases/css-import/a.css | 1 + test/cases/css-import/b.css | 5 ++ test/cases/css-import/c.css | 5 ++ test/cases/css-import/expected/main.css | 14 +++++ test/cases/css-import/index.css | 2 + test/cases/css-import/webpack.config.js | 21 ++++++++ ...76e1512072d65b9db.35ee3780b5b76904cef5.css | 1 + .../expected/style.25d094fb4a6ef6ef0222.js | 10 ++++ ...a674590ef68e758b3.ca7d26e87c697b1c7039.css | 1 + test/cases/js-hash/loader.js | 4 +- test/cases/js-hash/webpack.config.js | 10 ++-- test/cases/multiple-entry/a.css | 1 + test/cases/multiple-entry/async-one.js | 2 + test/cases/multiple-entry/async-two.js | 2 + test/cases/multiple-entry/b.css | 1 + test/cases/multiple-entry/c.css | 1 + test/cases/multiple-entry/d.css | 1 + .../multiple-entry/expected/async-one.css | 4 ++ .../multiple-entry/expected/async-two.css | 4 ++ .../multiple-entry/expected/main-one.css | 4 ++ .../multiple-entry/expected/main-two.css | 4 ++ test/cases/multiple-entry/index-one.js | 3 ++ test/cases/multiple-entry/index-two.js | 3 ++ test/cases/multiple-entry/webpack.config.js | 24 +++++++++ test/cases/shared-import/index.js | 2 +- .../simple-async-load-css-fallback/a.css | 1 + .../async-one.js | 2 + .../async-two.js | 2 + .../simple-async-load-css-fallback/b.css | 1 + .../simple-async-load-css-fallback/c.css | 1 + .../simple-async-load-css-fallback/d.css | 1 + .../simple-async-load-css-fallback/e.css | 1 + .../expected/async-one.css | 4 ++ .../expected/async-two.css | 4 ++ .../expected/main.css | 4 ++ .../simple-async-load-css-fallback/f.css | 1 + .../simple-async-load-css-fallback/index.js | 5 ++ .../webpack.config.js | 33 ++++++++++++ test/cases/simple-async-load-css/a.css | 1 + test/cases/simple-async-load-css/async-one.js | 2 + test/cases/simple-async-load-css/async-two.js | 2 + test/cases/simple-async-load-css/b.css | 1 + test/cases/simple-async-load-css/c.css | 1 + test/cases/simple-async-load-css/d.css | 1 + test/cases/simple-async-load-css/e.css | 1 + .../expected/async-one.css | 4 ++ .../expected/async-two.css | 4 ++ .../simple-async-load-css/expected/main.css | 4 ++ test/cases/simple-async-load-css/f.css | 1 + test/cases/simple-async-load-css/index.js | 5 ++ .../simple-async-load-css/webpack.config.js | 23 ++++++++ .../cases/simple-publicpath/expected/main.css | 2 + test/cases/simple-publicpath/index.js | 1 + test/cases/simple-publicpath/react.svg | 1 + test/cases/simple-publicpath/style.css | 1 + .../cases/simple-publicpath/webpack.config.js | 34 ++++++++++++ test/cases/source-map/expected/main.css | 4 ++ test/cases/source-map/index.js | 1 + test/cases/source-map/style.css | 1 + test/cases/source-map/webpack.config.js | 32 +++++++++++ test/cases/split-chunks-single/a.css | 1 + test/cases/split-chunks-single/b.css | 1 + test/cases/split-chunks-single/c.css | 1 + test/cases/split-chunks-single/chunk1.js | 2 + test/cases/split-chunks-single/chunk2.js | 2 + test/cases/split-chunks-single/d.css | 1 + test/cases/split-chunks-single/e1.css | 1 + test/cases/split-chunks-single/e2.css | 1 + test/cases/split-chunks-single/entry1.js | 6 +++ test/cases/split-chunks-single/entry2.js | 5 ++ .../split-chunks-single/expected/styles.css | 18 +++++++ test/cases/split-chunks-single/f.css | 1 + test/cases/split-chunks-single/g.css | 1 + test/cases/split-chunks-single/h.css | 1 + test/cases/split-chunks-single/style.css | 1 + .../split-chunks-single/webpack.config.js | 36 +++++++++++++ test/cases/split-chunks/index.js | 1 - test/cases/split-chunks/webpack.config.js | 8 +-- test/manual/index.html | 15 ++++-- test/manual/src/crossorigin.css | 3 ++ test/manual/src/crossorigin.js | 1 + test/manual/src/index.js | 40 ++++++++++---- test/manual/src/initial.css | 1 - test/manual/src/lazy-failure.css | 3 ++ test/manual/src/lazy-failure.js | 1 + test/manual/src/preloaded1.js | 2 +- test/manual/src/preloaded2.js | 2 +- test/manual/webpack.config.js | 23 +++----- 121 files changed, 700 insertions(+), 66 deletions(-) create mode 100644 test/TestMemoryFS.test.js create mode 100644 test/cases/at-import/a.css create mode 100644 test/cases/at-import/aa.css create mode 100644 test/cases/at-import/ab.css create mode 100644 test/cases/at-import/ac.css create mode 100644 test/cases/at-import/ad.css create mode 100644 test/cases/at-import/ae.css create mode 100644 test/cases/at-import/b.css create mode 100644 test/cases/at-import/ba.css create mode 100644 test/cases/at-import/bb.css create mode 100644 test/cases/at-import/expected/main.css create mode 100644 test/cases/at-import/index.js create mode 100644 test/cases/at-import/webpack.config.js create mode 100644 test/cases/composes-async/expected/2.css create mode 100644 test/cases/contenthash-multiple-entries/entryA.js create mode 100644 test/cases/contenthash-multiple-entries/entryB.js create mode 100644 test/cases/contenthash-multiple-entries/entryC.js create mode 100644 test/cases/contenthash-multiple-entries/entryD.js create mode 100644 test/cases/contenthash-multiple-entries/entryE.js create mode 100644 test/cases/contenthash-multiple-entries/expected/10adcc6fa8f8a3cf8d8d.css create mode 100644 test/cases/contenthash-multiple-entries/expected/3023a4e1067adc5b1950.css create mode 100644 test/cases/contenthash-multiple-entries/styleA.css create mode 100644 test/cases/contenthash-multiple-entries/styleB.css create mode 100644 test/cases/contenthash-multiple-entries/styleC.css create mode 100644 test/cases/contenthash-multiple-entries/styleD.css create mode 100644 test/cases/contenthash-multiple-entries/webpack.config.js create mode 100644 test/cases/contenthash/expected/1.main.e0d1c5b21d098a0a371f.css create mode 100644 test/cases/contenthash/expected/2.main.9728193f8673cfdafd0e.css create mode 100644 test/cases/css-import/a.css create mode 100644 test/cases/css-import/b.css create mode 100644 test/cases/css-import/c.css create mode 100644 test/cases/css-import/expected/main.css create mode 100644 test/cases/css-import/index.css create mode 100644 test/cases/css-import/webpack.config.js create mode 100644 test/cases/js-hash/expected/style.11a76e1512072d65b9db.35ee3780b5b76904cef5.css create mode 100644 test/cases/js-hash/expected/style.25d094fb4a6ef6ef0222.js create mode 100644 test/cases/js-hash/expected/style.822a674590ef68e758b3.ca7d26e87c697b1c7039.css create mode 100644 test/cases/multiple-entry/a.css create mode 100644 test/cases/multiple-entry/async-one.js create mode 100644 test/cases/multiple-entry/async-two.js create mode 100644 test/cases/multiple-entry/b.css create mode 100644 test/cases/multiple-entry/c.css create mode 100644 test/cases/multiple-entry/d.css create mode 100644 test/cases/multiple-entry/expected/async-one.css create mode 100644 test/cases/multiple-entry/expected/async-two.css create mode 100644 test/cases/multiple-entry/expected/main-one.css create mode 100644 test/cases/multiple-entry/expected/main-two.css create mode 100644 test/cases/multiple-entry/index-one.js create mode 100644 test/cases/multiple-entry/index-two.js create mode 100644 test/cases/multiple-entry/webpack.config.js create mode 100644 test/cases/simple-async-load-css-fallback/a.css create mode 100644 test/cases/simple-async-load-css-fallback/async-one.js create mode 100644 test/cases/simple-async-load-css-fallback/async-two.js create mode 100644 test/cases/simple-async-load-css-fallback/b.css create mode 100644 test/cases/simple-async-load-css-fallback/c.css create mode 100644 test/cases/simple-async-load-css-fallback/d.css create mode 100644 test/cases/simple-async-load-css-fallback/e.css create mode 100644 test/cases/simple-async-load-css-fallback/expected/async-one.css create mode 100644 test/cases/simple-async-load-css-fallback/expected/async-two.css create mode 100644 test/cases/simple-async-load-css-fallback/expected/main.css create mode 100644 test/cases/simple-async-load-css-fallback/f.css create mode 100644 test/cases/simple-async-load-css-fallback/index.js create mode 100644 test/cases/simple-async-load-css-fallback/webpack.config.js create mode 100644 test/cases/simple-async-load-css/a.css create mode 100644 test/cases/simple-async-load-css/async-one.js create mode 100644 test/cases/simple-async-load-css/async-two.js create mode 100644 test/cases/simple-async-load-css/b.css create mode 100644 test/cases/simple-async-load-css/c.css create mode 100644 test/cases/simple-async-load-css/d.css create mode 100644 test/cases/simple-async-load-css/e.css create mode 100644 test/cases/simple-async-load-css/expected/async-one.css create mode 100644 test/cases/simple-async-load-css/expected/async-two.css create mode 100644 test/cases/simple-async-load-css/expected/main.css create mode 100644 test/cases/simple-async-load-css/f.css create mode 100644 test/cases/simple-async-load-css/index.js create mode 100644 test/cases/simple-async-load-css/webpack.config.js create mode 100644 test/cases/simple-publicpath/expected/main.css create mode 100644 test/cases/simple-publicpath/index.js create mode 100644 test/cases/simple-publicpath/react.svg create mode 100644 test/cases/simple-publicpath/style.css create mode 100644 test/cases/simple-publicpath/webpack.config.js create mode 100644 test/cases/source-map/expected/main.css create mode 100644 test/cases/source-map/index.js create mode 100644 test/cases/source-map/style.css create mode 100644 test/cases/source-map/webpack.config.js create mode 100644 test/cases/split-chunks-single/a.css create mode 100644 test/cases/split-chunks-single/b.css create mode 100644 test/cases/split-chunks-single/c.css create mode 100644 test/cases/split-chunks-single/chunk1.js create mode 100644 test/cases/split-chunks-single/chunk2.js create mode 100644 test/cases/split-chunks-single/d.css create mode 100644 test/cases/split-chunks-single/e1.css create mode 100644 test/cases/split-chunks-single/e2.css create mode 100644 test/cases/split-chunks-single/entry1.js create mode 100644 test/cases/split-chunks-single/entry2.js create mode 100644 test/cases/split-chunks-single/expected/styles.css create mode 100644 test/cases/split-chunks-single/f.css create mode 100644 test/cases/split-chunks-single/g.css create mode 100644 test/cases/split-chunks-single/h.css create mode 100644 test/cases/split-chunks-single/style.css create mode 100644 test/cases/split-chunks-single/webpack.config.js create mode 100644 test/manual/src/crossorigin.css create mode 100644 test/manual/src/crossorigin.js create mode 100644 test/manual/src/lazy-failure.css create mode 100644 test/manual/src/lazy-failure.js diff --git a/test/TestCases.test.js b/test/TestCases.test.js index 4a133bc1..ee4cd52c 100644 --- a/test/TestCases.test.js +++ b/test/TestCases.test.js @@ -1,7 +1,6 @@ -/* eslint-disable no-restricted-syntax, import/no-dynamic-require, global-require, - no-console, no-undef, no-loop-func */ import fs from 'fs'; import path from 'path'; + import webpack from 'webpack'; describe('TestCases', () => { @@ -9,12 +8,30 @@ describe('TestCases', () => { const outputDirectory = path.resolve(__dirname, 'js'); for (const directory of fs.readdirSync(casesDirectory)) { if (!/^(\.|_)/.test(directory)) { + // eslint-disable-next-line no-loop-func it(`${directory} should compile to the expected result`, (done) => { const directoryForCase = path.resolve(casesDirectory, directory); const outputDirectoryForCase = path.resolve(outputDirectory, directory); - const webpackConfig = require(path.resolve(directoryForCase, 'webpack.config.js')); + // eslint-disable-next-line import/no-dynamic-require, global-require + const webpackConfig = require(path.resolve( + directoryForCase, + 'webpack.config.js' + )); for (const config of [].concat(webpackConfig)) { - Object.assign(config, { mode: 'none', context: directoryForCase, output: Object.assign({ path: outputDirectoryForCase }, config.output) }, config); + Object.assign( + config, + { + mode: 'none', + context: directoryForCase, + output: Object.assign( + { + path: outputDirectoryForCase, + }, + config.output + ), + }, + config + ); } webpack(webpackConfig, (err, stats) => { if (err) { @@ -22,15 +39,36 @@ describe('TestCases', () => { return; } done(); - console.log(stats.toString({ context: path.resolve(__dirname, '..'), chunks: true, chunkModules: true, modules: false })); + // eslint-disable-next-line no-console + console.log( + stats.toString({ + context: path.resolve(__dirname, '..'), + chunks: true, + chunkModules: true, + modules: false, + }) + ); if (stats.hasErrors()) { - done(new Error(stats.toString({ context: path.resolve(__dirname, '..'), errorDetails: true }))); + done( + new Error( + stats.toString({ + context: path.resolve(__dirname, '..'), + errorDetails: true, + }) + ) + ); return; } const expectedDirectory = path.resolve(directoryForCase, 'expected'); for (const file of fs.readdirSync(expectedDirectory)) { - const content = fs.readFileSync(path.resolve(expectedDirectory, file), 'utf-8'); - const actualContent = fs.readFileSync(path.resolve(outputDirectoryForCase, file), 'utf-8'); + const content = fs.readFileSync( + path.resolve(expectedDirectory, file), + 'utf-8' + ); + const actualContent = fs.readFileSync( + path.resolve(outputDirectoryForCase, file), + 'utf-8' + ); expect(actualContent).toEqual(content); } done(); diff --git a/test/TestMemoryFS.test.js b/test/TestMemoryFS.test.js new file mode 100644 index 00000000..635b2aef --- /dev/null +++ b/test/TestMemoryFS.test.js @@ -0,0 +1,40 @@ +import path from 'path'; + +import MemoryFS from 'memory-fs'; +import webpack from 'webpack'; + +const assetsNames = (json) => json.assets.map((asset) => asset.name); + +describe('TestMemoryFS', () => { + it('should preserve asset even if not emitted', (done) => { + const casesDirectory = path.resolve(__dirname, 'cases'); + const directoryForCase = path.resolve(casesDirectory, 'simple-publicpath'); + const webpackConfig = require(path.resolve( + directoryForCase, + 'webpack.config.js' + )); + const compiler = webpack({ + ...webpackConfig, + mode: 'development', + context: directoryForCase, + cache: false, + }); + compiler.outputFileSystem = new MemoryFS(); + compiler.run((err1, stats1) => { + if (err1) { + done(err1); + return; + } + compiler.run((err2, stats2) => { + if (err2) { + done(err2); + return; + } + expect(assetsNames(stats1.toJson())).toEqual( + assetsNames(stats2.toJson()) + ); + done(); + }); + }); + }); +}); diff --git a/test/cases/at-import/a.css b/test/cases/at-import/a.css new file mode 100644 index 00000000..34ce1e9c --- /dev/null +++ b/test/cases/at-import/a.css @@ -0,0 +1,9 @@ +@import './ae.css'; +@import './aa.css'; +@import './ab.css'; +@import './ac.css'; +@import './ad.css'; + +body { + background: red; +} diff --git a/test/cases/at-import/aa.css b/test/cases/at-import/aa.css new file mode 100644 index 00000000..9ad34057 --- /dev/null +++ b/test/cases/at-import/aa.css @@ -0,0 +1,3 @@ +.aa { + background: green; +} diff --git a/test/cases/at-import/ab.css b/test/cases/at-import/ab.css new file mode 100644 index 00000000..a57f2508 --- /dev/null +++ b/test/cases/at-import/ab.css @@ -0,0 +1,3 @@ +.ab { + background: green; +} diff --git a/test/cases/at-import/ac.css b/test/cases/at-import/ac.css new file mode 100644 index 00000000..356d5138 --- /dev/null +++ b/test/cases/at-import/ac.css @@ -0,0 +1,3 @@ +.ac { + background: green; +} diff --git a/test/cases/at-import/ad.css b/test/cases/at-import/ad.css new file mode 100644 index 00000000..1323e35d --- /dev/null +++ b/test/cases/at-import/ad.css @@ -0,0 +1,3 @@ +.ad { + background: green; +} diff --git a/test/cases/at-import/ae.css b/test/cases/at-import/ae.css new file mode 100644 index 00000000..5eca6b0e --- /dev/null +++ b/test/cases/at-import/ae.css @@ -0,0 +1,3 @@ +.ae { + background: green; +} diff --git a/test/cases/at-import/b.css b/test/cases/at-import/b.css new file mode 100644 index 00000000..e300b655 --- /dev/null +++ b/test/cases/at-import/b.css @@ -0,0 +1,6 @@ +@import './ba.css'; +@import './bb.css'; + +body { + background: yellow; +} diff --git a/test/cases/at-import/ba.css b/test/cases/at-import/ba.css new file mode 100644 index 00000000..adb84dbe --- /dev/null +++ b/test/cases/at-import/ba.css @@ -0,0 +1,3 @@ +.ba { + background: green; +} diff --git a/test/cases/at-import/bb.css b/test/cases/at-import/bb.css new file mode 100644 index 00000000..1e09c7ac --- /dev/null +++ b/test/cases/at-import/bb.css @@ -0,0 +1,3 @@ +.bb { + background: green; +} diff --git a/test/cases/at-import/expected/main.css b/test/cases/at-import/expected/main.css new file mode 100644 index 00000000..eb4811b4 --- /dev/null +++ b/test/cases/at-import/expected/main.css @@ -0,0 +1,36 @@ +.ae { + background: green; +} + +.aa { + background: green; +} + +.ab { + background: green; +} + +.ac { + background: green; +} + +.ad { + background: green; +} + +body { + background: red; +} + +.ba { + background: green; +} + +.bb { + background: green; +} + +body { + background: yellow; +} + diff --git a/test/cases/at-import/index.js b/test/cases/at-import/index.js new file mode 100644 index 00000000..a0ec7954 --- /dev/null +++ b/test/cases/at-import/index.js @@ -0,0 +1,2 @@ +import './a.css'; +import './b.css'; diff --git a/test/cases/at-import/webpack.config.js b/test/cases/at-import/webpack.config.js new file mode 100644 index 00000000..a22ebdad --- /dev/null +++ b/test/cases/at-import/webpack.config.js @@ -0,0 +1,21 @@ +const Self = require('../../../'); + +module.exports = { + entry: './index.js', + module: { + rules: [ + { + test: /\.css$/, + use: [ + Self.loader, + 'css-loader', + ], + }, + ], + }, + plugins: [ + new Self({ + filename: '[name].css', + }), + ], +}; diff --git a/test/cases/composes-async/expected/1.css b/test/cases/composes-async/expected/1.css index 2fa9e2cb..23f2a9f7 100644 --- a/test/cases/composes-async/expected/1.css +++ b/test/cases/composes-async/expected/1.css @@ -1,4 +1,4 @@ -.base { - background: blue; +.composed { + background: green; } diff --git a/test/cases/composes-async/expected/2.css b/test/cases/composes-async/expected/2.css new file mode 100644 index 00000000..2fa9e2cb --- /dev/null +++ b/test/cases/composes-async/expected/2.css @@ -0,0 +1,4 @@ +.base { + background: blue; +} + diff --git a/test/cases/composes-async/webpack.config.js b/test/cases/composes-async/webpack.config.js index 33c90863..ef38e7f6 100644 --- a/test/cases/composes-async/webpack.config.js +++ b/test/cases/composes-async/webpack.config.js @@ -11,9 +11,9 @@ module.exports = { { loader: 'css-loader', options: { - localIdentName: '[local]', - }, - }, + localIdentName: '[local]' + } + } ], }, ], @@ -25,10 +25,10 @@ module.exports = { test: /\.css$/, chunks: 'all', minChunks: 2, - enforce: true, - }, - }, - }, + enforce: true + } + } + } }, plugins: [ new Self({ diff --git a/test/cases/contenthash-multiple-entries/entryA.js b/test/cases/contenthash-multiple-entries/entryA.js new file mode 100644 index 00000000..c1845fd4 --- /dev/null +++ b/test/cases/contenthash-multiple-entries/entryA.js @@ -0,0 +1,2 @@ +import "./styleA.css"; +import "./styleB.css"; diff --git a/test/cases/contenthash-multiple-entries/entryB.js b/test/cases/contenthash-multiple-entries/entryB.js new file mode 100644 index 00000000..e5558621 --- /dev/null +++ b/test/cases/contenthash-multiple-entries/entryB.js @@ -0,0 +1 @@ +import "./styleA.css"; diff --git a/test/cases/contenthash-multiple-entries/entryC.js b/test/cases/contenthash-multiple-entries/entryC.js new file mode 100644 index 00000000..e69de29b diff --git a/test/cases/contenthash-multiple-entries/entryD.js b/test/cases/contenthash-multiple-entries/entryD.js new file mode 100644 index 00000000..c1845fd4 --- /dev/null +++ b/test/cases/contenthash-multiple-entries/entryD.js @@ -0,0 +1,2 @@ +import "./styleA.css"; +import "./styleB.css"; diff --git a/test/cases/contenthash-multiple-entries/entryE.js b/test/cases/contenthash-multiple-entries/entryE.js new file mode 100644 index 00000000..11bc2609 --- /dev/null +++ b/test/cases/contenthash-multiple-entries/entryE.js @@ -0,0 +1,2 @@ +import "./styleC.css"; +import "./styleD.css"; diff --git a/test/cases/contenthash-multiple-entries/expected/10adcc6fa8f8a3cf8d8d.css b/test/cases/contenthash-multiple-entries/expected/10adcc6fa8f8a3cf8d8d.css new file mode 100644 index 00000000..7dad92ee --- /dev/null +++ b/test/cases/contenthash-multiple-entries/expected/10adcc6fa8f8a3cf8d8d.css @@ -0,0 +1,4 @@ +.styleA { background: red; } + +.styleB { background: blue; } + diff --git a/test/cases/contenthash-multiple-entries/expected/3023a4e1067adc5b1950.css b/test/cases/contenthash-multiple-entries/expected/3023a4e1067adc5b1950.css new file mode 100644 index 00000000..f9171ff1 --- /dev/null +++ b/test/cases/contenthash-multiple-entries/expected/3023a4e1067adc5b1950.css @@ -0,0 +1,2 @@ +.styleA { background: red; } + diff --git a/test/cases/contenthash-multiple-entries/styleA.css b/test/cases/contenthash-multiple-entries/styleA.css new file mode 100644 index 00000000..84a728d8 --- /dev/null +++ b/test/cases/contenthash-multiple-entries/styleA.css @@ -0,0 +1 @@ +.styleA { background: red; } diff --git a/test/cases/contenthash-multiple-entries/styleB.css b/test/cases/contenthash-multiple-entries/styleB.css new file mode 100644 index 00000000..3662427b --- /dev/null +++ b/test/cases/contenthash-multiple-entries/styleB.css @@ -0,0 +1 @@ +.styleB { background: blue; } diff --git a/test/cases/contenthash-multiple-entries/styleC.css b/test/cases/contenthash-multiple-entries/styleC.css new file mode 100644 index 00000000..84a728d8 --- /dev/null +++ b/test/cases/contenthash-multiple-entries/styleC.css @@ -0,0 +1 @@ +.styleA { background: red; } diff --git a/test/cases/contenthash-multiple-entries/styleD.css b/test/cases/contenthash-multiple-entries/styleD.css new file mode 100644 index 00000000..3662427b --- /dev/null +++ b/test/cases/contenthash-multiple-entries/styleD.css @@ -0,0 +1 @@ +.styleB { background: blue; } diff --git a/test/cases/contenthash-multiple-entries/webpack.config.js b/test/cases/contenthash-multiple-entries/webpack.config.js new file mode 100644 index 00000000..6ea382fc --- /dev/null +++ b/test/cases/contenthash-multiple-entries/webpack.config.js @@ -0,0 +1,30 @@ +const Self = require('../../../'); + +module.exports = { + entry: { + 'entryA': './entryA.js', + 'entryB': './entryB.js', + 'entryC': './entryC.js', + 'entryD': './entryD.js', + 'entryE': './entryE.js', + }, + module: { + rules: [ + { + test: /\.css$/, + use: [ + Self.loader, + 'css-loader', + ], + }, + ], + }, + output: { + filename: '[name]-[contenthash].js', + }, + plugins: [ + new Self({ + filename: '[contenthash].css', + }), + ], +}; diff --git a/test/cases/contenthash/expected/1.main.e0d1c5b21d098a0a371f.css b/test/cases/contenthash/expected/1.main.e0d1c5b21d098a0a371f.css new file mode 100644 index 00000000..aea53e43 --- /dev/null +++ b/test/cases/contenthash/expected/1.main.e0d1c5b21d098a0a371f.css @@ -0,0 +1,2 @@ +body { background: red; } + diff --git a/test/cases/contenthash/expected/2.main.9728193f8673cfdafd0e.css b/test/cases/contenthash/expected/2.main.9728193f8673cfdafd0e.css new file mode 100644 index 00000000..1a6052d7 --- /dev/null +++ b/test/cases/contenthash/expected/2.main.9728193f8673cfdafd0e.css @@ -0,0 +1,2 @@ +body { background: green; } + diff --git a/test/cases/contenthash/index.js b/test/cases/contenthash/index.js index 4ec1281a..aa3357bf 100644 --- a/test/cases/contenthash/index.js +++ b/test/cases/contenthash/index.js @@ -1 +1 @@ -import './style.css'; // eslint-disable-line import/no-unresolved +import './style.css'; diff --git a/test/cases/contenthash/webpack.config.js b/test/cases/contenthash/webpack.config.js index 67560582..213bcc8d 100644 --- a/test/cases/contenthash/webpack.config.js +++ b/test/cases/contenthash/webpack.config.js @@ -14,12 +14,12 @@ module.exports = [1, 2].map(n => ({ ], }, output: { - filename: `${n}.[name].js`, + filename: `${n}.[name].js` }, resolve: { alias: { - './style.css': `./style${n}.css`, - }, + './style.css': `./style${n}.css` + } }, plugins: [ new Self({ diff --git a/test/cases/css-import/a.css b/test/cases/css-import/a.css new file mode 100644 index 00000000..31fc5b8a --- /dev/null +++ b/test/cases/css-import/a.css @@ -0,0 +1 @@ +body { background: red; } diff --git a/test/cases/css-import/b.css b/test/cases/css-import/b.css new file mode 100644 index 00000000..11559583 --- /dev/null +++ b/test/cases/css-import/b.css @@ -0,0 +1,5 @@ +.b { background: red; } + +@import url("https://some/external/css"); + +.b { color: yellow; } diff --git a/test/cases/css-import/c.css b/test/cases/css-import/c.css new file mode 100644 index 00000000..9c41dd1f --- /dev/null +++ b/test/cases/css-import/c.css @@ -0,0 +1,5 @@ +.c { background: red; } +@import './a.css'; +@import url("https://some/other/external/css"); + +.c { color: yellow; } diff --git a/test/cases/css-import/expected/main.css b/test/cases/css-import/expected/main.css new file mode 100644 index 00000000..cd5dacee --- /dev/null +++ b/test/cases/css-import/expected/main.css @@ -0,0 +1,14 @@ +@import url(https://some/other/external/css); +@import url(https://some/external/css); +body { background: red; } + +.c { background: red; } + +.c { color: yellow; } + +.b { background: red; } + +.b { color: yellow; } + + + diff --git a/test/cases/css-import/index.css b/test/cases/css-import/index.css new file mode 100644 index 00000000..c03e069d --- /dev/null +++ b/test/cases/css-import/index.css @@ -0,0 +1,2 @@ +@import './c.css'; +@import './b.css'; diff --git a/test/cases/css-import/webpack.config.js b/test/cases/css-import/webpack.config.js new file mode 100644 index 00000000..7442065a --- /dev/null +++ b/test/cases/css-import/webpack.config.js @@ -0,0 +1,21 @@ +const Self = require('../../../'); + +module.exports = { + entry: './index.css', + module: { + rules: [ + { + test: /\.css$/, + use: [ + Self.loader, + 'css-loader', + ], + }, + ], + }, + plugins: [ + new Self({ + filename: '[name].css', + }), + ], +}; diff --git a/test/cases/js-hash/expected/style.11a76e1512072d65b9db.35ee3780b5b76904cef5.css b/test/cases/js-hash/expected/style.11a76e1512072d65b9db.35ee3780b5b76904cef5.css new file mode 100644 index 00000000..39afb1fb --- /dev/null +++ b/test/cases/js-hash/expected/style.11a76e1512072d65b9db.35ee3780b5b76904cef5.css @@ -0,0 +1 @@ +.wX52cuPepLZcpDx5S3yYO { background: red; } diff --git a/test/cases/js-hash/expected/style.25d094fb4a6ef6ef0222.js b/test/cases/js-hash/expected/style.25d094fb4a6ef6ef0222.js new file mode 100644 index 00000000..21f472ef --- /dev/null +++ b/test/cases/js-hash/expected/style.25d094fb4a6ef6ef0222.js @@ -0,0 +1,10 @@ +(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[1],[ +/* 0 */, +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +// extracted by mini-css-extract-plugin +module.exports = {"a":"wX52cuPepLZcpDx5S3yYO"}; + +/***/ }) +]]); \ No newline at end of file diff --git a/test/cases/js-hash/expected/style.822a674590ef68e758b3.ca7d26e87c697b1c7039.css b/test/cases/js-hash/expected/style.822a674590ef68e758b3.ca7d26e87c697b1c7039.css new file mode 100644 index 00000000..f557e02c --- /dev/null +++ b/test/cases/js-hash/expected/style.822a674590ef68e758b3.ca7d26e87c697b1c7039.css @@ -0,0 +1 @@ +.wX52cuPepLZcpDx5S3yYO { background: green; } diff --git a/test/cases/js-hash/loader.js b/test/cases/js-hash/loader.js index dd2063b2..219e4f57 100644 --- a/test/cases/js-hash/loader.js +++ b/test/cases/js-hash/loader.js @@ -1,4 +1,4 @@ -module.exports = function (source) { +module.exports = function(source) { const { number } = this.query; - return source.split(/\r?\n/)[number - 1]; + return source.split(/\r?\n/)[number-1]; }; diff --git a/test/cases/js-hash/webpack.config.js b/test/cases/js-hash/webpack.config.js index 25ad2fda..de241c13 100644 --- a/test/cases/js-hash/webpack.config.js +++ b/test/cases/js-hash/webpack.config.js @@ -18,19 +18,19 @@ module.exports = [1, 2].map(n => ({ loader: './loader', ident: 'my-loader', options: { - number: n, - }, - }, + number: n + } + } ], }, ], }, output: { - filename: '[name].[contenthash].js', + filename: `[name].[contenthash].js` }, plugins: [ new Self({ - filename: '[name].[contenthash].[chunkhash].css', + filename: `[name].[contenthash].[chunkhash].css`, }), ], })); diff --git a/test/cases/multiple-entry/a.css b/test/cases/multiple-entry/a.css new file mode 100644 index 00000000..31fc5b8a --- /dev/null +++ b/test/cases/multiple-entry/a.css @@ -0,0 +1 @@ +body { background: red; } diff --git a/test/cases/multiple-entry/async-one.js b/test/cases/multiple-entry/async-one.js new file mode 100644 index 00000000..882b0824 --- /dev/null +++ b/test/cases/multiple-entry/async-one.js @@ -0,0 +1,2 @@ +import './c.css'; +import './d.css'; diff --git a/test/cases/multiple-entry/async-two.js b/test/cases/multiple-entry/async-two.js new file mode 100644 index 00000000..69733f71 --- /dev/null +++ b/test/cases/multiple-entry/async-two.js @@ -0,0 +1,2 @@ +import './d.css'; +import './c.css'; diff --git a/test/cases/multiple-entry/b.css b/test/cases/multiple-entry/b.css new file mode 100644 index 00000000..56af6df5 --- /dev/null +++ b/test/cases/multiple-entry/b.css @@ -0,0 +1 @@ +body { background: green; } diff --git a/test/cases/multiple-entry/c.css b/test/cases/multiple-entry/c.css new file mode 100644 index 00000000..4e2dfe9a --- /dev/null +++ b/test/cases/multiple-entry/c.css @@ -0,0 +1 @@ +body { background: blue; } diff --git a/test/cases/multiple-entry/d.css b/test/cases/multiple-entry/d.css new file mode 100644 index 00000000..75945584 --- /dev/null +++ b/test/cases/multiple-entry/d.css @@ -0,0 +1 @@ +body { background: yellow; } diff --git a/test/cases/multiple-entry/expected/async-one.css b/test/cases/multiple-entry/expected/async-one.css new file mode 100644 index 00000000..e28fd9a4 --- /dev/null +++ b/test/cases/multiple-entry/expected/async-one.css @@ -0,0 +1,4 @@ +body { background: blue; } + +body { background: yellow; } + diff --git a/test/cases/multiple-entry/expected/async-two.css b/test/cases/multiple-entry/expected/async-two.css new file mode 100644 index 00000000..14d2a2f0 --- /dev/null +++ b/test/cases/multiple-entry/expected/async-two.css @@ -0,0 +1,4 @@ +body { background: yellow; } + +body { background: blue; } + diff --git a/test/cases/multiple-entry/expected/main-one.css b/test/cases/multiple-entry/expected/main-one.css new file mode 100644 index 00000000..f17305d1 --- /dev/null +++ b/test/cases/multiple-entry/expected/main-one.css @@ -0,0 +1,4 @@ +body { background: red; } + +body { background: green; } + diff --git a/test/cases/multiple-entry/expected/main-two.css b/test/cases/multiple-entry/expected/main-two.css new file mode 100644 index 00000000..f49bc882 --- /dev/null +++ b/test/cases/multiple-entry/expected/main-two.css @@ -0,0 +1,4 @@ +body { background: green; } + +body { background: red; } + diff --git a/test/cases/multiple-entry/index-one.js b/test/cases/multiple-entry/index-one.js new file mode 100644 index 00000000..2a31d962 --- /dev/null +++ b/test/cases/multiple-entry/index-one.js @@ -0,0 +1,3 @@ +import './a.css'; +import './b.css'; +import(/* webpackChunkName: 'async-one' */'./async-one'); diff --git a/test/cases/multiple-entry/index-two.js b/test/cases/multiple-entry/index-two.js new file mode 100644 index 00000000..4ce48925 --- /dev/null +++ b/test/cases/multiple-entry/index-two.js @@ -0,0 +1,3 @@ +import(/* webpackChunkName: 'async-two' */'./async-two'); +import './b.css'; +import './a.css'; diff --git a/test/cases/multiple-entry/webpack.config.js b/test/cases/multiple-entry/webpack.config.js new file mode 100644 index 00000000..688637f0 --- /dev/null +++ b/test/cases/multiple-entry/webpack.config.js @@ -0,0 +1,24 @@ +const Self = require('../../../'); + +module.exports = { + entry: { + 'main-one': './index-one.js', + 'main-two': './index-two.js', + }, + module: { + rules: [ + { + test: /\.css$/, + use: [ + Self.loader, + 'css-loader', + ], + }, + ], + }, + plugins: [ + new Self({ + filename: '[name].css', + }), + ], +}; diff --git a/test/cases/shared-import/index.js b/test/cases/shared-import/index.js index b1356e18..bd92052b 100644 --- a/test/cases/shared-import/index.js +++ b/test/cases/shared-import/index.js @@ -1,4 +1,4 @@ import './a.css'; import './b.css'; -import('./c.css'); +import("./c.css"); diff --git a/test/cases/simple-async-load-css-fallback/a.css b/test/cases/simple-async-load-css-fallback/a.css new file mode 100644 index 00000000..31fc5b8a --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/a.css @@ -0,0 +1 @@ +body { background: red; } diff --git a/test/cases/simple-async-load-css-fallback/async-one.js b/test/cases/simple-async-load-css-fallback/async-one.js new file mode 100644 index 00000000..882b0824 --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/async-one.js @@ -0,0 +1,2 @@ +import './c.css'; +import './d.css'; diff --git a/test/cases/simple-async-load-css-fallback/async-two.js b/test/cases/simple-async-load-css-fallback/async-two.js new file mode 100644 index 00000000..e83f933c --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/async-two.js @@ -0,0 +1,2 @@ +import './e.css'; +import './f.css'; diff --git a/test/cases/simple-async-load-css-fallback/b.css b/test/cases/simple-async-load-css-fallback/b.css new file mode 100644 index 00000000..56af6df5 --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/b.css @@ -0,0 +1 @@ +body { background: green; } diff --git a/test/cases/simple-async-load-css-fallback/c.css b/test/cases/simple-async-load-css-fallback/c.css new file mode 100644 index 00000000..4e2dfe9a --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/c.css @@ -0,0 +1 @@ +body { background: blue; } diff --git a/test/cases/simple-async-load-css-fallback/d.css b/test/cases/simple-async-load-css-fallback/d.css new file mode 100644 index 00000000..75945584 --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/d.css @@ -0,0 +1 @@ +body { background: yellow; } diff --git a/test/cases/simple-async-load-css-fallback/e.css b/test/cases/simple-async-load-css-fallback/e.css new file mode 100644 index 00000000..484aaf18 --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/e.css @@ -0,0 +1 @@ +body { background: purple; } diff --git a/test/cases/simple-async-load-css-fallback/expected/async-one.css b/test/cases/simple-async-load-css-fallback/expected/async-one.css new file mode 100644 index 00000000..e28fd9a4 --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/expected/async-one.css @@ -0,0 +1,4 @@ +body { background: blue; } + +body { background: yellow; } + diff --git a/test/cases/simple-async-load-css-fallback/expected/async-two.css b/test/cases/simple-async-load-css-fallback/expected/async-two.css new file mode 100644 index 00000000..83c2b1a9 --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/expected/async-two.css @@ -0,0 +1,4 @@ +body { background: purple; } + +body { background: indigo; } + diff --git a/test/cases/simple-async-load-css-fallback/expected/main.css b/test/cases/simple-async-load-css-fallback/expected/main.css new file mode 100644 index 00000000..f17305d1 --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/expected/main.css @@ -0,0 +1,4 @@ +body { background: red; } + +body { background: green; } + diff --git a/test/cases/simple-async-load-css-fallback/f.css b/test/cases/simple-async-load-css-fallback/f.css new file mode 100644 index 00000000..a0f22c15 --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/f.css @@ -0,0 +1 @@ +body { background: indigo; } diff --git a/test/cases/simple-async-load-css-fallback/index.js b/test/cases/simple-async-load-css-fallback/index.js new file mode 100644 index 00000000..4a384fd0 --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/index.js @@ -0,0 +1,5 @@ +import './a.css'; +import './b.css'; +import(/* webpackChunkName: 'async-one' */'./async-one'); +import(/* webpackChunkName: 'async-two' */'./async-two'); + diff --git a/test/cases/simple-async-load-css-fallback/webpack.config.js b/test/cases/simple-async-load-css-fallback/webpack.config.js new file mode 100644 index 00000000..17dc8ead --- /dev/null +++ b/test/cases/simple-async-load-css-fallback/webpack.config.js @@ -0,0 +1,33 @@ +const Self = require('../../../'); + +module.exports = { + entry: { + 'main': './index.js', + }, + module: { + rules: [ + { + test: /\.css$/, + use: [ + Self.loader, + 'css-loader', + ], + }, + ], + }, + plugins: [ + function() { + this.hooks.compilation.tap("Test", compilation => { + compilation.hooks.beforeChunkAssets.tap("Test", () => { + for (const chunkGroup of compilation.chunkGroups) { + // remove getModuleIndex2 to enforce using fallback + chunkGroup.getModuleIndex2 = undefined; + } + }); + }) + }, + new Self({ + filename: '[name].css', + }), + ], +}; diff --git a/test/cases/simple-async-load-css/a.css b/test/cases/simple-async-load-css/a.css new file mode 100644 index 00000000..31fc5b8a --- /dev/null +++ b/test/cases/simple-async-load-css/a.css @@ -0,0 +1 @@ +body { background: red; } diff --git a/test/cases/simple-async-load-css/async-one.js b/test/cases/simple-async-load-css/async-one.js new file mode 100644 index 00000000..882b0824 --- /dev/null +++ b/test/cases/simple-async-load-css/async-one.js @@ -0,0 +1,2 @@ +import './c.css'; +import './d.css'; diff --git a/test/cases/simple-async-load-css/async-two.js b/test/cases/simple-async-load-css/async-two.js new file mode 100644 index 00000000..e83f933c --- /dev/null +++ b/test/cases/simple-async-load-css/async-two.js @@ -0,0 +1,2 @@ +import './e.css'; +import './f.css'; diff --git a/test/cases/simple-async-load-css/b.css b/test/cases/simple-async-load-css/b.css new file mode 100644 index 00000000..56af6df5 --- /dev/null +++ b/test/cases/simple-async-load-css/b.css @@ -0,0 +1 @@ +body { background: green; } diff --git a/test/cases/simple-async-load-css/c.css b/test/cases/simple-async-load-css/c.css new file mode 100644 index 00000000..4e2dfe9a --- /dev/null +++ b/test/cases/simple-async-load-css/c.css @@ -0,0 +1 @@ +body { background: blue; } diff --git a/test/cases/simple-async-load-css/d.css b/test/cases/simple-async-load-css/d.css new file mode 100644 index 00000000..75945584 --- /dev/null +++ b/test/cases/simple-async-load-css/d.css @@ -0,0 +1 @@ +body { background: yellow; } diff --git a/test/cases/simple-async-load-css/e.css b/test/cases/simple-async-load-css/e.css new file mode 100644 index 00000000..484aaf18 --- /dev/null +++ b/test/cases/simple-async-load-css/e.css @@ -0,0 +1 @@ +body { background: purple; } diff --git a/test/cases/simple-async-load-css/expected/async-one.css b/test/cases/simple-async-load-css/expected/async-one.css new file mode 100644 index 00000000..e28fd9a4 --- /dev/null +++ b/test/cases/simple-async-load-css/expected/async-one.css @@ -0,0 +1,4 @@ +body { background: blue; } + +body { background: yellow; } + diff --git a/test/cases/simple-async-load-css/expected/async-two.css b/test/cases/simple-async-load-css/expected/async-two.css new file mode 100644 index 00000000..83c2b1a9 --- /dev/null +++ b/test/cases/simple-async-load-css/expected/async-two.css @@ -0,0 +1,4 @@ +body { background: purple; } + +body { background: indigo; } + diff --git a/test/cases/simple-async-load-css/expected/main.css b/test/cases/simple-async-load-css/expected/main.css new file mode 100644 index 00000000..f17305d1 --- /dev/null +++ b/test/cases/simple-async-load-css/expected/main.css @@ -0,0 +1,4 @@ +body { background: red; } + +body { background: green; } + diff --git a/test/cases/simple-async-load-css/f.css b/test/cases/simple-async-load-css/f.css new file mode 100644 index 00000000..a0f22c15 --- /dev/null +++ b/test/cases/simple-async-load-css/f.css @@ -0,0 +1 @@ +body { background: indigo; } diff --git a/test/cases/simple-async-load-css/index.js b/test/cases/simple-async-load-css/index.js new file mode 100644 index 00000000..4a384fd0 --- /dev/null +++ b/test/cases/simple-async-load-css/index.js @@ -0,0 +1,5 @@ +import './a.css'; +import './b.css'; +import(/* webpackChunkName: 'async-one' */'./async-one'); +import(/* webpackChunkName: 'async-two' */'./async-two'); + diff --git a/test/cases/simple-async-load-css/webpack.config.js b/test/cases/simple-async-load-css/webpack.config.js new file mode 100644 index 00000000..2a846242 --- /dev/null +++ b/test/cases/simple-async-load-css/webpack.config.js @@ -0,0 +1,23 @@ +const Self = require('../../../'); + +module.exports = { + entry: { + 'main': './index.js', + }, + module: { + rules: [ + { + test: /\.css$/, + use: [ + Self.loader, + 'css-loader', + ], + }, + ], + }, + plugins: [ + new Self({ + filename: '[name].css', + }), + ], +}; diff --git a/test/cases/simple-publicpath/expected/main.css b/test/cases/simple-publicpath/expected/main.css new file mode 100644 index 00000000..6073c14a --- /dev/null +++ b/test/cases/simple-publicpath/expected/main.css @@ -0,0 +1,2 @@ +body { background: red; background-image: url(/static/img/cd0bb358c45b584743d8ce4991777c42.svg); } + diff --git a/test/cases/simple-publicpath/index.js b/test/cases/simple-publicpath/index.js new file mode 100644 index 00000000..aa3357bf --- /dev/null +++ b/test/cases/simple-publicpath/index.js @@ -0,0 +1 @@ +import './style.css'; diff --git a/test/cases/simple-publicpath/react.svg b/test/cases/simple-publicpath/react.svg new file mode 100644 index 00000000..5b3b22a4 --- /dev/null +++ b/test/cases/simple-publicpath/react.svg @@ -0,0 +1 @@ +logo-on-dark-bg \ No newline at end of file diff --git a/test/cases/simple-publicpath/style.css b/test/cases/simple-publicpath/style.css new file mode 100644 index 00000000..edcbc24a --- /dev/null +++ b/test/cases/simple-publicpath/style.css @@ -0,0 +1 @@ +body { background: red; background-image: url(./react.svg); } diff --git a/test/cases/simple-publicpath/webpack.config.js b/test/cases/simple-publicpath/webpack.config.js new file mode 100644 index 00000000..75b7b8b8 --- /dev/null +++ b/test/cases/simple-publicpath/webpack.config.js @@ -0,0 +1,34 @@ +const Self = require('../../../'); + +module.exports = { + entry: './index.js', + module: { + rules: [ + { + test: /\.css$/, + use: [ + { + loader: Self.loader, + options: { + publicPath: '/static/img/' + } + }, + 'css-loader', + ], + }, { + test: /\.(svg|png)$/, + use: [{ + loader: 'file-loader', + options: { + filename: '[name].[ext]' + } + }] + } + ], + }, + plugins: [ + new Self({ + filename: '[name].css', + }), + ], +}; diff --git a/test/cases/source-map/expected/main.css b/test/cases/source-map/expected/main.css new file mode 100644 index 00000000..e7d36a90 --- /dev/null +++ b/test/cases/source-map/expected/main.css @@ -0,0 +1,4 @@ +body { background: red; } + + +/*# sourceMappingURL=main.css.map*/ \ No newline at end of file diff --git a/test/cases/source-map/index.js b/test/cases/source-map/index.js new file mode 100644 index 00000000..aa3357bf --- /dev/null +++ b/test/cases/source-map/index.js @@ -0,0 +1 @@ +import './style.css'; diff --git a/test/cases/source-map/style.css b/test/cases/source-map/style.css new file mode 100644 index 00000000..31fc5b8a --- /dev/null +++ b/test/cases/source-map/style.css @@ -0,0 +1 @@ +body { background: red; } diff --git a/test/cases/source-map/webpack.config.js b/test/cases/source-map/webpack.config.js new file mode 100644 index 00000000..4c8bdad1 --- /dev/null +++ b/test/cases/source-map/webpack.config.js @@ -0,0 +1,32 @@ +const Self = require('../../../'); + +module.exports = { + entry: './index.js', + devtool: "source-map", + module: { + rules: [ + { + test: /\.css$/, + use: [ + { + loader: Self.loader, + options: { + sourceMap: true + } + }, + { + loader: 'css-loader', + options: { + sourceMap: true + } + } + ], + }, + ], + }, + plugins: [ + new Self({ + filename: '[name].css', + }), + ], +}; diff --git a/test/cases/split-chunks-single/a.css b/test/cases/split-chunks-single/a.css new file mode 100644 index 00000000..dd4f97ce --- /dev/null +++ b/test/cases/split-chunks-single/a.css @@ -0,0 +1 @@ +body { content: "a"; } diff --git a/test/cases/split-chunks-single/b.css b/test/cases/split-chunks-single/b.css new file mode 100644 index 00000000..52d18453 --- /dev/null +++ b/test/cases/split-chunks-single/b.css @@ -0,0 +1 @@ +body { content: "b"; } diff --git a/test/cases/split-chunks-single/c.css b/test/cases/split-chunks-single/c.css new file mode 100644 index 00000000..c53028fb --- /dev/null +++ b/test/cases/split-chunks-single/c.css @@ -0,0 +1 @@ +body { content: "c"; } diff --git a/test/cases/split-chunks-single/chunk1.js b/test/cases/split-chunks-single/chunk1.js new file mode 100644 index 00000000..eb558470 --- /dev/null +++ b/test/cases/split-chunks-single/chunk1.js @@ -0,0 +1,2 @@ +import "./c.css"; +import "./d.css"; diff --git a/test/cases/split-chunks-single/chunk2.js b/test/cases/split-chunks-single/chunk2.js new file mode 100644 index 00000000..7254062a --- /dev/null +++ b/test/cases/split-chunks-single/chunk2.js @@ -0,0 +1,2 @@ +import "./d.css"; +import "./h.css"; diff --git a/test/cases/split-chunks-single/d.css b/test/cases/split-chunks-single/d.css new file mode 100644 index 00000000..1b2fc6a8 --- /dev/null +++ b/test/cases/split-chunks-single/d.css @@ -0,0 +1 @@ +body { content: "d"; } diff --git a/test/cases/split-chunks-single/e1.css b/test/cases/split-chunks-single/e1.css new file mode 100644 index 00000000..9028097f --- /dev/null +++ b/test/cases/split-chunks-single/e1.css @@ -0,0 +1 @@ +body { content: "e1"; } diff --git a/test/cases/split-chunks-single/e2.css b/test/cases/split-chunks-single/e2.css new file mode 100644 index 00000000..af21d863 --- /dev/null +++ b/test/cases/split-chunks-single/e2.css @@ -0,0 +1 @@ +body { content: "e2"; } diff --git a/test/cases/split-chunks-single/entry1.js b/test/cases/split-chunks-single/entry1.js new file mode 100644 index 00000000..db2fccba --- /dev/null +++ b/test/cases/split-chunks-single/entry1.js @@ -0,0 +1,6 @@ +import './a.css'; +import './e1.css'; +import './e2.css'; +import './f.css'; +import("./chunk1"); +import("./chunk2"); diff --git a/test/cases/split-chunks-single/entry2.js b/test/cases/split-chunks-single/entry2.js new file mode 100644 index 00000000..a8576c43 --- /dev/null +++ b/test/cases/split-chunks-single/entry2.js @@ -0,0 +1,5 @@ +import './b.css'; +import './e2.css'; +import './e1.css'; +import './g.css'; +import './h.css'; diff --git a/test/cases/split-chunks-single/expected/styles.css b/test/cases/split-chunks-single/expected/styles.css new file mode 100644 index 00000000..1bd8b96d --- /dev/null +++ b/test/cases/split-chunks-single/expected/styles.css @@ -0,0 +1,18 @@ +body { content: "a"; } + +body { content: "b"; } + +body { content: "c"; } + +body { content: "d"; } + +body { content: "e1"; } + +body { content: "e2"; } + +body { content: "f"; } + +body { content: "g"; } + +body { content: "h"; } + diff --git a/test/cases/split-chunks-single/f.css b/test/cases/split-chunks-single/f.css new file mode 100644 index 00000000..08f73240 --- /dev/null +++ b/test/cases/split-chunks-single/f.css @@ -0,0 +1 @@ +body { content: "f"; } diff --git a/test/cases/split-chunks-single/g.css b/test/cases/split-chunks-single/g.css new file mode 100644 index 00000000..098e2a66 --- /dev/null +++ b/test/cases/split-chunks-single/g.css @@ -0,0 +1 @@ +body { content: "g"; } diff --git a/test/cases/split-chunks-single/h.css b/test/cases/split-chunks-single/h.css new file mode 100644 index 00000000..991f82ec --- /dev/null +++ b/test/cases/split-chunks-single/h.css @@ -0,0 +1 @@ +body { content: "h"; } diff --git a/test/cases/split-chunks-single/style.css b/test/cases/split-chunks-single/style.css new file mode 100644 index 00000000..31fc5b8a --- /dev/null +++ b/test/cases/split-chunks-single/style.css @@ -0,0 +1 @@ +body { background: red; } diff --git a/test/cases/split-chunks-single/webpack.config.js b/test/cases/split-chunks-single/webpack.config.js new file mode 100644 index 00000000..9732c2a0 --- /dev/null +++ b/test/cases/split-chunks-single/webpack.config.js @@ -0,0 +1,36 @@ +const Self = require('../../../'); + +module.exports = { + entry: { + entry1: './entry1.js', + entry2: './entry2.js' + }, + module: { + rules: [ + { + test: /\.css$/, + use: [ + Self.loader, + 'css-loader', + ], + }, + ], + }, + optimization: { + splitChunks: { + cacheGroups: { + styles: { + name: "styles", + chunks: 'all', + test: /\.css$/, + enforce: true + } + } + } + }, + plugins: [ + new Self({ + filename: '[name].css', + }), + ], +}; diff --git a/test/cases/split-chunks/index.js b/test/cases/split-chunks/index.js index 4bac714b..c83e204a 100644 --- a/test/cases/split-chunks/index.js +++ b/test/cases/split-chunks/index.js @@ -1,3 +1,2 @@ -/* eslint-disable */ import 'bootstrap.css'; import './style.css'; diff --git a/test/cases/split-chunks/webpack.config.js b/test/cases/split-chunks/webpack.config.js index c1b163e1..d276ab14 100644 --- a/test/cases/split-chunks/webpack.config.js +++ b/test/cases/split-chunks/webpack.config.js @@ -19,10 +19,10 @@ module.exports = { cacheGroups: { vendors: { test: /node_modules/, - enforce: true, - }, - }, - }, + enforce: true + } + } + } }, plugins: [ new Self({ diff --git a/test/manual/index.html b/test/manual/index.html index 8f544a27..8158d36a 100644 --- a/test/manual/index.html +++ b/test/manual/index.html @@ -3,7 +3,7 @@ - extract-css-chunks-webpack-plugin testcase + mini-css-extract-plugin testcase