Skip to content

Commit

Permalink
refactor: sourcemap paths
Browse files Browse the repository at this point in the history
BREAKING CHANGE: source map contains absolute `sources`
  • Loading branch information
cap-Bernardito committed Aug 28, 2020
1 parent d7bc470 commit 53da71a
Show file tree
Hide file tree
Showing 9 changed files with 303 additions and 24 deletions.
58 changes: 56 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -44,6 +44,7 @@
"dependencies": {
"cosmiconfig": "^7.0.0",
"loader-utils": "^2.0.0",
"normalize-path": "^3.0.0",
"postcss": "^7.0.0",
"schema-utils": "^2.7.0"
},
Expand All @@ -67,6 +68,7 @@
"jest": "^26.2.2",
"jest-junit": "^11.1.0",
"jsdoc-to-markdown": "^6.0.1",
"less-loader": "^6.2.0",
"lint-staged": "^10.2.11",
"memfs": "^3.2.0",
"midas": "^2.0.3",
Expand Down
33 changes: 27 additions & 6 deletions src/index.js
Expand Up @@ -8,7 +8,14 @@ import postcss from 'postcss';
import Warning from './Warning';
import SyntaxError from './Error';
import schema from './options.json';
import { exec, loadConfig, getArrayPlugins } from './utils';
import {
exec,
loadConfig,
getArrayPlugins,
getSourceMapAbsolutePath,
getSourceMapRelativePath,
normalizeSourceMap,
} from './utils';

/**
* **PostCSS Loader**
Expand Down Expand Up @@ -103,8 +110,18 @@ export default async function loader(content, sourceMap, meta = {}) {
? options.sourceMap
: this.sourceMap;

const sourceMapNormalized =
sourceMap && useSourceMap ? normalizeSourceMap(sourceMap) : null;

if (sourceMapNormalized) {
sourceMapNormalized.sources = sourceMapNormalized.sources.map((src) =>
getSourceMapRelativePath(src, path.dirname(file))
);
}

const postcssOptions = {
from: file,
to: file,
map: useSourceMap
? options.sourceMap === 'inline'
? { inline: true, annotation: false }
Expand All @@ -115,9 +132,8 @@ export default async function loader(content, sourceMap, meta = {}) {
stringifier,
};

if (postcssOptions.map && sourceMap) {
postcssOptions.map.prev =
typeof sourceMap === 'string' ? JSON.parse(sourceMap) : sourceMap;
if (postcssOptions.map && sourceMapNormalized) {
postcssOptions.map.prev = sourceMapNormalized;
}

// Loader Exec (Deprecated)
Expand Down Expand Up @@ -210,8 +226,13 @@ export default async function loader(content, sourceMap, meta = {}) {
map = map ? map.toJSON() : null;

if (map) {
map.file = path.resolve(map.file);
map.sources = map.sources.map((src) => path.resolve(src));
if (typeof map.file !== 'undefined') {
delete map.file;
}

map.sources = map.sources.map((src) =>
getSourceMapAbsolutePath(src, postcssOptions.to)
);
}

const ast = {
Expand Down
75 changes: 74 additions & 1 deletion src/utils.js
Expand Up @@ -2,6 +2,8 @@ import path from 'path';

import Module from 'module';

import normalizePath from 'normalize-path';

import postcssPkg from 'postcss/package.json';
import { cosmiconfig } from 'cosmiconfig';

Expand Down Expand Up @@ -242,4 +244,75 @@ function getArrayPlugins(plugins, file, disabledPlugins, loaderContext) {
return pluginsProcessing(plugins, file, disabledPlugins);
}

export { exec, loadConfig, getArrayPlugins };
// TODO Remove, when postcss 8 will be released
function normalizeSourceMap(map) {
let newMap = map;

// Some loader emit source map as string
// Strip any JSON XSSI avoidance prefix from the string (as documented in the source maps specification), and then parse the string as JSON.
if (typeof newMap === 'string') {
newMap = JSON.parse(newMap);
}

// 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 (newMap.file) {
delete newMap.file;
}

const { sourceRoot } = newMap;

if (newMap.sourceRoot) {
delete newMap.sourceRoot;
}

if (newMap.sources) {
newMap.sources = newMap.sources.map((source) => {
return !sourceRoot
? normalizePath(source)
: normalizePath(path.resolve(sourceRoot, source));
});
}

return newMap;
}

function getSourceMapRelativePath(file, from) {
if (file.indexOf('<') === 0) return file;
if (/^\w+:\/\//.test(file)) return file;

const result = path.relative(from, file);

if (path.sep === '\\') {
return result.replace(/\\/g, '/');
}

return result;
}

function getSourceMapAbsolutePath(file, to) {
if (file.indexOf('<') === 0) return file;
if (/^\w+:\/\//.test(file)) return file;

if (typeof to === 'undefined') return file;

const dirname = path.dirname(to);

const result = path.resolve(dirname, file);

if (path.sep === '\\') {
return result.replace(/\\/g, '/');
}

return result;
}

export {
exec,
loadConfig,
getArrayPlugins,
getSourceMapAbsolutePath,
getSourceMapRelativePath,
normalizeSourceMap,
};
3 changes: 3 additions & 0 deletions test/fixtures/less/index.js
@@ -0,0 +1,3 @@
import style from './style.less'

export default style
1 change: 1 addition & 0 deletions test/fixtures/less/style.less
@@ -0,0 +1 @@
a { color: coral }
4 changes: 2 additions & 2 deletions test/helpers/getCodeFromBundle.js
@@ -1,6 +1,6 @@
import normalizeMap from './normalizeMap';

export default (id, stats) => {
export default (id, stats, processMap = true) => {
const { modules } = stats.compilation;
const module = modules.find((m) => m.id.endsWith(id));
const { _source } = module;
Expand All @@ -21,5 +21,5 @@ export default (id, stats) => {

const { css, map } = result;

return { css, map: normalizeMap(map) };
return { css, map: processMap ? normalizeMap(map) : map };
};
68 changes: 56 additions & 12 deletions test/options/__snapshots__/sourceMap.test.js.snap
@@ -1,5 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Options Sourcemap should generated absolute paths in sourcemap: css 1`] = `
"a { color: black }
"
`;

exports[`Options Sourcemap should generated absolute paths in sourcemap: errors 1`] = `Array []`;

exports[`Options Sourcemap should generated absolute paths in sourcemap: map 1`] = `
Object {
"mappings": "AAAA,IAAI,aAAa",
"names": Array [],
"sources": Array [
"xxx",
],
"sourcesContent": Array [
"a { color: black }
",
],
"version": 3,
}
`;

exports[`Options Sourcemap should generated absolute paths in sourcemap: warnings 1`] = `Array []`;

exports[`Options Sourcemap should work Sourcemap - {Boolean}: css 1`] = `
"a { color: black }
"
Expand All @@ -9,7 +33,6 @@ exports[`Options Sourcemap should work Sourcemap - {Boolean}: errors 1`] = `Arra

exports[`Options Sourcemap should work Sourcemap - {Boolean}: map 1`] = `
Object {
"file": "x",
"mappings": "AAAA,IAAI,aAAa",
"names": Array [],
"sources": Array [
Expand All @@ -28,7 +51,7 @@ exports[`Options Sourcemap should work Sourcemap - {Boolean}: warnings 1`] = `Ar
exports[`Options Sourcemap should work Sourcemap - {String}: css 1`] = `
"a { color: black }
/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvZml4dHVyZXMvY3NzL3N0eWxlLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxJQUFJLGFBQWEiLCJmaWxlIjoidGVzdC9maXh0dXJlcy9jc3Mvc3R5bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiYSB7IGNvbG9yOiBibGFjayB9XG4iXX0= */"
/*# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInN0eWxlLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxJQUFJLGFBQWEiLCJmaWxlIjoic3R5bGUuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiYSB7IGNvbG9yOiBibGFjayB9XG4iXX0= */"
`;

exports[`Options Sourcemap should work Sourcemap - {String}: errors 1`] = `Array []`;
Expand All @@ -44,32 +67,53 @@ exports[`Options Sourcemap should work disable Sourcemap - {Boolean}: errors 1`]

exports[`Options Sourcemap should work disable Sourcemap - {Boolean}: warnings 1`] = `Array []`;

exports[`Options Sourcemap should work with prev sourceMap: css 1`] = `
exports[`Options Sourcemap should work with prev sourceMap (less-loader): css 1`] = `
"a {
color: coral;
}"
}
"
`;

exports[`Options Sourcemap should work with prev sourceMap: errors 1`] = `Array []`;
exports[`Options Sourcemap should work with prev sourceMap (less-loader): errors 1`] = `Array []`;

exports[`Options Sourcemap should work with prev sourceMap: map 1`] = `
exports[`Options Sourcemap should work with prev sourceMap (less-loader): map 1`] = `
Object {
"file": "x",
"mappings": "AAAA;EAAI,YAAA;ACEJ",
"mappings": "AAAA;EAAI,YAAA;AAEJ",
"names": Array [],
"sources": Array [
"xxx",
"xxx",
],
"sourcesContent": Array [
"a { color: coral }
",
"a {
],
"version": 3,
}
`;

exports[`Options Sourcemap should work with prev sourceMap (less-loader): warnings 1`] = `Array []`;

exports[`Options Sourcemap should work with prev sourceMap (sass-loader): css 1`] = `
"a {
color: coral;
}",
}"
`;

exports[`Options Sourcemap should work with prev sourceMap (sass-loader): errors 1`] = `Array []`;

exports[`Options Sourcemap should work with prev sourceMap (sass-loader): map 1`] = `
Object {
"mappings": "AAAA;EAAI,YAAA;AAEJ",
"names": Array [],
"sources": Array [
"xxx",
],
"sourcesContent": Array [
"a { color: coral }
",
],
"version": 3,
}
`;

exports[`Options Sourcemap should work with prev sourceMap: warnings 1`] = `Array []`;
exports[`Options Sourcemap should work with prev sourceMap (sass-loader): warnings 1`] = `Array []`;

0 comments on commit 53da71a

Please sign in to comment.