diff --git a/lib/loader.js b/lib/loader.js index 292f4f7d..cc807bb8 100644 --- a/lib/loader.js +++ b/lib/loader.js @@ -49,7 +49,6 @@ module.exports = function loader(content, map) { } /* eslint-enable no-param-reassign */ - const parserOptions = {}; const resolveImport = options.import !== false; const resolveUrl = options.url !== false; const loaderContext = this; @@ -98,7 +97,7 @@ module.exports = function loader(content, map) { plugins.push(urlParser()); } - plugins.push(icssParser(parserOptions)); + plugins.push(icssParser()); postcss(plugins) .process(content, { @@ -125,34 +124,39 @@ module.exports = function loader(content, map) { const messages = result.messages || []; const { camelCase, exportOnlyLocals, importLoaders } = options; - const { importItems } = parserOptions; // Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS const importUrlPrefix = getImportPrefix(this, importLoaders); // Prepare replacer to change from `___CSS_LOADER_IMPORT___INDEX___` to `require('./file.css').locals` - const importItemReplacer = (item) => { - const match = placholderRegExps.importItem.exec(item); + const importItemReplacer = (placeholder) => { + const match = placholderRegExps.importItem.exec(placeholder); const idx = Number(match[1]); - if (!importItems[idx]) { - return item; + const message = messages.find( + // eslint-disable-next-line no-shadow + (message) => + message.type === 'icss-import' && message.item.index === idx + ); + + if (!message) { + return placeholder; } - const importItem = importItems[idx]; - const importUrl = importUrlPrefix + importItem.url; + const { item } = message; + const importUrl = importUrlPrefix + item.url; if (exportOnlyLocals) { return `" + require(${stringifyRequest( this, importUrl - )})[${JSON.stringify(importItem.export)}] + "`; + )})[${JSON.stringify(item.export)}] + "`; } return `" + require(${stringifyRequest( this, importUrl - )}).locals[${JSON.stringify(importItem.export)}] + "`; + )}).locals[${JSON.stringify(item.export)}] + "`; }; let exportCode = compileExports(messages, camelCase, (valueAsString) => @@ -166,22 +170,11 @@ module.exports = function loader(content, map) { ); } - const alreadyImported = {}; - const importCode = importItems - .filter((imp) => { - if (!imp.media) { - if (alreadyImported[imp.url]) { - return false; - } - - alreadyImported[imp.url] = true; - } - - return true; - }) - .map((imp) => { - const { url } = imp; - const media = imp.media || ''; + const importCode = messages + .filter((message) => message.type === 'import') + .map((message) => { + const { url } = message.item; + const media = message.item.media || ''; if (!isUrlRequest(url)) { return `exports.push([module.id, ${JSON.stringify( @@ -207,7 +200,7 @@ module.exports = function loader(content, map) { let urlEscapeHelperCode = ''; messages - .filter((message) => message.type === 'url' && resolveUrl) + .filter((message) => message.type === 'url') .forEach((message) => { if (!urlEscapeHelperCode) { urlEscapeHelperCode = `var escape = require(${stringifyRequest( diff --git a/lib/plugins/postcss-icss-parser.js b/lib/plugins/postcss-icss-parser.js index fed8a5d8..96e5800c 100644 --- a/lib/plugins/postcss-icss-parser.js +++ b/lib/plugins/postcss-icss-parser.js @@ -7,12 +7,8 @@ const pluginName = 'postcss-icss-parser'; module.exports = postcss.plugin( pluginName, - (options) => + () => function process(css, result) { - const importItems = (result.messages || []) - .filter((message) => message.type === 'import') - .map((message) => message.item); - const imports = {}; const icss = icssUtils.extractICSS(css); const exports = icss.icssExports; @@ -21,11 +17,32 @@ module.exports = postcss.plugin( const url = loaderUtils.parseString(key); Object.keys(icss.icssImports[key]).forEach((prop) => { - imports[`$${prop}`] = importItems.length; - importItems.push({ - url, - media: '', - export: icss.icssImports[key][prop], + const index = Object.keys(imports).length; + + imports[`$${prop}`] = index; + + result.messages.push({ + pluginName, + type: 'icss-import', + item: { url, export: icss.icssImports[key][prop], index }, + }); + + const alreadyIncluded = result.messages.find( + (message) => + message.pluginName === pluginName && + message.type === 'import' && + message.item.url === url && + message.item.media === '' + ); + + if (alreadyIncluded) { + return; + } + + result.messages.push({ + pluginName, + type: 'import', + item: { url, media: '' }, }); }); }); @@ -73,9 +90,5 @@ module.exports = postcss.plugin( }, }); }); - - /* eslint-disable no-param-reassign */ - options.importItems = importItems; - /* eslint-enable no-param-reassign */ } ); diff --git a/test/__snapshots__/import-option.test.js.snap b/test/__snapshots__/import-option.test.js.snap index e9d56761..8499bf19 100644 --- a/test/__snapshots__/import-option.test.js.snap +++ b/test/__snapshots__/import-option.test.js.snap @@ -7,6 +7,12 @@ Array [ Array [ 2, " +", + "", + ], + Array [ + 3, + " ", "", ], @@ -17,6 +23,27 @@ Array [ .ghi { color: red; } + +.class { + color: blue; +} + +.other { + display: block; +} + +.other-other { + width: 2112moon; +} + +.green { + color: green; +} + +.foo { + prop: red; + duplicate: green; +} ", "", ], @@ -27,13 +54,18 @@ exports[`import option false and modules false: module 1`] = ` "exports = module.exports = require(\\"../../../lib/runtime/api.js\\")(false); // imports exports.i(require(\\"-!../../../index.js??ref--4-0!./values.css\\"), \\"\\"); +exports.i(require(\\"-!../../../index.js??ref--4-0!./something.css\\"), \\"\\"); // module -exports.push([module.id, \\"@import url(test-other.css) (min-width: 100px);\\\\n\\\\n.ghi {\\\\n color: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"def\\"] + \\";\\\\n}\\\\n\\", \\"\\"]); +exports.push([module.id, \\"@import url(test-other.css) (min-width: 100px);\\\\n\\\\n.ghi {\\\\n color: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"def\\"] + \\";\\\\n}\\\\n\\\\n.class {\\\\n color: blue;\\\\n}\\\\n\\\\n.other {\\\\n display: block;\\\\n}\\\\n\\\\n.other-other {\\\\n width: \\" + require(\\"-!../../../index.js??ref--4-0!./something.css\\").locals[\\"something\\"] + \\";\\\\n}\\\\n\\\\n.green {\\\\n color: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"other\\"] + \\";\\\\n}\\\\n\\\\n.foo {\\\\n prop: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"def\\"] + \\";\\\\n duplicate: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"other\\"] + \\";\\\\n}\\\\n\\", \\"\\"]); // exports exports.locals = { - \\"def\\": \\"\\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"def\\"] + \\"\\" + \\"def\\": \\"\\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"def\\"] + \\"\\", + \\"other\\": \\"\\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"other\\"] + \\"\\", + \\"something\\": \\"\\" + require(\\"-!../../../index.js??ref--4-0!./something.css\\").locals[\\"something\\"] + \\"\\", + \\"foo\\": \\"blue\\", + \\"bar\\": \\"block\\" };" `; @@ -46,6 +78,12 @@ Array [ Array [ 2, " +", + "", + ], + Array [ + 3, + " ", "", ], @@ -56,6 +94,27 @@ Array [ ._3r49KZIIAltPknAjdNVZ-7 { color: red; } + +._4o0o5eKzoeDOSI0_cR8mr { + color: blue; +} + +._2wLXKM9pRjt1oRYvf0Wo3Q { + display: block; +} + +._1RBgqC8j3f4iU6k-ocmIG7 { + width: 2112moon; +} + +._1lCIckG6C8tRZjGNDsAPWr { + color: green; +} + +._1YL4f0i_603GTMRC_pnsP5 { + prop: red; + duplicate: green; +} ", "", ], @@ -66,14 +125,22 @@ exports[`import option false and modules true: module 1`] = ` "exports = module.exports = require(\\"../../../lib/runtime/api.js\\")(false); // imports exports.i(require(\\"-!../../../index.js??ref--4-0!./values.css\\"), \\"\\"); +exports.i(require(\\"-!../../../index.js??ref--4-0!./something.css\\"), \\"\\"); // module -exports.push([module.id, \\"@import url(test-other.css) (min-width: 100px);\\\\n\\\\n._3r49KZIIAltPknAjdNVZ-7 {\\\\n color: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"def\\"] + \\";\\\\n}\\\\n\\", \\"\\"]); +exports.push([module.id, \\"@import url(test-other.css) (min-width: 100px);\\\\n\\\\n._3r49KZIIAltPknAjdNVZ-7 {\\\\n color: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"def\\"] + \\";\\\\n}\\\\n\\\\n._4o0o5eKzoeDOSI0_cR8mr {\\\\n color: blue;\\\\n}\\\\n\\\\n._2wLXKM9pRjt1oRYvf0Wo3Q {\\\\n display: block;\\\\n}\\\\n\\\\n._1RBgqC8j3f4iU6k-ocmIG7 {\\\\n width: \\" + require(\\"-!../../../index.js??ref--4-0!./something.css\\").locals[\\"something\\"] + \\";\\\\n}\\\\n\\\\n._1lCIckG6C8tRZjGNDsAPWr {\\\\n color: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"other\\"] + \\";\\\\n}\\\\n\\\\n._1YL4f0i_603GTMRC_pnsP5 {\\\\n prop: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"def\\"] + \\";\\\\n duplicate: \\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"other\\"] + \\";\\\\n}\\\\n\\", \\"\\"]); // exports exports.locals = { \\"def\\": \\"\\" + require(\\"-!../../../index.js??ref--4-0!./values.css\\").locals[\\"def\\"] + \\"\\", - \\"ghi\\": \\"_3r49KZIIAltPknAjdNVZ-7\\" + \\"other\\": \\"_2wLXKM9pRjt1oRYvf0Wo3Q\\", + \\"something\\": \\"\\" + require(\\"-!../../../index.js??ref--4-0!./something.css\\").locals[\\"something\\"] + \\"\\", + \\"foo\\": \\"_1YL4f0i_603GTMRC_pnsP5\\", + \\"bar\\": \\"block\\", + \\"ghi\\": \\"_3r49KZIIAltPknAjdNVZ-7\\", + \\"class\\": \\"_4o0o5eKzoeDOSI0_cR8mr\\", + \\"other-other\\": \\"_1RBgqC8j3f4iU6k-ocmIG7\\", + \\"green\\": \\"_1lCIckG6C8tRZjGNDsAPWr\\" };" `; diff --git a/test/fixtures/import/css-modules.css b/test/fixtures/import/css-modules.css index 1b17d9b4..ec7ee2d2 100644 --- a/test/fixtures/import/css-modules.css +++ b/test/fixtures/import/css-modules.css @@ -1,7 +1,33 @@ @import url(test-other.css) (min-width: 100px); @value def from './values.css'; +@value other from './values.css'; +@value other from './values.css'; +@value something from './something.css'; +@value foo: blue; +@value bar: block; .ghi { color: def; } + +.class { + color: foo; +} + +.other { + display: bar; +} + +.other-other { + width: something; +} + +.green { + color: other; +} + +.foo { + prop: def; + duplicate: other; +} diff --git a/test/fixtures/import/something.css b/test/fixtures/import/something.css new file mode 100644 index 00000000..8d4c11e7 --- /dev/null +++ b/test/fixtures/import/something.css @@ -0,0 +1 @@ +@value something: 2112moon; diff --git a/test/fixtures/import/values.css b/test/fixtures/import/values.css index 2b75b778..34aefa7d 100644 --- a/test/fixtures/import/values.css +++ b/test/fixtures/import/values.css @@ -1 +1,2 @@ @value def: red; +@value other: green;