diff --git a/src/index.js b/src/index.js index a6920efe..57cd64da 100644 --- a/src/index.js +++ b/src/index.js @@ -128,30 +128,60 @@ export default (options = {}) => { !(options_.dir || options_.file) ) return + const entries = Object + .values(bundle) + .filter(bundle => bundle.isEntry) + const isMultiEntry = entries.length > 1 + + let concat // TODO: support `[hash]` - const dir = options_.dir || path.dirname(options_.file) - const file = - options_.file || - path.join( - options_.dir, - Object.keys(bundle).find(fileName => bundle[fileName].isEntry) - ) - const getExtracted = () => { - let fileName = `${path.basename(file, path.extname(file))}.css` + const getExtracted = ({ fileName: entryFileName, modules }) => { + let baseName + let fileName + let dir + + if (isMultiEntry) { + baseName = `${path.basename(entryFileName, path.extname(entryFileName))}.css` + dir = path.dirname(entryFileName) + fileName = path.join( + dir, + baseName + ) + } else { + // TODO: copy from the previous version, refactor + dir = options_.dir || path.dirname(options_.file) + const file = options_.file || path.join( + options_.dir, + Object.keys(bundle).find(fileName => bundle[fileName].isEntry) + ) + fileName = `${path.basename(file, path.extname(file))}.css` + baseName = fileName + } + if (typeof postcssLoaderOptions.extract === 'string') { if (path.isAbsolute(postcssLoaderOptions.extract)) { + const dir = options_.dir || path.dirname(options_.file) fileName = normalizePath(path.relative(dir, postcssLoaderOptions.extract)) } else { fileName = normalizePath(postcssLoaderOptions.extract) } + + baseName = fileName + concat = concat || new Concat(true, fileName, '\n') + } else { + concat = new Concat(true, fileName, '\n') } - const concat = new Concat(true, fileName, '\n') - const entries = [...extracted.values()] - const { modules } = bundle[normalizePath(path.relative(dir, file))] + const entries = [] if (modules) { + const fileList = Object.keys(modules) const moduleIds = [...this.moduleIds] + fileList.forEach(id => { + if (extracted.has(id)) { + entries.push(extracted.get(id)) + } + }) entries.sort( (a, b) => moduleIds.indexOf(a.id) - moduleIds.indexOf(b.id) ) @@ -161,7 +191,7 @@ export default (options = {}) => { const relative = normalizePath(path.relative(dir, result.id)) const map = result.map || null if (map) { - map.file = fileName + map.file = baseName } concat.add(relative, result.code, map) @@ -175,7 +205,7 @@ export default (options = {}) => { 'utf8' ).toString('base64')}*/` } else if (sourceMap === true) { - code += `\n/*# sourceMappingURL=${fileName}.map */` + code += `\n/*# sourceMappingURL=${baseName}.map */` } return { @@ -193,38 +223,46 @@ export default (options = {}) => { } } - let { code, codeFileName, map, mapFileName } = getExtracted() - // Perform cssnano on the extracted file - if (postcssLoaderOptions.minimize) { - const cssOptions = postcssLoaderOptions.minimize - cssOptions.from = codeFileName - if (sourceMap === 'inline') { - cssOptions.map = { inline: true } - } else if (sourceMap === true && map) { - cssOptions.map = { prev: map } - cssOptions.to = codeFileName - } + const handleEntry = async entry => { + let { code, codeFileName, map, mapFileName } = getExtracted(entry) + // Perform cssnano on the extracted file + if (postcssLoaderOptions.minimize) { + const cssOptions = postcssLoaderOptions.minimize + cssOptions.from = codeFileName + if (sourceMap === 'inline') { + cssOptions.map = { inline: true } + } else if (sourceMap === true && map) { + cssOptions.map = { prev: map } + cssOptions.to = codeFileName + } - const result = await require('cssnano').process(code, cssOptions) - code = result.css + const result = await require('cssnano').process(code, cssOptions) + code = result.css - if (sourceMap === true && result.map && result.map.toString) { - map = result.map.toString() + if (sourceMap === true && result.map && result.map.toString) { + map = result.map.toString() + } } - } - this.emitFile({ - fileName: codeFileName, - type: 'asset', - source: code - }) - if (map) { this.emitFile({ - fileName: mapFileName, + fileName: codeFileName, type: 'asset', - source: map + source: code }) + if (map) { + this.emitFile({ + fileName: mapFileName, + type: 'asset', + source: map + }) + } } + + await Promise.all( + Object.values(bundle) + .filter(bundle => bundle.isEntry) + .map(handleEntry) + ) } } } diff --git a/test/__snapshots__/index.test.js.snap b/test/__snapshots__/index.test.js.snap index 35da34d2..f53a2254 100644 --- a/test/__snapshots__/index.test.js.snap +++ b/test/__snapshots__/index.test.js.snap @@ -166,27 +166,10 @@ exports[`extract custom-path: css code 1`] = ` color: red; } -body { - color: #f00; - background: #f00; -} -/*# sourceMappingURL=test/fixtures/simple/style.css.map */ -#sidebar { - width: 30%; - background-color: #faa; } - -#header { - color: #6c94be; -} - -.pcss { - color: red; -} - /*# sourceMappingURL=this/is/extracted.css.map */" `; -exports[`extract custom-path: css map 1`] = `"{\\"version\\":3,\\"sources\\":[\\"foo.css\\",\\"bar.css\\",\\"test/fixtures/simple/style.styl\\",\\"style.styl\\",\\"style.sass\\",\\"test/fixtures/simple/style.less\\",\\"style.less\\",\\"style.pcss\\"],\\"names\\":[],\\"mappings\\":\\"AAAA;EACE,UAAU;AACZ;;ACFA;EACE,UAAU;AACZ;;ACFA;EACE,WAAO;EACP,gBAAY;ACCd;AACA,yDAAyD;ACJzD;EACE,UAAU;EACV,sBAAsB,EAAE;;ACC1B;EACE,cAAA;ACFF;;ACFA;EACE,UAAU;AACZ\\",\\"file\\":\\"this/is/extracted.css\\",\\"sourcesContent\\":[\\"body {\\\\n color: red;\\\\n}\\\\n\\",\\".bar {\\\\n color: red;\\\\n}\\\\n\\",null,null,\\"#sidebar {\\\\n width: 30%;\\\\n background-color: #faa; }\\\\n\\",null,null,\\".pcss {\\\\n color: red;\\\\n}\\\\n\\"]}"`; +exports[`extract custom-path: css map 1`] = `"{\\"version\\":3,\\"sources\\":[\\"foo.css\\",\\"bar.css\\"],\\"names\\":[],\\"mappings\\":\\"AAAA;EACE,UAAU;AACZ;;ACFA;EACE,UAAU;AACZ\\",\\"file\\":\\"this/is/extracted.css\\",\\"sourcesContent\\":[\\"body {\\\\n color: red;\\\\n}\\\\n\\",\\".bar {\\\\n color: red;\\\\n}\\\\n\\"]}"`; exports[`extract custom-path: js code 1`] = ` "'use strict'; @@ -204,27 +187,10 @@ exports[`extract relative-path: css code 1`] = ` color: red; } -body { - color: #f00; - background: #f00; -} -/*# sourceMappingURL=test/fixtures/simple/style.css.map */ -#sidebar { - width: 30%; - background-color: #faa; } - -#header { - color: #6c94be; -} - -.pcss { - color: red; -} - /*# sourceMappingURL=this/is/extracted.css.map */" `; -exports[`extract relative-path: css map 1`] = `"{\\"version\\":3,\\"sources\\":[\\"foo.css\\",\\"bar.css\\",\\"test/fixtures/simple/style.styl\\",\\"style.styl\\",\\"style.sass\\",\\"test/fixtures/simple/style.less\\",\\"style.less\\",\\"style.pcss\\"],\\"names\\":[],\\"mappings\\":\\"AAAA;EACE,UAAU;AACZ;;ACFA;EACE,UAAU;AACZ;;ACFA;EACE,WAAO;EACP,gBAAY;ACCd;AACA,yDAAyD;ACJzD;EACE,UAAU;EACV,sBAAsB,EAAE;;ACC1B;EACE,cAAA;ACFF;;ACFA;EACE,UAAU;AACZ\\",\\"file\\":\\"this/is/extracted.css\\",\\"sourcesContent\\":[\\"body {\\\\n color: red;\\\\n}\\\\n\\",\\".bar {\\\\n color: red;\\\\n}\\\\n\\",null,null,\\"#sidebar {\\\\n width: 30%;\\\\n background-color: #faa; }\\\\n\\",null,null,\\".pcss {\\\\n color: red;\\\\n}\\\\n\\"]}"`; +exports[`extract relative-path: css map 1`] = `"{\\"version\\":3,\\"sources\\":[\\"foo.css\\",\\"bar.css\\"],\\"names\\":[],\\"mappings\\":\\"AAAA;EACE,UAAU;AACZ;;ACFA;EACE,UAAU;AACZ\\",\\"file\\":\\"this/is/extracted.css\\",\\"sourcesContent\\":[\\"body {\\\\n color: red;\\\\n}\\\\n\\",\\".bar {\\\\n color: red;\\\\n}\\\\n\\"]}"`; exports[`extract relative-path: js code 1`] = ` "'use strict'; @@ -242,25 +208,7 @@ exports[`extract sourcemap-inline: css code 1`] = ` color: red; } -body { - color: #f00; - background: #f00; -} -/*# sourceMappingURL=test/fixtures/simple/style.css.map */ -#sidebar { - width: 30%; - background-color: #faa; } - -/*# sourceMappingURL=../../../inline */ -#header { - color: #6c94be; -} - -.pcss { - color: red; -} - -/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZvby5jc3MiLCJiYXIuY3NzIiwidGVzdC9maXh0dXJlcy9zaW1wbGUvc3R5bGUuc3R5bCIsInN0eWxlLnN0eWwiLCJ0ZXN0L2ZpeHR1cmVzL3NpbXBsZS9zdHlsZS5zYXNzIiwic3R5bGUuc2FzcyIsInRlc3QvZml4dHVyZXMvc2ltcGxlL3N0eWxlLmxlc3MiLCJzdHlsZS5sZXNzIiwic3R5bGUucGNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtFQUNFLFVBQVU7QUFDWjs7QUNGQTtFQUNFLFVBQVU7QUFDWjs7QUNGQTtFQUNFLFdBQU87RUFDUCxnQkFBWTtBQ0NkO0FBQ0EseURBQXlEO0FDSnpEO0VBQ0UsVUFBVTtFQUNWLHNCQUFzQixFQUFBOztBQ0V4QixzQ0FBc0M7QUNEdEM7RUFDRSxjQUFBO0FDRkY7O0FDRkE7RUFDRSxVQUFVO0FBQ1oiLCJmaWxlIjoiYnVuZGxlLmNzcyIsInNvdXJjZXNDb250ZW50IjpbImJvZHkge1xuICBjb2xvcjogcmVkO1xufVxuIiwiLmJhciB7XG4gIGNvbG9yOiByZWQ7XG59XG4iLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLCIucGNzcyB7XG4gIGNvbG9yOiByZWQ7XG59XG4iXX0=*/" +/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImZvby5jc3MiLCJiYXIuY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0VBQ0UsVUFBVTtBQUNaOztBQ0ZBO0VBQ0UsVUFBVTtBQUNaIiwiZmlsZSI6ImJ1bmRsZS5jc3MiLCJzb3VyY2VzQ29udGVudCI6WyJib2R5IHtcbiAgY29sb3I6IHJlZDtcbn1cbiIsIi5iYXIge1xuICBjb2xvcjogcmVkO1xufVxuIl19*/" `; exports[`extract sourcemap-inline: js code 1`] = ` @@ -279,27 +227,10 @@ exports[`extract sourcemap-true: css code 1`] = ` color: red; } -body { - color: #f00; - background: #f00; -} -/*# sourceMappingURL=test/fixtures/simple/style.css.map */ -#sidebar { - width: 30%; - background-color: #faa; } - -#header { - color: #6c94be; -} - -.pcss { - color: red; -} - /*# sourceMappingURL=bundle.css.map */" `; -exports[`extract sourcemap-true: css map 1`] = `"{\\"version\\":3,\\"sources\\":[\\"foo.css\\",\\"bar.css\\",\\"test/fixtures/simple/style.styl\\",\\"style.styl\\",\\"style.sass\\",\\"test/fixtures/simple/style.less\\",\\"style.less\\",\\"style.pcss\\"],\\"names\\":[],\\"mappings\\":\\"AAAA;EACE,UAAU;AACZ;;ACFA;EACE,UAAU;AACZ;;ACFA;EACE,WAAO;EACP,gBAAY;ACCd;AACA,yDAAyD;ACJzD;EACE,UAAU;EACV,sBAAsB,EAAE;;ACC1B;EACE,cAAA;ACFF;;ACFA;EACE,UAAU;AACZ\\",\\"file\\":\\"bundle.css\\",\\"sourcesContent\\":[\\"body {\\\\n color: red;\\\\n}\\\\n\\",\\".bar {\\\\n color: red;\\\\n}\\\\n\\",null,null,\\"#sidebar {\\\\n width: 30%;\\\\n background-color: #faa; }\\\\n\\",null,null,\\".pcss {\\\\n color: red;\\\\n}\\\\n\\"]}"`; +exports[`extract sourcemap-true: css map 1`] = `"{\\"version\\":3,\\"sources\\":[\\"foo.css\\",\\"bar.css\\"],\\"names\\":[],\\"mappings\\":\\"AAAA;EACE,UAAU;AACZ;;ACFA;EACE,UAAU;AACZ\\",\\"file\\":\\"bundle.css\\",\\"sourcesContent\\":[\\"body {\\\\n color: red;\\\\n}\\\\n\\",\\".bar {\\\\n color: red;\\\\n}\\\\n\\"]}"`; exports[`extract sourcemap-true: js code 1`] = ` "'use strict'; @@ -316,23 +247,6 @@ exports[`extract true: css code 1`] = ` .bar { color: red; } - -body { - color: #f00; - background: #f00; -} - -#sidebar { - width: 30%; - background-color: #faa; } - -#header { - color: #6c94be; -} - -.pcss { - color: red; -} " `; @@ -431,7 +345,7 @@ console.log(css_248z, css_248z$1); " `; -exports[`minimize extract: css code 1`] = `".bar,body{color:red}body{background:red}#sidebar{width:30%;background-color:#faa}#header{color:#6c94be}.pcss{color:red}"`; +exports[`minimize extract: css code 1`] = `".bar,body{color:red}"`; exports[`minimize extract: js code 1`] = ` "'use strict'; @@ -441,8 +355,8 @@ console.log(undefined, undefined); `; exports[`minimize extract-sourcemap-inline: css code 1`] = ` -".bar,body{color:red}body{background:red}#sidebar{width:30%;background-color:#faa}#header{color:#6c94be}.pcss{color:red} -/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImJ1bmRsZS5jc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBUUEsVUFIRSxTQU1GLENBSEEsS0FFRSxjQUNGLENBRUEsU0FDRSxTQUFVLENBQ1YscUJBQXdCLENBRzFCLFFBQ0UsYUFDRixDQUVBLE1BQ0UsU0FDRiIsImZpbGUiOiJidW5kbGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiYm9keSB7XG4gIGNvbG9yOiByZWQ7XG59XG5cbi5iYXIge1xuICBjb2xvcjogcmVkO1xufVxuXG5ib2R5IHtcbiAgY29sb3I6ICNmMDA7XG4gIGJhY2tncm91bmQ6ICNmMDA7XG59XG4vKiMgc291cmNlTWFwcGluZ1VSTD10ZXN0L2ZpeHR1cmVzL3NpbXBsZS9zdHlsZS5jc3MubWFwICovXG4jc2lkZWJhciB7XG4gIHdpZHRoOiAzMCU7XG4gIGJhY2tncm91bmQtY29sb3I6ICNmYWE7IH1cblxuLyojIHNvdXJjZU1hcHBpbmdVUkw9Li4vLi4vLi4vaW5saW5lICovXG4jaGVhZGVyIHtcbiAgY29sb3I6ICM2Yzk0YmU7XG59XG5cbi5wY3NzIHtcbiAgY29sb3I6IHJlZDtcbn1cblxuLyojIHNvdXJjZU1hcHBpbmdVUkw9ZGF0YTphcHBsaWNhdGlvbi9qc29uO2Jhc2U2NCxleUoyWlhKemFXOXVJam96TENKemIzVnlZMlZ6SWpwYkltWnZieTVqYzNNaUxDSmlZWEl1WTNOeklpd2lkR1Z6ZEM5bWFYaDBkWEpsY3k5emFXMXdiR1V2YzNSNWJHVXVjM1I1YkNJc0luTjBlV3hsTG5OMGVXd2lMQ0owWlhOMEwyWnBlSFIxY21WekwzTnBiWEJzWlM5emRIbHNaUzV6WVhOeklpd2ljM1I1YkdVdWMyRnpjeUlzSW5SbGMzUXZabWw0ZEhWeVpYTXZjMmx0Y0d4bEwzTjBlV3hsTG14bGMzTWlMQ0p6ZEhsc1pTNXNaWE56SWl3aWMzUjViR1V1Y0dOemN5SmRMQ0p1WVcxbGN5STZXMTBzSW0xaGNIQnBibWR6SWpvaVFVRkJRVHRGUVVORkxGVkJRVlU3UVVGRFdqczdRVU5HUVR0RlFVTkZMRlZCUVZVN1FVRkRXanM3UVVOR1FUdEZRVU5GTEZkQlFVODdSVUZEVUN4blFrRkJXVHRCUTBOa08wRkJRMEVzZVVSQlFYbEVPMEZEU25wRU8wVkJRMFVzVlVGQlZUdEZRVU5XTEhOQ1FVRnpRaXhGUVVGQk96dEJRMFY0UWl4elEwRkJjME03UVVORWRFTTdSVUZEUlN4alFVRkJPMEZEUmtZN08wRkRSa0U3UlVGRFJTeFZRVUZWTzBGQlExb2lMQ0ptYVd4bElqb2lZblZ1Wkd4bExtTnpjeUlzSW5OdmRYSmpaWE5EYjI1MFpXNTBJanBiSW1KdlpIa2dlMXh1SUNCamIyeHZjam9nY21Wa08xeHVmVnh1SWl3aUxtSmhjaUI3WEc0Z0lHTnZiRzl5T2lCeVpXUTdYRzU5WEc0aUxHNTFiR3dzYm5Wc2JDeHVkV3hzTEc1MWJHd3NiblZzYkN4dWRXeHNMQ0l1Y0dOemN5QjdYRzRnSUdOdmJHOXlPaUJ5WldRN1hHNTlYRzRpWFgwPSovIl19 */" +".bar,body{color:red} +/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImJhci5jc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsVUFDRSxTQUNGIiwiZmlsZSI6ImJ1bmRsZS5jc3MiLCJzb3VyY2VzQ29udGVudCI6WyIuYmFyIHtcbiAgY29sb3I6IHJlZDtcbn1cbiJdfQ== */" `; exports[`minimize extract-sourcemap-inline: js code 1`] = ` @@ -453,11 +367,11 @@ console.log(undefined, undefined); `; exports[`minimize extract-sourcemap-true: css code 1`] = ` -".bar,body{color:red}body{background:red}#sidebar{width:30%;background-color:#faa}#header{color:#6c94be}.pcss{color:red} +".bar,body{color:red} /*# sourceMappingURL=bundle.css.map */" `; -exports[`minimize extract-sourcemap-true: css map 1`] = `"{\\"version\\":3,\\"sources\\":[\\"test/fixtures/simple/style.styl\\",\\"bar.css\\",\\"style.styl\\",\\"style.sass\\",\\"test/fixtures/simple/style.less\\",\\"style.less\\",\\"style.pcss\\"],\\"names\\":[],\\"mappings\\":\\"AAAA,UCCE,SCEF,CFHA,KAEE,cECF,CCHA,SACE,SAAU,CACV,qBAAwB,CCC1B,QACE,aCFF,CCFA,MACE,SACF\\",\\"file\\":\\"bundle.css\\",\\"sourcesContent\\":[null,\\".bar {\\\\n color: red;\\\\n}\\\\n\\",null,\\"#sidebar {\\\\n width: 30%;\\\\n background-color: #faa; }\\\\n\\",null,null,\\".pcss {\\\\n color: red;\\\\n}\\\\n\\"]}"`; +exports[`minimize extract-sourcemap-true: css map 1`] = `"{\\"version\\":3,\\"sources\\":[\\"bar.css\\"],\\"names\\":[],\\"mappings\\":\\"AAAA,UACE,SACF\\",\\"file\\":\\"bundle.css\\",\\"sourcesContent\\":[\\".bar {\\\\n color: red;\\\\n}\\\\n\\"]}"`; exports[`minimize extract-sourcemap-true: js code 1`] = ` "'use strict'; @@ -762,6 +676,46 @@ console.log(style$1); " `; +exports[`multi-entry multi-entry: css code entry1 1`] = ` +".baz { + color: red; +} +.foo { + color: red; +}" +`; + +exports[`multi-entry multi-entry: css code entry2 1`] = `""`; + +exports[`multi-entry multi-entry: js code entry1 1`] = ` +"'use strict'; + +var styles = /*#__PURE__*/Object.freeze({ + __proto__: null, + 'default': undefined +}); + +var extraStyles = /*#__PURE__*/Object.freeze({ + __proto__: null, + 'default': undefined +}); + +console.log(styles, extraStyles); +" +`; + +exports[`multi-entry multi-entry: js code entry2 1`] = ` +"'use strict'; + +var styles = /*#__PURE__*/Object.freeze({ + __proto__: null, + 'default': undefined +}); + +console.log(styles); +" +`; + exports[`onExtract 1`] = ` "'use strict'; diff --git a/test/fixtures/multi-entry/entry1-extra.css b/test/fixtures/multi-entry/entry1-extra.css new file mode 100644 index 00000000..c8296e63 --- /dev/null +++ b/test/fixtures/multi-entry/entry1-extra.css @@ -0,0 +1,3 @@ +.foo { + color: red; +} \ No newline at end of file diff --git a/test/fixtures/multi-entry/entry1.css b/test/fixtures/multi-entry/entry1.css new file mode 100644 index 00000000..bee693c3 --- /dev/null +++ b/test/fixtures/multi-entry/entry1.css @@ -0,0 +1,3 @@ +.baz { + color: red; +} \ No newline at end of file diff --git a/test/fixtures/multi-entry/entry1.js b/test/fixtures/multi-entry/entry1.js new file mode 100644 index 00000000..57df2233 --- /dev/null +++ b/test/fixtures/multi-entry/entry1.js @@ -0,0 +1,4 @@ +import * as styles from './entry1.css' +import * as extraStyles from './entry1-extra.css' + +console.log(styles, extraStyles) diff --git a/test/fixtures/multi-entry/entry2.css b/test/fixtures/multi-entry/entry2.css new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/multi-entry/entry2.js b/test/fixtures/multi-entry/entry2.js new file mode 100644 index 00000000..5b6438de --- /dev/null +++ b/test/fixtures/multi-entry/entry2.js @@ -0,0 +1,3 @@ +import * as styles from './entry2.css' + +console.log(styles) diff --git a/test/index.test.js b/test/index.test.js index c66e0b20..cad360b0 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -10,6 +10,15 @@ process.env.ROLLUP_POSTCSS_TEST = true const JEST_TIMEOUT = process.platform === 'win32' ? 20000 : 5000 function fixture(...args) { + if (args.length === 1 && typeof args[0] === 'object') { + const fixtureInput = {} + for (const [key, value] of Object.entries(args[0])) { + fixtureInput[key] = path.join(__dirname, 'fixtures', value) + } + + return fixtureInput + } + return path.join(__dirname, 'fixtures', ...args) } @@ -20,6 +29,7 @@ async function write({ outDir, options }) { + const isMultiEntry = typeof input === 'object' outDir = fixture('dist', outDir) const bundle = await rollup({ input: fixture(input), @@ -29,7 +39,11 @@ async function write({ }) await bundle.write({ format: 'cjs', - file: path.join(outDir, 'bundle.js') + ...( + isMultiEntry ? + { dir: outDir } : + { file: path.join(outDir, 'bundle.js') } + ) }) let cssCodePath = path.join(outDir, 'bundle.css') if (typeof options.extract === 'string') { @@ -42,21 +56,50 @@ async function write({ const cssMapPath = `${cssCodePath}.map` const jsCodePath = path.join(outDir, 'bundle.js') + const entryNames = Object.keys(input) + return { - jsCode() { - return fs.readFile(jsCodePath, 'utf8') + async jsCode() { + if (!isMultiEntry) { + return fs.readFile(jsCodePath, 'utf8') + } + + return Promise.all( + entryNames.map(async entry => [ + entry, + await fs.readFile(path.join(outDir, `${entry}.js`), 'utf8') + ]) + ) }, - cssCode() { - return fs.readFile(cssCodePath, 'utf8') + async cssCode() { + if (!isMultiEntry) { + return fs.readFile(cssCodePath, 'utf8') + } + + return Promise.all( + entryNames.map(async entry => [ + entry, + await fs.readFile(path.join(outDir, `${entry}.css`), 'utf8') + ]) + ) }, cssMap() { return fs.readFile(cssMapPath, 'utf8') }, - hasCssFile() { - return fs.pathExists(cssCodePath) + async hasCssFile() { + if (!isMultiEntry) { + return fs.pathExists(cssCodePath) + } + + const results = await Promise.all( + entryNames.map(entry => fs.pathExists(path.join(outDir, `${entry}.css`))) + ) + return results.every(Boolean) }, hasCssMapFile() { - return fs.pathExists(cssMapPath) + if (!isMultiEntry) { + return fs.pathExists(cssMapPath) + } } } } @@ -69,6 +112,7 @@ function snapshot({ }) { test(title, async () => { let result + const isMultiEntry = typeof input === 'object' try { result = await write({ input, @@ -84,11 +128,25 @@ function snapshot({ throw error } - expect(await result.jsCode()).toMatchSnapshot('js code') + if (isMultiEntry) { + const files = await result.jsCode() + for (const [entry, file] of files) { + expect(file).toMatchSnapshot(`js code ${entry}`) + } + } else { + expect(await result.jsCode()).toMatchSnapshot('js code') + } if (options.extract) { expect(await result.hasCssFile()).toBe(true) - expect(await result.cssCode()).toMatchSnapshot('css code') + if (isMultiEntry) { + const files = await result.cssCode() + for (const [entry, file] of files) { + expect(file).toMatchSnapshot(`css code ${entry}`) + } + } else { + expect(await result.cssCode()).toMatchSnapshot('css code') + } } const sourceMap = options && options.sourceMap @@ -369,6 +427,20 @@ snapshotMany('sass', [ } ]) +snapshotMany('multi-entry', [ + { + title: 'multi-entry', + input: { + entry1: 'multi-entry/entry1.js', + entry2: 'multi-entry/entry2.js' + }, + options: { + extract: true, + multiEntry: true + } + } +]) + test('onExtract', async () => { const result = await write({ input: 'simple/index.js',