From 553ca85c8efe27007a1be22771bb8719fd54da40 Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Thu, 14 May 2020 20:33:36 +0300 Subject: [PATCH] fix(multi-entry): correct and consistent order of single extracted file --- __tests__/__snapshots__/index.test.ts.snap | 38 ++++++------- __tests__/helpers/index.ts | 18 ++----- __tests__/utils.test.ts | 16 ++++-- jest.config.js | 7 ++- src/index.ts | 62 ++++++++++++---------- 5 files changed, 76 insertions(+), 65 deletions(-) diff --git a/__tests__/__snapshots__/index.test.ts.snap b/__tests__/__snapshots__/index.test.ts.snap index 577d335e..92e8df92 100644 --- a/__tests__/__snapshots__/index.test.ts.snap +++ b/__tests__/__snapshots__/index.test.ts.snap @@ -564,9 +564,15 @@ exports[`code-splitting multi-entry-single: css 1`] = ` ".third_third { color: maroon; } +.third2_third2 { + color: hotpink; } + .fourth_fourth { color: magenta; } +.fourth2_fourth2 { + color: honeydew; } + .first_partial { color: rosybrown; } @@ -576,25 +582,19 @@ exports[`code-splitting multi-entry-single: css 1`] = ` .second_second { color: royalblue; } -.third2_third2 { - color: hotpink; } - -.fourth2_fourth2 { - color: honeydew; } - .otherScript_otherScript { color: wheat; } -.nestedScript_nestedScript { - color: rebeccapurple; } - .nondynamic_nondynamic { color: deepskyblue; } .nondynamic2_nondynamic2 { color: deeppink; } -/*# sourceMappingURL=extracted-ce4cad6d.css.map */" +.nestedScript_nestedScript { + color: rebeccapurple; } + +/*# sourceMappingURL=extracted-332bb2b3.css.map */" `; exports[`code-splitting multi-entry-single: js 1`] = ` @@ -692,7 +692,7 @@ export { css }; " `; -exports[`code-splitting multi-entry-single: map 1`] = `"{\\"version\\":3,\\"sources\\":[\\"../../../../code-splitting/third.scss\\",\\"../../../../code-splitting/fourth.scss\\",\\"../../../../code-splitting/partial.css\\",\\"../../../../code-splitting/first.scss\\",\\"../../../../code-splitting/second.scss\\",\\"../../../../code-splitting/third2.scss\\",\\"../../../../code-splitting/fourth2.scss\\",\\"../../../../code-splitting/other-script.scss\\",\\"../../../../code-splitting/nested-script.scss\\",\\"../../../../code-splitting/nondynamic.scss\\",\\"../../../../code-splitting/nondynamic2.scss\\"],\\"names\\":[],\\"mappings\\":\\"AAAA;EACE,aAAa,EAAA;;ACDf;EACE,cAAc,EAAA;;ACDhB;EACE,gBAAgB;AAClB;ACAA;EACE,UAAU,EAAA;;ACHZ;EACE,gBAAgB,EAAA;;ACDlB;EACE,cAAc,EAAA;;ACDhB;EACE,eAAe,EAAA;;ACDjB;EACE,YAAY,EAAA;;ACDd;EACE,oBAAoB,EAAA;;ACDtB;EACE,kBAAkB,EAAA;;ACDpB;EACE,eAAe,EAAA\\",\\"file\\":\\"extracted-ce4cad6d.css\\",\\"sourcesContent\\":[\\".third {\\\\n color: maroon;\\\\n}\\\\n\\",\\".fourth {\\\\n color: magenta;\\\\n}\\\\n\\",\\".partial {\\\\n color: rosybrown;\\\\n}\\\\n\\",\\"@import \\\\\\"./partial.css\\\\\\";\\\\n\\\\n.first {\\\\n color: red;\\\\n}\\\\n\\",\\".second {\\\\n color: royalblue;\\\\n}\\\\n\\",\\".third2 {\\\\n color: hotpink;\\\\n}\\\\n\\",\\".fourth2 {\\\\n color: honeydew;\\\\n}\\\\n\\",\\".other-script {\\\\n color: wheat;\\\\n}\\\\n\\",\\".nested-script {\\\\n color: rebeccapurple;\\\\n}\\\\n\\",\\".nondynamic {\\\\n color: deepskyblue;\\\\n}\\\\n\\",\\".nondynamic2 {\\\\n color: deeppink;\\\\n}\\\\n\\"]}"`; +exports[`code-splitting multi-entry-single: map 1`] = `"{\\"version\\":3,\\"sources\\":[\\"../../../../code-splitting/third.scss\\",\\"../../../../code-splitting/third2.scss\\",\\"../../../../code-splitting/fourth.scss\\",\\"../../../../code-splitting/fourth2.scss\\",\\"../../../../code-splitting/partial.css\\",\\"../../../../code-splitting/first.scss\\",\\"../../../../code-splitting/second.scss\\",\\"../../../../code-splitting/other-script.scss\\",\\"../../../../code-splitting/nondynamic.scss\\",\\"../../../../code-splitting/nondynamic2.scss\\",\\"../../../../code-splitting/nested-script.scss\\"],\\"names\\":[],\\"mappings\\":\\"AAAA;EACE,aAAa,EAAA;;ACDf;EACE,cAAc,EAAA;;ACDhB;EACE,cAAc,EAAA;;ACDhB;EACE,eAAe,EAAA;;ACDjB;EACE,gBAAgB;AAClB;ACAA;EACE,UAAU,EAAA;;ACHZ;EACE,gBAAgB,EAAA;;ACDlB;EACE,YAAY,EAAA;;ACDd;EACE,kBAAkB,EAAA;;ACDpB;EACE,eAAe,EAAA;;ACDjB;EACE,oBAAoB,EAAA\\",\\"file\\":\\"extracted-332bb2b3.css\\",\\"sourcesContent\\":[\\".third {\\\\n color: maroon;\\\\n}\\\\n\\",\\".third2 {\\\\n color: hotpink;\\\\n}\\\\n\\",\\".fourth {\\\\n color: magenta;\\\\n}\\\\n\\",\\".fourth2 {\\\\n color: honeydew;\\\\n}\\\\n\\",\\".partial {\\\\n color: rosybrown;\\\\n}\\\\n\\",\\"@import \\\\\\"./partial.css\\\\\\";\\\\n\\\\n.first {\\\\n color: red;\\\\n}\\\\n\\",\\".second {\\\\n color: royalblue;\\\\n}\\\\n\\",\\".other-script {\\\\n color: wheat;\\\\n}\\\\n\\",\\".nondynamic {\\\\n color: deepskyblue;\\\\n}\\\\n\\",\\".nondynamic2 {\\\\n color: deeppink;\\\\n}\\\\n\\",\\".nested-script {\\\\n color: rebeccapurple;\\\\n}\\\\n\\"]}"`; exports[`code-splitting single: css 1`] = ` ".third_third { @@ -739,9 +739,9 @@ exports[`code-splitting single: js 2`] = ` "const modules_0858c0ee = {\\"fourth\\":\\"fourth_fourth\\"}; (async () => { - const first = await import('./first-4ee52dc0.js'); - const second = await import('./second-0e0469bf.js'); - const otherScript = await import('./other-script-71e1de4d.js'); + const first = await import('./first-d485e816.js'); + const second = await import('./second-23bff606.js'); + const otherScript = await import('./other-script-2c3340ab.js'); console.log(first, second, otherScript); })(); @@ -764,7 +764,7 @@ exports[`code-splitting single: js 4`] = ` exports[`code-splitting single: js 5`] = ` "(async () => { await import('./noncss-f3feb5ac.js'); - const nestedScript = await import('./nested-script-3a18b46f.js'); + const nestedScript = await import('./nested-script-fb424854.js'); console.log(nestedScript); })(); " @@ -843,9 +843,9 @@ exports[`code-splitting true: js 2`] = ` "const modules_0858c0ee = {\\"fourth\\":\\"fourth_fourth\\"}; (async () => { - const first = await import('./first-4ee52dc0.js'); - const second = await import('./second-0e0469bf.js'); - const otherScript = await import('./other-script-71e1de4d.js'); + const first = await import('./first-d485e816.js'); + const second = await import('./second-23bff606.js'); + const otherScript = await import('./other-script-2c3340ab.js'); console.log(first, second, otherScript); })(); @@ -868,7 +868,7 @@ exports[`code-splitting true: js 4`] = ` exports[`code-splitting true: js 5`] = ` "(async () => { await import('./noncss-f3feb5ac.js'); - const nestedScript = await import('./nested-script-3a18b46f.js'); + const nestedScript = await import('./nested-script-fb424854.js'); console.log(nestedScript); })(); " diff --git a/__tests__/helpers/index.ts b/__tests__/helpers/index.ts index 2dd3cbe2..33bbb70c 100644 --- a/__tests__/helpers/index.ts +++ b/__tests__/helpers/index.ts @@ -1,14 +1,14 @@ /* eslint-disable jest/no-export */ import path from "path"; import fs from "fs-extra"; -import { Plugin, rollup, OutputOptions, RollupOptions } from "rollup"; +import { Plugin, rollup, OutputOptions } from "rollup"; import styles from "../../src"; import { Options } from "../../src/types"; import { inferModeOption } from "../../src/utils/options"; export type WriteData = { - input: NonNullable; + input: string | string[]; title?: string; outDir?: string; options?: Options; @@ -39,18 +39,8 @@ export const fixture = (...args: string[]): string => export async function write(data: WriteData): Promise { const outDir = fixture("dist", data.outDir ?? data.title ?? ""); - - const input = Array.isArray(data.input) - ? data.input.map(i => fixture(i)) - : typeof data.input === "object" - ? Object.entries(data.input).reduce((acc, [k, v]) => ({ ...acc, [k]: fixture(v) }), {}) - : fixture(data.input); - - const multiEntry = Array.isArray(data.input) - ? data.input.length > 1 - : typeof data.input === "object" - ? Object.keys(data.input).length > 1 - : false; + const input = Array.isArray(data.input) ? data.input.map(i => fixture(i)) : fixture(data.input); + const multiEntry = Array.isArray(data.input) ? data.input.length > 1 : false; const bundle = await rollup({ input, diff --git a/__tests__/utils.test.ts b/__tests__/utils.test.ts index a9a60b1c..dc5a40c0 100644 --- a/__tests__/utils.test.ts +++ b/__tests__/utils.test.ts @@ -1,14 +1,22 @@ -import { ensurePCSSOption } from "../src/utils/options"; -import { loadSass } from "../src/loaders/sass/load"; -import Loaders from "../src/loaders"; +import postcss from "postcss"; import { Payload } from "../src/types"; -import { fixture } from "./helpers"; +import Loaders from "../src/loaders"; +import postcssNoop from "../src/loaders/postcss/noop"; +import { loadSass } from "../src/loaders/sass/load"; +import { ensurePCSSOption } from "../src/utils/options"; import { mm, getMap, stripMap } from "../src/utils/sourcemap"; import { humanlizePath } from "../src/utils/path"; +import { fixture } from "./helpers"; + jest.mock("../src/utils/load-module", () => jest.fn()); import loadModuleMock from "../src/utils/load-module"; +test("noop", async () => { + const { css } = await postcss(postcssNoop).process(".foo{color:red}", { from: "simple.css" }); + expect(css).toBe(".foo{color:red}"); +}); + describe("load-module", () => { const loadModule = jest.requireActual("../src/utils/load-module") .default as typeof loadModuleMock; diff --git a/jest.config.js b/jest.config.js index 4a265635..70a77b82 100644 --- a/jest.config.js +++ b/jest.config.js @@ -5,5 +5,10 @@ module.exports = { globals: { "ts-jest": { packageJson: "package.json" } }, testMatch: ["/__tests__/*.(spec|test).[jt]s?(x)"], setupFilesAfterEnv: ["/__tests__/setup.ts"], - collectCoverageFrom: ["/src/**/*.[jt]s?(x)", "!**/*.d.ts"], + collectCoverageFrom: [ + "/src/**/*.[jt]s?(x)", + "/__tests__/*.[jt]s?(x)", + "/__tests__/helpers/*.[jt]s?(x)", + "!**/*.d.ts", + ], }; diff --git a/src/index.ts b/src/index.ts index 2d3a783d..f73f91e2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -145,7 +145,6 @@ export default (options: Options = {}): Plugin => { if (extracted.size === 0 || !(opts.dir || opts.file)) return; const infoFn = this.getModuleInfo.bind(this); - const moduleIds = [...this.moduleIds]; const dir = opts.dir ?? path.dirname(opts.file ?? ""); @@ -175,7 +174,7 @@ export default (options: Options = {}): Plugin => { const entries = [...extracted.values()] .filter(e => ids.includes(e.id)) - .sort((a, b) => moduleIds.indexOf(a.id) - moduleIds.indexOf(b.id)); + .sort((a, b) => ids.indexOf(a.id) - ids.indexOf(b.id)); const concat = new Concat(true, path.basename(fileName), "\n"); for (const res of entries) { @@ -193,47 +192,56 @@ export default (options: Options = {}): Plugin => { }; const getEmitted = (): Map => { + const moduleIds = [...this.moduleIds]; const chunks: OutputChunk[] = []; - const entries = Object.values(bundle).filter((c): c is OutputChunk => { + const [index, ...entries] = Object.values(bundle).filter((c): c is OutputChunk => { if (c.type !== "chunk") return false; if (c.isEntry) return true; chunks.push(c); return false; }); - const [index] = entries.splice(0, 1); const idsMap = new Map(); - const ids: string[] = []; - if (typeof postcssLoaderOpts.extract !== "string") { - const chunkIds: string[] = []; - for (const chunk of chunks) { - const ids = getIds(chunk, infoFn) - .filter(isSupported) - .sort((a, b) => moduleIds.indexOf(a) - moduleIds.indexOf(b)); + const chunkIds: string[] = []; + for (const chunk of chunks) { + const ids = getIds(chunk, infoFn) + .filter(isSupported) + .sort((a, b) => moduleIds.indexOf(a) - moduleIds.indexOf(b)); - if (ids.length === 0) continue; + if (ids.length === 0) continue; + chunkIds.push(...ids); - chunkIds.push(...ids); - idsMap.set(chunk.name, ids); - } + if (typeof postcssLoaderOpts.extract === "string") continue; + idsMap.set(chunk.name, ids); + } - const entryIds: string[] = []; - for (const entry of entries) { - const ids = getIds(entry, infoFn) - .filter(id => !chunkIds.includes(id) && isSupported(id)) - .sort((a, b) => moduleIds.indexOf(a) - moduleIds.indexOf(b)); + const entryIds: string[] = []; + for (const entry of entries) { + const ids = getIds(entry, infoFn) + .filter(id => !chunkIds.includes(id) && isSupported(id)) + .sort((a, b) => moduleIds.indexOf(a) - moduleIds.indexOf(b)); - if (ids.length === 0) continue; + if (ids.length === 0) continue; + entryIds.push(...ids); - entryIds.push(...ids); - idsMap.set(entry.name, ids); - } - - ids.push(...chunkIds, ...entryIds); + if (typeof postcssLoaderOpts.extract === "string") continue; + idsMap.set(entry.name, ids); } - const indexIds = moduleIds.filter(id => !ids.includes(id) && isSupported(id)); + const orderedIds = [ + ...moduleIds.filter(id => !entryIds.includes(id) && !chunkIds.includes(id)), + ...entryIds, + ...chunkIds, + ]; + + const indexIds = moduleIds + .filter(id => { + if (typeof postcssLoaderOpts.extract === "string") return isSupported(id); + return !entryIds.includes(id) && !chunkIds.includes(id) && isSupported(id); + }) + .sort((a, b) => orderedIds.lastIndexOf(a) - orderedIds.lastIndexOf(b)); + if (indexIds.length > 0) { idsMap.set( opts.file ? path.basename(opts.file, path.extname(opts.file)) : index.name,