From e9ce745db43b6a66149443dd62ee418ded72dffe Mon Sep 17 00:00:00 2001 From: Evilebot Tnawi Date: Wed, 6 Mar 2019 17:48:49 +0300 Subject: [PATCH] fix: source map generation when `sourceRoot` is present (#901) --- package-lock.json | 67 +++--- package.json | 1 + src/index.js | 57 ++--- .../sourceMap-option.test.js.snap | 226 ++++++++++++++---- test/fixtures/source-map/basic.postcss.css | 35 +++ test/fixtures/source-map/basic.scss | 7 + test/helpers.js | 25 +- test/sourceMap-option.test.js | 136 ++++++----- 8 files changed, 362 insertions(+), 192 deletions(-) create mode 100644 test/fixtures/source-map/basic.postcss.css create mode 100644 test/fixtures/source-map/basic.scss diff --git a/package-lock.json b/package-lock.json index 9677671c..5fe1895e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1032,15 +1032,6 @@ "any-observable": "^0.3.0" } }, - "@types/babel__traverse": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.6.tgz", - "integrity": "sha512-XYVgHF2sQ0YblLRMLNPB3CkFMewzFmlDsH/TneZFHUXDlABQgh88uOxuez7ZcXxayLFrqLwtDH1t+FmlFwNZxw==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, "@types/node": { "version": "10.12.29", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.29.tgz", @@ -1719,13 +1710,10 @@ } }, "babel-plugin-jest-hoist": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.2.0.tgz", - "integrity": "sha512-U63Kx0ZbB6TFjcmRRZvkQfkBlh8beJ1q8CsO+cl4uAlr7bLZM0isvQP369fUEZeJJr/1yqRplzHj14TAmQ1r0Q==", - "dev": true, - "requires": { - "@types/babel__traverse": "^7.0.6" - } + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.1.0.tgz", + "integrity": "sha512-gljYrZz8w1b6fJzKcsfKsipSru2DU2DmQ39aB6nV3xQ0DDv3zpIzKGortA5gknrhNnPN8DweaEgrnZdmbGmhnw==", + "dev": true }, "babel-polyfill": { "version": "6.26.0", @@ -3592,9 +3580,9 @@ "dev": true }, "diff-sequences": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.2.0.tgz", - "integrity": "sha512-yvZNXjhIhe9DwBOKfdr1HKmvld95EzQkZOUjlZlPzzIBy01TM8oDweo2PT9WJmaHd8+J7DC8etgbJGHWWuVJxQ==", + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.0.0.tgz", + "integrity": "sha512-46OkIuVGBBnrC0soO/4LHu5LHGHx0uhP65OVz8XOrAJpqiCB2aVIuESvjI1F9oqebuvY8lekS1pt6TN7vt7qsw==", "dev": true }, "diffie-hellman": { @@ -6771,9 +6759,9 @@ } }, "jest-docblock": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.2.0.tgz", - "integrity": "sha512-BCo9v+rB61Hte9r2WUS2YHIsKVjW3oGnY2BhWZtSks2gxQjuDVR5QMGKVAywQtOCwmH92O9p2NgNpfpeu4MY8A==", + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.0.0.tgz", + "integrity": "sha512-KfAKZ4SN7CFOZpWg4i7g7MSlY0M+mq7K0aMqENaG2vHuhC9fc3vkpU/iNN9sOus7v3h3Y48uEjqz3+Gdn2iptA==", "dev": true, "requires": { "detect-newline": "^2.1.0" @@ -6813,9 +6801,9 @@ } }, "jest-get-type": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.2.0.tgz", - "integrity": "sha512-IWrgF05BU05R7vXs+UfL9NbPfInotQWZMWv5T/jU3h/wH7qg2GGZ/hqR7zA/+n6TtWvT/E2vBxCkB/3s6pHrIg==", + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.0.0.tgz", + "integrity": "sha512-z6/Eyf6s9ZDGz7eOvl+fzpuJmN9i0KyTt1no37/dHu8galssxz5ZEgnc1KaV8R31q1khxyhB4ui/X5ZjjPk77w==", "dev": true }, "jest-haste-map": { @@ -6895,9 +6883,9 @@ "dev": true }, "jest-regex-util": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.2.0.tgz", - "integrity": "sha512-6zXSsbUdAPIbtThixsYMN+YsDW9yJ+ZOg5DfkdyPrk/I7CVkaXwD0eouNRWA3vD1NZXlgTbpoLXMYYC0gr0GYw==", + "version": "24.0.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.0.0.tgz", + "integrity": "sha512-Jv/uOTCuC+PY7WpJl2mpoI+WbY2ut73qwwO9ByJJNwOCwr1qWhEW2Lyi2S9ZewUdJqeVpEBisdEVZSI+Zxo58Q==", "dev": true }, "jest-resolve": { @@ -8230,8 +8218,7 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "normalize-range": { "version": "0.1.2", @@ -9265,9 +9252,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.0.tgz", - "integrity": "sha512-E4EHwWgh5NIh/F44hYfQHR1jwejCza1ktpeWTetDtc71hxdDmWPjfSs28/58DBDIKxz5Dxlw8oW6am2ph/OCkg==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.1.tgz", + "integrity": "sha512-bg46FvHx2lSHput5J4xCiCHrRxjza73jceSW8JcOVNzCEnlhuZF7pLa7K0KpNt8whL7C8V5wdb0bSrCRg0w13g==", "requires": { "cssesc": "^3.0.0", "indexes-of": "^1.0.1", @@ -9611,9 +9598,9 @@ "dev": true }, "regenerate-unicode-properties": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.0.0.tgz", - "integrity": "sha512-tlYkVh6F/QXtosuyOZV2SkOtA248fjMAUWjGf8aYBvQK1ZMarbMvFBvkguSt93HhdXh20m15sc4b5EIBxXLHQQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.0.1.tgz", + "integrity": "sha512-HTjMafphaH5d5QDHuwW8Me6Hbc/GhXg8luNqTkPVwZ/oCZhnoifjWhGYsu2BzepMELTlbnoVcXvV0f+2uDDvoQ==", "dev": true, "requires": { "regenerate": "^1.4.0" @@ -9657,13 +9644,13 @@ "dev": true }, "regexpu-core": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.2.tgz", - "integrity": "sha512-CgGxXmuX0Cf57z7KahSHe4kaNY8gBRCFFEretQ5AHsnlLx/5VdCrQOoOz1POxLdZjPbwE5ncTspPJwp2WHPcHA==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.3.tgz", + "integrity": "sha512-LON8666bTAlViVEPXMv65ZqiaR3rMNLz36PIaQ7D+er5snu93k0peR7FSvO0QteYbZ3GOkvfHKbGr/B1xDu9FA==", "dev": true, "requires": { "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.0.0", + "regenerate-unicode-properties": "^8.0.1", "regjsgen": "^0.5.0", "regjsparser": "^0.6.0", "unicode-match-property-ecmascript": "^1.0.4", diff --git a/package.json b/package.json index 79040627..447e80ac 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "icss-utils": "^4.1.0", "loader-utils": "^1.2.3", "camelcase": "^5.2.0", + "normalize-path": "^3.0.0", "postcss": "^7.0.14", "postcss-modules-extract-imports": "^2.0.0", "postcss-modules-local-by-default": "^2.0.6", diff --git a/src/index.js b/src/index.js index f3b04202..c499ce2a 100644 --- a/src/index.js +++ b/src/index.js @@ -17,6 +17,7 @@ import { getCurrentRequest, stringifyRequest, } from 'loader-utils'; +import normalizePath from 'normalize-path'; import schema from './options.json'; import { importParser, icssParser, urlParser } from './plugins'; @@ -42,13 +43,24 @@ export default function loader(content, map, meta) { /* eslint-disable no-param-reassign */ if (sourceMap) { if (map) { + // Some loader emit source map as string if (typeof map === 'string') { map = JSON.stringify(map); } + // Source maps should use forward slash because it is URLs (https://github.com/mozilla/source-map/issues/91) + // We should normalize path because previous loaders like `sass-loader` using backslash when generate source map + + if (map.file) { + map.file = normalizePath(map.file); + } + + if (map.sourceRoot) { + map.sourceRoot = normalizePath(map.sourceRoot); + } + if (map.sources) { - map.sources = map.sources.map((source) => source.replace(/\\/g, '/')); - map.sourceRoot = ''; + map.sources = map.sources.map((source) => normalizePath(source)); } } } else { @@ -120,17 +132,15 @@ export default function loader(content, map, meta) { postcss(plugins) .process(content, { - // we need a prefix to avoid path rewriting of PostCSS - from: `/css-loader!${getRemainingRequest(this) + from: getRemainingRequest(this) .split('!') - .pop()}`, + .pop(), to: getCurrentRequest(this) .split('!') .pop(), map: options.sourceMap ? { prev: map, - sourcesContent: true, inline: false, annotation: false, } @@ -141,6 +151,14 @@ export default function loader(content, map, meta) { .warnings() .forEach((warning) => this.emitWarning(new Warning(warning))); + if (result.map) { + const newMap = result.map.toJSON(); + + console.log(newMap.file); + console.log(newMap.sourceRoot); + console.log(newMap.sources); + } + const messages = result.messages || []; // Run other loader (`postcss-loader`, `sass-loader` and etc) for importing CSS @@ -301,31 +319,6 @@ export default function loader(content, map, meta) { ); }); - let newMap = result.map; - - if (sourceMap && newMap) { - // Add a SourceMap - newMap = newMap.toJSON(); - - if (newMap.sources) { - newMap.sources = newMap.sources.map( - (source) => - source - .split('!') - .pop() - .replace(/\\/g, '/'), - this - ); - newMap.sourceRoot = ''; - } - - newMap.file = newMap.file - .split('!') - .pop() - .replace(/\\/g, '/'); - newMap = JSON.stringify(newMap); - } - const runtimeCode = `exports = module.exports = require(${stringifyRequest( this, require.resolve('./runtime/api') @@ -333,7 +326,7 @@ export default function loader(content, map, meta) { const importCode = imports.length > 0 ? `// Imports\n${imports.join('\n')}\n\n` : ''; const moduleCode = `// Module\nexports.push([module.id, ${cssAsString}, ""${ - newMap ? `,${newMap}` : '' + result.map ? `,${result.map}` : '' }]);\n\n`; const exportsCode = exports.length > 0 diff --git a/test/__snapshots__/sourceMap-option.test.js.snap b/test/__snapshots__/sourceMap-option.test.js.snap index 92df5507..43c55cae 100644 --- a/test/__snapshots__/sourceMap-option.test.js.snap +++ b/test/__snapshots__/sourceMap-option.test.js.snap @@ -34,23 +34,6 @@ Array [ exports[`sourceMap option false should not generate source map when source map is \`undefined\` from other loader: warnings 1`] = `Array []`; -exports[`sourceMap option false should not generate source map when source map is valid and it is string from other loader: errors 1`] = `Array []`; - -exports[`sourceMap option false should not generate source map when source map is valid and it is string from other loader: module (evaluated) 1`] = ` -Array [ - Array [ - 1, - ".class { - color: red; -} -", - "", - ], -] -`; - -exports[`sourceMap option false should not generate source map when source map is valid and it is string from other loader: warnings 1`] = `Array []`; - exports[`sourceMap option false should not generate source map: errors 1`] = `Array []`; exports[`sourceMap option false should not generate source map: module (evaluated) 1`] = ` @@ -68,22 +51,22 @@ Array [ exports[`sourceMap option false should not generate source map: warnings 1`] = `Array []`; -exports[`sourceMap option false should not generate sourceMap when source map is valid from other loader: errors 1`] = `Array []`; +exports[`sourceMap option should not generate sourceMap when source map is valid from other loader (\`sass-loader\`): errors 1`] = `Array []`; -exports[`sourceMap option false should not generate sourceMap when source map is valid from other loader: module (evaluated) 1`] = ` +exports[`sourceMap option should not generate sourceMap when source map is valid from other loader (\`sass-loader\`): module (evaluated) 1`] = ` Array [ Array [ 1, - ".class { - color: red; -} -", + "body { + font: 100% Helvetica, sans-serif; + color: #333; +}", "", ], ] `; -exports[`sourceMap option false should not generate sourceMap when source map is valid from other loader: warnings 1`] = `Array []`; +exports[`sourceMap option should not generate sourceMap when source map is valid from other loader (\`sass-loader\`): warnings 1`] = `Array []`; exports[`sourceMap option true should generate source map when source map is \`null\` from other loader: errors 1`] = `Array []`; @@ -97,12 +80,11 @@ Array [ ", "", Object { - "file": "basic.css", + "file": "../../basic.css", "mappings": "AAAA;EACE,UAAU;AACZ", "names": Array [], - "sourceRoot": "", "sources": Array [ - "/replaced/original/path/", + "../../basic.css", ], "sourcesContent": Array [ ".class { @@ -130,12 +112,11 @@ Array [ ", "", Object { - "file": "basic.css", + "file": "../../basic.css", "mappings": "AAAA;EACE,UAAU;AACZ", "names": Array [], - "sourceRoot": "", "sources": Array [ - "/replaced/original/path/", + "../../basic.css", ], "sourcesContent": Array [ ".class { @@ -163,16 +144,50 @@ Array [ ", "", Object { - "file": "basic.css", - "mappings": "AAAA;ECCE,UAAU;AACZ", + "file": "../../basic.css", + "mappings": "AAGA;EACE,UAAA;ACFF", "names": Array [], - "sourceRoot": "", "sources": Array [ - "/replaced/original/path/", - "/replaced/original/path/", + "source-map/basic.postcss.css", + "../../basic.css", ], "sourcesContent": Array [ - ".class { a: b c d; }", + "@custom-media --viewport-medium (width <= 50rem); +@custom-selector :--heading h1, h2, h3, h4, h5, h6; + +:root { + --fontSize: 1rem; + --mainColor: #12345678; + --secondaryColor: lab(32.5 38.5 -47.6 / 90%); +} + +html { + overflow: hidden auto; +} + +@media (--viewport-medium) { + body { + color: var(--mainColor); + font-family: system-ui; + font-size: var(--fontSize); + line-height: calc(var(--fontSize) * 1.5); + overflow-wrap: break-word; + padding-inline: calc(var(--fontSize) / 2 + 1px); + } +} + +:--heading { + margin-block: 0; +} + +a { + color: rgb(0 0 100% / 90%); + +&:hover { + color: rebeccapurple; + } +} +", ".class { color: red; } @@ -186,32 +201,140 @@ Array [ exports[`sourceMap option true should generate source map when source map is valid and it is string from other loader: warnings 1`] = `Array []`; -exports[`sourceMap option true should generate source map when source map is valid from other loader: errors 1`] = `Array []`; +exports[`sourceMap option true should generate source map when source map is valid from other loader (\`postcss-loader\`): errors 1`] = `Array []`; -exports[`sourceMap option true should generate source map when source map is valid from other loader: module (evaluated) 1`] = ` +exports[`sourceMap option true should generate source map when source map is valid from other loader (\`postcss-loader\`): module (evaluated) 1`] = ` Array [ Array [ 1, - ".class { - color: red; + ":root { + --fontSize: 1rem; + --mainColor: rgba(18,52,86,0.47059); + --secondaryColor: rgba(102, 51, 153, 0.9); +} + +html { + overflow-x: hidden; + overflow-y: auto; + overflow: hidden auto; +} + +@media (max-width: 50rem) { + body { + color: rgba(18,52,86,0.47059); + color: var(--mainColor); + font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif; + font-size: 1rem; + font-size: var(--fontSize); + line-height: calc(1rem * 1.5); + line-height: calc(var(--fontSize) * 1.5); + word-wrap: break-word; + padding-left: calc(1rem / 2 + 1px); + padding-right: calc(1rem / 2 + 1px); + padding-left: calc(var(--fontSize) / 2 + 1px); + padding-right: calc(var(--fontSize) / 2 + 1px); + } +} + +h1,h2,h3,h4,h5,h6 { + margin-top: 0; + margin-bottom: 0; +} + +a { + color: rgba(0, 0, 255, 0.9) } + +a:hover { + color: #639; + } ", "", Object { - "file": "basic.css", - "mappings": "AAAA;ECCE,UAAU;AACZ", + "file": "../../basic.postcss.css", + "mappings": "AAGA;EACE,gBAAgB;EAChB,mCAAsB;EACtB,yCAA4C;AAC9C;;AAEA;EACE,kBAAqB;EAArB,gBAAqB;EAArB,qBAAqB;AACvB;;AAEA;EACE;IACE,6BAAuB;IAAvB,uBAAuB;IACvB,iGAAsB;IACtB,eAA0B;IAA1B,0BAA0B;IAC1B,6BAAwC;IAAxC,wCAAwC;IACxC,qBAAyB;IACzB,kCAA+C;IAA/C,mCAA+C;IAA/C,6CAA+C;IAA/C,8CAA+C;EACjD;AACF;;AAEA;EACE,aAAe;EAAf,gBAAe;AACjB;;AAEA;EACE;AAKF;;AAHA;GACG,WAAoB;CACtB", "names": Array [], - "sourceRoot": "", "sources": Array [ - "/replaced/original/path/", - "/replaced/original/path/", + "../../basic.postcss.css", ], "sourcesContent": Array [ - ".class { a: b c d; }", - ".class { - color: red; + "@custom-media --viewport-medium (width <= 50rem); +@custom-selector :--heading h1, h2, h3, h4, h5, h6; + +:root { + --fontSize: 1rem; + --mainColor: #12345678; + --secondaryColor: lab(32.5 38.5 -47.6 / 90%); +} + +html { + overflow: hidden auto; +} + +@media (--viewport-medium) { + body { + color: var(--mainColor); + font-family: system-ui; + font-size: var(--fontSize); + line-height: calc(var(--fontSize) * 1.5); + overflow-wrap: break-word; + padding-inline: calc(var(--fontSize) / 2 + 1px); + } +} + +:--heading { + margin-block: 0; +} + +a { + color: rgb(0 0 100% / 90%); + +&:hover { + color: rebeccapurple; + } +} +", + ], + "version": 3, + }, + ], +] +`; + +exports[`sourceMap option true should generate source map when source map is valid from other loader (\`postcss-loader\`): warnings 1`] = `Array []`; + +exports[`sourceMap option true should generate source map when source map is valid from other loader (\`sass-loader\`): errors 1`] = `Array []`; + +exports[`sourceMap option true should generate source map when source map is valid from other loader (\`sass-loader\`): module (evaluated) 1`] = ` +Array [ + Array [ + 1, + "body { + font: 100% Helvetica, sans-serif; + color: #333; +}", + "", + Object { + "file": "../../basic.scss", + "mappings": "AAGA;EACE,gCAAA;EACA,WAJc;ACEhB", + "names": Array [], + "sources": Array [ + "source-map/basic.scss", + "../../basic.scss", + ], + "sourcesContent": Array [ + "$font-stack: Helvetica, sans-serif; +$primary-color: #333; + +body { + font: 100% $font-stack; + color: $primary-color; } ", + "body { + font: 100% Helvetica, sans-serif; + color: #333; +}", ], "version": 3, }, @@ -219,7 +342,7 @@ Array [ ] `; -exports[`sourceMap option true should generate source map when source map is valid from other loader: warnings 1`] = `Array []`; +exports[`sourceMap option true should generate source map when source map is valid from other loader (\`sass-loader\`): warnings 1`] = `Array []`; exports[`sourceMap option true should generate source map: errors 1`] = `Array []`; @@ -233,12 +356,11 @@ Array [ ", "", Object { - "file": "basic.css", + "file": "../../basic.css", "mappings": "AAAA;EACE,UAAU;AACZ", "names": Array [], - "sourceRoot": "", "sources": Array [ - "/replaced/original/path/", + "../../basic.css", ], "sourcesContent": Array [ ".class { diff --git a/test/fixtures/source-map/basic.postcss.css b/test/fixtures/source-map/basic.postcss.css new file mode 100644 index 00000000..b95d332e --- /dev/null +++ b/test/fixtures/source-map/basic.postcss.css @@ -0,0 +1,35 @@ +@custom-media --viewport-medium (width <= 50rem); +@custom-selector :--heading h1, h2, h3, h4, h5, h6; + +:root { + --fontSize: 1rem; + --mainColor: #12345678; + --secondaryColor: lab(32.5 38.5 -47.6 / 90%); +} + +html { + overflow: hidden auto; +} + +@media (--viewport-medium) { + body { + color: var(--mainColor); + font-family: system-ui; + font-size: var(--fontSize); + line-height: calc(var(--fontSize) * 1.5); + overflow-wrap: break-word; + padding-inline: calc(var(--fontSize) / 2 + 1px); + } +} + +:--heading { + margin-block: 0; +} + +a { + color: rgb(0 0 100% / 90%); + +&:hover { + color: rebeccapurple; + } +} diff --git a/test/fixtures/source-map/basic.scss b/test/fixtures/source-map/basic.scss new file mode 100644 index 00000000..1a72d52f --- /dev/null +++ b/test/fixtures/source-map/basic.scss @@ -0,0 +1,7 @@ +$font-stack: Helvetica, sans-serif; +$primary-color: #333; + +body { + font: 100% $font-stack; + color: $primary-color; +} diff --git a/test/helpers.js b/test/helpers.js index 9a29ee7e..c0bece72 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -5,6 +5,7 @@ const del = require('del'); const webpack = require('webpack'); const MemoryFS = require('memory-fs'); const stripAnsi = require('strip-ansi'); +const normalizePath = require('normalize-path'); function evaluated(output, modules, moduleId = 1) { let m; @@ -224,8 +225,28 @@ function normalizeErrors(errors) { function normalizeSourceMap(module) { return module.map((m) => { if (m[3]) { - // eslint-disable-next-line no-param-reassign - m[3].sources = m[3].sources.map(() => '/replaced/original/path/'); + if (m[3].file) { + // eslint-disable-next-line no-param-reassign + m[3].file = normalizePath( + path.relative(path.resolve(__dirname, 'fixtures'), m[3].file) + ); + } + + if (m[3].sourceRoot) { + // eslint-disable-next-line no-param-reassign + m[3].sourceRoot = normalizePath( + path.relative(path.resolve(__dirname, 'fixtures'), m[3].sourceRoot) + ); + } + + if (m[3].sources) { + // eslint-disable-next-line no-param-reassign + m[3].sources = m[3].sources.map((source) => + normalizePath( + path.relative(path.resolve(__dirname, 'fixtures'), source) + ) + ); + } } return m; diff --git a/test/sourceMap-option.test.js b/test/sourceMap-option.test.js index 76d24369..04ba498f 100644 --- a/test/sourceMap-option.test.js +++ b/test/sourceMap-option.test.js @@ -1,3 +1,7 @@ +const path = require('path'); + +const postcssPresetEnv = require('postcss-preset-env'); + const { webpack, evaluated, normalizeSourceMap } = require('./helpers'); describe('sourceMap option', () => { @@ -65,22 +69,26 @@ describe('sourceMap option', () => { expect(stats.compilation.errors).toMatchSnapshot('errors'); }); - it('should generate source map when source map is valid from other loader', async () => { + it('should generate source map when source map is valid and it is string from other loader', async () => { const config = { loader: { options: { sourceMap: true, }, }, - sourceMap: { - file: 'test.css', - mappings: 'AAAA,SAAS,SAAS,EAAE', - names: [], - sourceRoot: '', - sources: ['/folder/test.css'], - sourcesContent: ['.class { a: b c d; }'], + sourceMap: JSON.stringify({ version: 3, - }, + sources: [ + path.join(__dirname, 'fixtures/source-map/basic.postcss.css'), + ], + names: [], + mappings: + 'AAGA;EACE,gBAAgB;EAChB,mCAAsB;EACtB,yCAA4C;AAC9C;;AAEA;EACE,kBAAqB;EAArB,gBAAqB;EAArB,qBAAqB;AACvB;;AAEA;EACE;IACE,6BAAuB;IAAvB,uBAAuB;IACvB,iGAAsB;IACtB,eAA0B;IAA1B,0BAA0B;IAC1B,6BAAwC;IAAxC,wCAAwC;IACxC,qBAAyB;IACzB,kCAA+C;IAA/C,mCAA+C;IAA/C,6CAA+C;IAA/C,8CAA+C;EACjD;AACF;;AAEA;EACE,aAAe;EAAf,gBAAe;AACjB;;AAEA;EACE;AAKF;;AAHA;GACG,WAAoB;CACtB', + file: path.join(__dirname, 'fixtures/source-map/basic.postcss.css'), + sourcesContent: [ + '@custom-media --viewport-medium (width <= 50rem);\n@custom-selector :--heading h1, h2, h3, h4, h5, h6;\n\n:root {\n --fontSize: 1rem;\n --mainColor: #12345678;\n --secondaryColor: lab(32.5 38.5 -47.6 / 90%);\n}\n\nhtml {\n overflow: hidden auto;\n}\n\n@media (--viewport-medium) {\n body {\n color: var(--mainColor);\n font-family: system-ui;\n font-size: var(--fontSize);\n line-height: calc(var(--fontSize) * 1.5);\n overflow-wrap: break-word;\n padding-inline: calc(var(--fontSize) / 2 + 1px);\n }\n}\n\n:--heading {\n margin-block: 0;\n}\n\na {\n color: rgb(0 0 100% / 90%);\n\n&:hover {\n color: rebeccapurple;\n }\n}\n', + ], + }), }; const testId = './source-map/basic.css'; const stats = await webpack(testId, config); @@ -94,24 +102,22 @@ describe('sourceMap option', () => { expect(stats.compilation.errors).toMatchSnapshot('errors'); }); - it('should generate source map when source map is valid and it is string from other loader', async () => { + it('should generate source map when source map is valid from other loader (`sass-loader`)', async () => { const config = { loader: { + test: /\.s[ca]ss$/i, options: { sourceMap: true, }, }, - sourceMap: JSON.stringify({ - file: 'test.css', - mappings: 'AAAA,SAAS,SAAS,EAAE', - names: [], - sourceRoot: '', - sources: ['/folder/test.css'], - sourcesContent: ['.class { a: b c d; }'], - version: 3, - }), + sassLoader: true, + sassLoaderOptions: { + // eslint-disable-next-line global-require + implementation: require('sass'), + sourceMap: true, + }, }; - const testId = './source-map/basic.css'; + const testId = './source-map/basic.scss'; const stats = await webpack(testId, config); const { modules } = stats.toJson(); const module = modules.find((m) => m.id === testId); @@ -122,35 +128,41 @@ describe('sourceMap option', () => { expect(stats.compilation.warnings).toMatchSnapshot('warnings'); expect(stats.compilation.errors).toMatchSnapshot('errors'); }); - }); - describe('false', () => { - it('should not generate source map', async () => { + it('should generate source map when source map is valid from other loader (`postcss-loader`)', async () => { const config = { loader: { options: { - sourceMap: false, + sourceMap: true, }, }, + postcssLoader: true, + postcssLoaderOptions: { + sourceMap: true, + plugins: () => [postcssPresetEnv({ stage: 0 })], + }, }; - const testId = './source-map/basic.css'; + const testId = './source-map/basic.postcss.css'; const stats = await webpack(testId, config); const { modules } = stats.toJson(); const module = modules.find((m) => m.id === testId); - expect(evaluated(module.source)).toMatchSnapshot('module (evaluated)'); + expect(normalizeSourceMap(evaluated(module.source))).toMatchSnapshot( + 'module (evaluated)' + ); expect(stats.compilation.warnings).toMatchSnapshot('warnings'); expect(stats.compilation.errors).toMatchSnapshot('errors'); }); + }); - it('should not generate source map when source map is `null` from other loader', async () => { + describe('false', () => { + it('should not generate source map', async () => { const config = { loader: { options: { sourceMap: false, }, }, - sourceMap: null, }; const testId = './source-map/basic.css'; const stats = await webpack(testId, config); @@ -162,15 +174,14 @@ describe('sourceMap option', () => { expect(stats.compilation.errors).toMatchSnapshot('errors'); }); - it('should not generate source map when source map is `undefined` from other loader', async () => { + it('should not generate source map when source map is `null` from other loader', async () => { const config = { loader: { options: { sourceMap: false, }, }, - // eslint-disable-next-line no-undefined - sourceMap: undefined, + sourceMap: null, }; const testId = './source-map/basic.css'; const stats = await webpack(testId, config); @@ -182,22 +193,15 @@ describe('sourceMap option', () => { expect(stats.compilation.errors).toMatchSnapshot('errors'); }); - it('should not generate sourceMap when source map is valid from other loader', async () => { + it('should not generate source map when source map is `undefined` from other loader', async () => { const config = { loader: { options: { sourceMap: false, }, }, - sourceMap: { - file: 'test.css', - mappings: 'AAAA,SAAS,SAAS,EAAE', - names: [], - sourceRoot: '', - sources: ['/folder/test.css'], - sourcesContent: ['.class { a: b c d; }'], - version: 3, - }, + // eslint-disable-next-line no-undefined + sourceMap: undefined, }; const testId = './source-map/basic.css'; const stats = await webpack(testId, config); @@ -208,32 +212,32 @@ describe('sourceMap option', () => { expect(stats.compilation.warnings).toMatchSnapshot('warnings'); expect(stats.compilation.errors).toMatchSnapshot('errors'); }); + }); - it('should not generate source map when source map is valid and it is string from other loader', async () => { - const config = { - loader: { - options: { - sourceMap: false, - }, + it('should not generate sourceMap when source map is valid from other loader (`sass-loader`)', async () => { + const config = { + loader: { + test: /\.s[ca]ss$/i, + options: { + sourceMap: false, }, - sourceMap: JSON.stringify({ - file: 'test.css', - mappings: 'AAAA,SAAS,SAAS,EAAE', - names: [], - sourceRoot: '', - sources: ['/folder/test.css'], - sourcesContent: ['.class { a: b c d; }'], - version: 3, - }), - }; - const testId = './source-map/basic.css'; - const stats = await webpack(testId, config); - const { modules } = stats.toJson(); - const module = modules.find((m) => m.id === testId); - - expect(evaluated(module.source)).toMatchSnapshot('module (evaluated)'); - expect(stats.compilation.warnings).toMatchSnapshot('warnings'); - expect(stats.compilation.errors).toMatchSnapshot('errors'); - }); + }, + sassLoader: true, + sassLoaderOptions: { + // eslint-disable-next-line global-require + implementation: require('sass'), + sourceMap: true, + }, + }; + const testId = './source-map/basic.scss'; + const stats = await webpack(testId, config); + const { modules } = stats.toJson(); + const module = modules.find((m) => m.id === testId); + + expect(normalizeSourceMap(evaluated(module.source))).toMatchSnapshot( + 'module (evaluated)' + ); + expect(stats.compilation.warnings).toMatchSnapshot('warnings'); + expect(stats.compilation.errors).toMatchSnapshot('errors'); }); });