diff --git a/package-lock.json b/package-lock.json index 9677671c2..5fe1895ef 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 790406278..447e80ac6 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 f3b042026..9c104d235 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'; @@ -46,9 +47,19 @@ export default function loader(content, map, meta) { 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 +131,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, } @@ -301,31 +310,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 +317,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 92df55072..4194e10a9 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,23 +51,6 @@ 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 false should not generate sourceMap when source map is valid from other loader: module (evaluated) 1`] = ` -Array [ - Array [ - 1, - ".class { - color: red; -} -", - "", - ], -] -`; - -exports[`sourceMap option false should not generate sourceMap when source map is valid from other loader: warnings 1`] = `Array []`; - exports[`sourceMap option true should generate source map when source map is \`null\` from other loader: errors 1`] = `Array []`; exports[`sourceMap option true should generate source map when source map is \`null\` from other loader: module (evaluated) 1`] = ` @@ -100,9 +66,8 @@ Array [ "file": "basic.css", "mappings": "AAAA;EACE,UAAU;AACZ", "names": Array [], - "sourceRoot": "", "sources": Array [ - "/replaced/original/path/", + "basic.css", ], "sourcesContent": Array [ ".class { @@ -133,9 +98,8 @@ Array [ "file": "basic.css", "mappings": "AAAA;EACE,UAAU;AACZ", "names": Array [], - "sourceRoot": "", "sources": Array [ - "/replaced/original/path/", + "basic.css", ], "sourcesContent": Array [ ".class { @@ -151,76 +115,6 @@ Array [ exports[`sourceMap option true should generate source map when source map is \`undefined\` from other loader: warnings 1`] = `Array []`; -exports[`sourceMap option true should generate source map when source map is valid and it is string from other loader: errors 1`] = `Array []`; - -exports[`sourceMap option true should generate source map when source map is valid and it is string from other loader: module (evaluated) 1`] = ` -Array [ - Array [ - 1, - ".class { - color: red; -} -", - "", - Object { - "file": "basic.css", - "mappings": "AAAA;ECCE,UAAU;AACZ", - "names": Array [], - "sourceRoot": "", - "sources": Array [ - "/replaced/original/path/", - "/replaced/original/path/", - ], - "sourcesContent": Array [ - ".class { a: b c d; }", - ".class { - color: red; -} -", - ], - "version": 3, - }, - ], -] -`; - -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: module (evaluated) 1`] = ` -Array [ - Array [ - 1, - ".class { - color: red; -} -", - "", - Object { - "file": "basic.css", - "mappings": "AAAA;ECCE,UAAU;AACZ", - "names": Array [], - "sourceRoot": "", - "sources": Array [ - "/replaced/original/path/", - "/replaced/original/path/", - ], - "sourcesContent": Array [ - ".class { a: b c d; }", - ".class { - color: red; -} -", - ], - "version": 3, - }, - ], -] -`; - -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: errors 1`] = `Array []`; exports[`sourceMap option true should generate source map: module (evaluated) 1`] = ` @@ -236,9 +130,8 @@ Array [ "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/helpers.js b/test/helpers.js index 9a29ee7e1..19b220de8 100644 --- a/test/helpers.js +++ b/test/helpers.js @@ -224,8 +224,22 @@ 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 = path.relative(process.cwd(), m[3].file); + } + + if (m[3].sourceRoot) { + // eslint-disable-next-line no-param-reassign + m[3].sourceRoot = path.relative(process.cwd(), m[3].sourceRoot); + } + + if (m[3].sources) { + // eslint-disable-next-line no-param-reassign + m[3].sources = m[3].sources.map((source) => + path.relative(process.cwd(), source) + ); + } } return m; diff --git a/test/sourceMap-option.test.js b/test/sourceMap-option.test.js index 76d243699..4035f02e6 100644 --- a/test/sourceMap-option.test.js +++ b/test/sourceMap-option.test.js @@ -64,64 +64,6 @@ describe('sourceMap option', () => { expect(stats.compilation.warnings).toMatchSnapshot('warnings'); expect(stats.compilation.errors).toMatchSnapshot('errors'); }); - - it('should generate source map when source map is valid 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; }'], - 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(normalizeSourceMap(evaluated(module.source))).toMatchSnapshot( - 'module (evaluated)' - ); - expect(stats.compilation.warnings).toMatchSnapshot('warnings'); - expect(stats.compilation.errors).toMatchSnapshot('errors'); - }); - - 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: 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(normalizeSourceMap(evaluated(module.source))).toMatchSnapshot( - 'module (evaluated)' - ); - expect(stats.compilation.warnings).toMatchSnapshot('warnings'); - expect(stats.compilation.errors).toMatchSnapshot('errors'); - }); }); describe('false', () => { @@ -181,59 +123,5 @@ describe('sourceMap option', () => { expect(stats.compilation.warnings).toMatchSnapshot('warnings'); expect(stats.compilation.errors).toMatchSnapshot('errors'); }); - - it('should not generate sourceMap when source map is valid 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, - }, - }; - 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'); - }); - - 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, - }, - }, - 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'); - }); }); });