Skip to content

Commit 6b88cb9

Browse files
authored
Merge pull request #4 from vanduynslagerp/sourcemaps
Add Sourcemap in Karma files
2 parents 5638df3 + 4f66d52 commit 6b88cb9

7 files changed

Lines changed: 99 additions & 46 deletions

File tree

package-lock.json

Lines changed: 21 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@metahub/karma-postcss-preprocessor",
3-
"description": "Karma preprocessor to compile css files with postcss",
3+
"description": "Karma preprocessor to compile css files with postcss with sourcemap and watch support",
44
"version": "1.1.1",
55
"author": "Pierre Vanduynslager",
66
"bugs": {
@@ -9,7 +9,8 @@
99
"dependencies": {
1010
"chokidar": "^1.7.0",
1111
"lodash": "^4.17.4",
12-
"nodeify": "^1.0.1"
12+
"nodeify": "^1.0.1",
13+
"source-map-url": "^0.4.0"
1314
},
1415
"devDependencies": {
1516
"@metahub/eslint-config": "^1.5.1",
@@ -24,7 +25,7 @@
2425
"eslint": "^4.3.0",
2526
"eslint-config-prettier": "^2.3.0",
2627
"eslint-plugin-ava": "^4.2.1",
27-
"eslint-plugin-babel": "^4.1.1",
28+
"eslint-plugin-babel": "^4.1.2",
2829
"eslint-plugin-import": "^2.7.0",
2930
"eslint-plugin-jasmine": "^2.8.0",
3031
"eslint-plugin-json": "^1.2.0",
@@ -61,7 +62,7 @@
6162
},
6263
"files": ["lib"],
6364
"homepage": "https://github.com/vanduynslagerp/karma-postcss-preprocessor#readme",
64-
"keywords": ["karma-plugin", "karma-preprocessor", "postcss"],
65+
"keywords": ["karma-plugin", "karma-preprocessor", "postcss", "watcher", "sourcemaps"],
6566
"license": "MIT",
6667
"main": "lib/index.js",
6768
"repository": {

src/index.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import path from 'path';
22
import {merge} from 'lodash';
33
import {FSWatcher} from 'chokidar';
44
import nodeify from 'nodeify';
5+
import sourceMappingURL from 'source-map-url';
56
import postcss from 'postcss';
67

78
/**
@@ -53,9 +54,8 @@ function createPostcssPreprocessor(args, config, logger, server) {
5354

5455
// Inline source maps
5556
if (opts.sourceMap || opts.map) {
56-
opts.map = {inline: true};
57+
opts.map = {inline: false};
5758
}
58-
5959
opts.from = file.originalPath;
6060
opts.to = file.originalPath;
6161

@@ -109,6 +109,14 @@ function createPostcssPreprocessor(args, config, logger, server) {
109109
watcher.unwatch(stopWatching);
110110
}
111111
}
112+
if (opts.map && result.map) {
113+
file.sourceMap = JSON.parse(result.map.toString());
114+
return `${sourceMappingURL.removeFrom(
115+
result.css
116+
)}\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,${Buffer.from(
117+
JSON.stringify(file.sourceMap)
118+
).toString('base64')}\n`;
119+
}
112120
return result.css;
113121
})
114122
.catch(err => {
@@ -124,6 +132,4 @@ function createPostcssPreprocessor(args, config, logger, server) {
124132
createPostcssPreprocessor.$inject = ['args', 'config', 'logger', 'emitter'];
125133

126134
// Export preprocessor
127-
module.exports = {
128-
'preprocessor:postcss': ['factory', createPostcssPreprocessor],
129-
};
135+
module.exports = {'preprocessor:postcss': ['factory', createPostcssPreprocessor]};

test/helpers/karma.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const KARMA_CONFIG = {
1818
},
1919
babelPreprocessor: {options: {babelrc: false, presets: ['es2015'], sourceMap: 'inline'}},
2020
colors: true,
21-
logLevel: constants.LOG_DISABLED,
21+
logLevel: constants.LOG_DISABLE,
2222
browsers: ['PhantomJS'],
2323
plugins: ['@metahub/karma-jasmine-jquery', 'karma-*', karmaPreprocessor],
2424
};

test/helpers/utils.js

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import path from 'path';
22
import {readFile} from 'fs-extra';
33
import uuid from 'uuid';
44
import pEvent from 'p-event';
5+
import sourceMappingURL from 'source-map-url';
56
import postcss from 'postcss';
67

78
/**
@@ -41,25 +42,38 @@ export function sleep(delay) {
4142
export function waitFor(emitter, event, timeout = 5000) {
4243
return pEvent(emitter, event, {timeout});
4344
}
44-
/* eslint-enable no-magic-numbers */
4545

46+
/**
47+
* @typedef {Object} Compiled
48+
* @property {string} css the compiled css code.
49+
* @property {Object} map the sourcemap resulting from the compilation.
50+
*/
51+
52+
/* eslint-enable no-magic-numbers */
4653
/**
4754
* Compile a css file and return the result as a `string`.
4855
*
4956
* @method compile
5057
* @param {string} file path of the file to compile.
5158
* @param {Object} [options={}] postcss options.
52-
* @return {string} compiled css.
59+
* @return {Compiled} compiled code and source map.
5360
*/
5461
export async function compile(file, options = {}) {
5562
if (options.sourceMap || options.map) {
56-
options.map = {inline: true};
63+
options.map = {inline: false};
5764
}
65+
options.from = path.resolve(file);
66+
options.to = path.resolve(file);
67+
const {css, map} = await postcss(options.plugins || []).process(await readFile(path.resolve(file)), options);
5868

59-
const result = await postcss(options.plugins || []).process(
60-
await readFile(path.resolve(file)),
61-
Object.assign(options, {from: path.resolve(file), to: path.resolve(file)})
62-
);
63-
64-
return result.css.toString();
69+
return {
70+
css: map
71+
? `${sourceMappingURL.removeFrom(
72+
css
73+
)}\n//# source${''}MappingURL=data:application/json;charset=utf-8;base64,${Buffer.from(
74+
JSON.stringify(JSON.parse(map.toString()))
75+
).toString('base64')}\n`
76+
: css,
77+
map: map ? JSON.parse(map.toString()) : undefined,
78+
};
6579
}

test/integration.test.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,20 @@ import cssnano from 'cssnano';
66
import mixins from 'postcss-mixins';
77
import simpleVars from 'postcss-simple-vars';
88
import atImport from 'postcss-import';
9+
import {stub} from 'sinon';
910
import {run, watch, waitForRunComplete} from './helpers/karma';
1011
import {tmp} from './helpers/utils';
1112

13+
let stubWrite;
14+
15+
test.before(() => {
16+
stubWrite = stub(process.stdout, 'write');
17+
});
18+
19+
test.after(() => {
20+
stubWrite.restore();
21+
});
22+
1223
test('Compile css file', async t => {
1324
const {success, error, disconnected} = await run(['test/fixtures/basic.css', 'test/fixtures/styles.test.js'], {
1425
options: {plugins: [atImport, mixins, simpleVars, cssnano]},

test/unit.test.js

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ test('Compile css file', async t => {
1515
const {preprocessor, debug} = mockPreprocessor({}, {postcssPreprocessor: {options}});
1616
const file = {originalPath: fixture};
1717

18-
t.is((await preprocessor(await readFile(fixture), file)).toString(), await compile(fixture, options));
18+
t.is(await preprocessor(await readFile(fixture), file), (await compile(fixture, options)).css);
1919
t.true(debug.firstCall.calledWith(match('Processing'), fixture));
2020
t.is(path.resolve(file.path), path.resolve('test/fixtures/basic.css'));
2121
});
@@ -25,7 +25,7 @@ test('Compile css file without plugins', async t => {
2525
const {preprocessor, debug} = mockPreprocessor();
2626
const file = {originalPath: fixture};
2727

28-
t.is((await preprocessor(await readFile(fixture), file)).toString(), await compile(fixture));
28+
t.is(await preprocessor(await readFile(fixture), file), (await compile(fixture)).css);
2929
t.true(debug.firstCall.calledWith(match('Processing'), fixture));
3030
t.is(path.resolve(file.path), path.resolve('test/fixtures/basic.css'));
3131
});
@@ -35,8 +35,12 @@ test('Compile css file with sourcemap (options.sourceMap)', async t => {
3535
const options = {plugins: [atImport, mixins, simpleVars, cssnano], sourceMap: true};
3636
const {preprocessor, debug} = mockPreprocessor({}, {postcssPreprocessor: {options}});
3737
const file = {originalPath: fixture};
38+
const {css, map} = await compile(fixture, options);
3839

39-
t.is((await preprocessor(await readFile(fixture), file)).toString(), await compile(fixture, options));
40+
t.is(await preprocessor(await readFile(fixture), file), css);
41+
t.deepEqual(file.sourceMap, map);
42+
t.is(file.sourceMap.file, path.basename(fixture));
43+
t.truthy(file.sourceMap.mappings);
4044
t.true(debug.firstCall.calledWith(match('Processing'), fixture));
4145
t.is(path.resolve(file.path), path.resolve('test/fixtures/basic.css'));
4246
});
@@ -46,8 +50,12 @@ test('Compile css file with sourcemap (options.map)', async t => {
4650
const options = {plugins: [atImport, mixins, simpleVars, cssnano], map: true};
4751
const {preprocessor, debug} = mockPreprocessor({}, {postcssPreprocessor: {options}});
4852
const file = {originalPath: fixture};
53+
const {css, map} = await compile(fixture, options);
4954

50-
t.is((await preprocessor(await readFile(fixture), file)).toString(), await compile(fixture, options));
55+
t.is(await preprocessor(await readFile(fixture), file), css);
56+
t.deepEqual(file.sourceMap, map);
57+
t.is(file.sourceMap.file, path.basename(fixture));
58+
t.truthy(file.sourceMap.mappings);
5159
t.true(debug.firstCall.calledWith(match('Processing'), fixture));
5260
t.is(path.resolve(file.path), path.resolve('test/fixtures/basic.css'));
5361
});
@@ -57,8 +65,12 @@ test('Compile scss file with sourcemap (options.sourceMap) and custom preprocess
5765
const options = {plugins: [atImport, mixins, simpleVars, cssnano], sourceMap: true};
5866
const {preprocessor, debug} = mockPreprocessor({options});
5967
const file = {originalPath: fixture};
68+
const {css, map} = await compile(fixture, options);
6069

61-
t.is((await preprocessor(await readFile(fixture), file)).toString(), await compile(fixture, options));
70+
t.is(await preprocessor(await readFile(fixture), file), css);
71+
t.deepEqual(file.sourceMap, map);
72+
t.is(file.sourceMap.file, path.basename(fixture));
73+
t.truthy(file.sourceMap.mappings);
6274
t.true(debug.firstCall.calledWith(match('Processing'), fixture));
6375
t.is(path.resolve(file.path), path.resolve('test/fixtures/basic.custom.css'));
6476
});
@@ -68,8 +80,12 @@ test('Compile scss file with sourcemap (options.map) and custom preprocessor', a
6880
const options = {plugins: [atImport, mixins, simpleVars, cssnano], map: true};
6981
const {preprocessor, debug} = mockPreprocessor({options});
7082
const file = {originalPath: fixture};
83+
const {css, map} = await compile(fixture, options);
7184

72-
t.is((await preprocessor(await readFile(fixture), file)).toString(), await compile(fixture, options));
85+
t.is(await preprocessor(await readFile(fixture), file), css);
86+
t.deepEqual(file.sourceMap, map);
87+
t.is(file.sourceMap.file, path.basename(fixture));
88+
t.truthy(file.sourceMap.mappings);
7389
t.true(debug.firstCall.calledWith(match('Processing'), fixture));
7490
t.is(path.resolve(file.path), path.resolve('test/fixtures/basic.custom.css'));
7591
});
@@ -80,7 +96,7 @@ test('Compile scss file with partial import', async t => {
8096
const {preprocessor, debug} = mockPreprocessor({}, {postcssPreprocessor: {options}});
8197
const file = {originalPath: fixture};
8298

83-
t.is((await preprocessor(await readFile(fixture), file)).toString(), await compile(fixture, options));
99+
t.is(await preprocessor(await readFile(fixture), file), (await compile(fixture, options)).css);
84100
t.true(debug.firstCall.calledWith(match('Processing'), fixture));
85101
t.is(path.resolve(file.path), path.resolve('test/fixtures/with-partial.css'));
86102
});
@@ -91,7 +107,7 @@ test('Compile scss file with non css extension', async t => {
91107
const {preprocessor, debug} = mockPreprocessor({}, {postcssPreprocessor: {options}});
92108
const file = {originalPath: fixture};
93109

94-
t.is((await preprocessor(await readFile(fixture), file)).toString(), await compile(fixture, options));
110+
t.is(await preprocessor(await readFile(fixture), file), (await compile(fixture, options)).css);
95111
t.true(debug.firstCall.calledWith(match('Processing'), fixture));
96112
t.is(path.resolve(file.path), path.resolve('test/fixtures/basic.css'));
97113
});
@@ -102,7 +118,7 @@ test('Compile css file with no extension', async t => {
102118
const {preprocessor, debug} = mockPreprocessor({}, {postcssPreprocessor: {options}});
103119
const file = {originalPath: fixture};
104120

105-
t.is((await preprocessor(await readFile(fixture), file)).toString(), await compile(fixture, options));
121+
t.is(await preprocessor(await readFile(fixture), file), (await compile(fixture, options)).css);
106122
t.true(debug.firstCall.calledWith(match('Processing'), fixture));
107123
t.is(path.resolve(file.path), path.resolve('test/fixtures/basic.css'));
108124
});
@@ -114,7 +130,7 @@ test('Compile css file with custom transformPath', async t => {
114130
const {preprocessor, debug} = mockPreprocessor({}, {postcssPreprocessor: {transformPath, options}});
115131
const file = {originalPath: fixture};
116132

117-
t.is((await preprocessor(await readFile(fixture), file)).toString(), await compile(fixture, options));
133+
t.is(await preprocessor(await readFile(fixture), file), (await compile(fixture, options)).css);
118134
t.true(debug.firstCall.calledWith(match('Processing'), fixture));
119135
t.true(transformPath.calledOnce);
120136
t.is(path.resolve(file.path), path.resolve('test/basic.css'));
@@ -127,7 +143,7 @@ test('Compile css file with custom transformPath and custom preprocessor', async
127143
const {preprocessor, debug} = mockPreprocessor({transformPath, options});
128144
const file = {originalPath: fixture};
129145

130-
t.is((await preprocessor(await readFile(fixture), file)).toString(), await compile(fixture, options));
146+
t.is(await preprocessor(await readFile(fixture), file), (await compile(fixture, options)).css);
131147
t.true(debug.firstCall.calledWith(match('Processing'), fixture));
132148
t.true(transformPath.calledOnce);
133149
t.is(path.resolve(file.path), path.resolve('test/basic.custom.css'));

0 commit comments

Comments
 (0)