Skip to content

Commit

Permalink
CSS SourceMaps (#4440)
Browse files Browse the repository at this point in the history
* Convert $FlowFixMe for untyped imports to flowlint off

* Implement CSS sourcemaps

* update source-map

* update sourcemap tests

* all remaining typescript tests

* Allow whitespace characters while checking mappings

* fix tests

Co-authored-by: Jasper De Moor <jasperdemoor@gmail.com>
  • Loading branch information
Will Binns-Smith and DeMoorJasper committed Apr 15, 2020
1 parent f9f7320 commit 8e80016
Show file tree
Hide file tree
Showing 35 changed files with 634 additions and 447 deletions.
24 changes: 14 additions & 10 deletions flow-libs/postcss.js.flow
Expand Up @@ -4,7 +4,8 @@
// Derived from the PostCSS docs available at
// http://api.postcss.org/postcss.html.

import type {SourceMapGenerator} from 'source-map';
// eslint-disable-next-line import/no-extraneous-dependencies
import typeof {SourceMapGenerator} from 'source-map';

declare module 'postcss' {
declare type NodeCallback = (Node, number) => false | void;
Expand All @@ -23,20 +24,23 @@ declare module 'postcss' {
declare interface Root extends Container {}

declare class Processor {
process(css: string | Result, opts?: processOptions): Promise<Result>;
process(
css: string | Result | Root,
opts?: ProcessOptions,
): Promise<Result>;
}

declare type ProcessOptions = {|
from?: string,
to?: string,
map?: MapOptions,
parser?: parser,
stringifier?: stringifier,
syntax?: {|
declare type ProcessOptions = $Shape<{|
from: string,
to: string,
map: MapOptions,
parser: parser,
stringifier: stringifier,
syntax: {|
parser: parser,
stringifier: stringifier,
|},
|};
|}>;

declare type MapOptions = {|
inline?: boolean,
Expand Down
2 changes: 1 addition & 1 deletion packages/core/cache/src/Cache.js
Expand Up @@ -8,7 +8,7 @@ import type {FileSystem} from '@parcel/fs';
import path from 'path';
import logger from '@parcel/logger';
import {serialize, deserialize, registerSerializableClass} from '@parcel/core';
// $FlowFixMe this is untyped
// flowlint-next-line untyped-import:off
import packageJson from '../package.json';

export default class Cache {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/core/src/utils.js
Expand Up @@ -10,7 +10,7 @@ import Graph from './Graph';
import ParcelConfig from './ParcelConfig';
import {RequestGraph} from './RequestTracker';
import Config from './public/Config';
// $FlowFixMe this is untyped
// flowlint-next-line untyped-import:off
import packageJson from '../package.json';

export function getBundleGroupId(bundleGroup: BundleGroup): string {
Expand Down
35 changes: 30 additions & 5 deletions packages/core/integration-tests/test/css.js
Expand Up @@ -264,6 +264,7 @@ describe('css', () => {
path.join(__dirname, '/integration/cssnano/index.js'),
{
minify: true,
sourceMaps: false,
},
);

Expand All @@ -275,19 +276,43 @@ describe('css', () => {
assert(css.includes('.local'));
assert(css.includes('.index'));

// TODO: Make this `2` when a `sourceMappingURL` is added
assert.equal(css.split('\n').length, 1);
});

it('should produce a sourcemap when sourceMaps are used', async function() {
await bundle(path.join(__dirname, '/integration/cssnano/index.js'), {
minify: true,
});

let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8');
assert(css.includes('.local'));
assert(css.includes('.index'));

let lines = css.trim().split('\n');
assert.equal(lines.length, 2);
assert.equal(lines[1], '/*# sourceMappingURL=index.css.map */');

let map = JSON.parse(
await outputFS.readFile(path.join(distDir, 'index.css.map'), 'utf8'),
);
assert.equal(map.file, 'index.css.map');
assert.equal(map.mappings, 'AAAA,OACA,WACA,CCFA,OACA,SACA');
assert.deepEqual(map.sources, [
'integration/cssnano/local.css',
'integration/cssnano/index.css',
]);
});

it('should inline data-urls for text-encoded files', async () => {
await bundle(path.join(__dirname, '/integration/data-url/text.css'));
await bundle(path.join(__dirname, '/integration/data-url/text.css'), {
sourceMaps: false,
});
let css = await outputFS.readFile(path.join(distDir, 'text.css'), 'utf8');
assert.equal(
css,
css.trim(),
`.svg-img {
background-image: url('data:image/svg+xml,%3Csvg%3E%0A%0A%3C%2Fsvg%3E%0A');
}
`,
}`,
);
});

Expand Down
18 changes: 11 additions & 7 deletions packages/core/integration-tests/test/html.js
Expand Up @@ -329,8 +329,8 @@ describe('html', function() {

// mergeStyles
assert(
html.includes(
'<style>h1{color:red}div{font-size:20px}</style><style media="print">div{color:#00f}</style>',
html.match(
/<style>h1{color:red}div{font-size:20px}\n\/\*# sourceMappingURL=.*\*\/<\/style><style media="print">div{color:#00f}\n\/\*# sourceMappingURL=.*\*\/<\/style>/,
),
);

Expand Down Expand Up @@ -834,7 +834,11 @@ describe('html', function() {
path.join(distDir, 'index.html'),
'utf8',
);
assert(html.includes('<style>.index{color:#00f}</style>'));
assert(
html.match(
/<style>.index{color:#00f}\n\/\*# sourceMappingURL=.*<\/style>/,
),
);
});

it('should process inline non-js scripts', async function() {
Expand Down Expand Up @@ -1159,8 +1163,8 @@ describe('html', function() {
path.join(distDir, html.match(/\/a\.[a-z0-9]+\.css/)[0]),
'utf8',
);
assert(css.includes('.a'));
assert(!css.includes('.b'));
assert(css.includes('.a {'));
assert(!css.includes('.b {'));

// b.html should point to a CSS bundle containing only b.css
// It should not point to the bundle containing a.css from a.html
Expand All @@ -1178,8 +1182,8 @@ describe('html', function() {
path.join(distDir, html.match(/\/b\.[a-z0-9]+\.css/)[0]),
'utf8',
);
assert(!css.includes('.a'));
assert(css.includes('.b'));
assert(!css.includes('.a {'));
assert(css.includes('.b {'));
});

it('should invalidate parent bundle when inline bundles change', async function() {
Expand Down
@@ -0,0 +1,6 @@
{
"name": "parcel-sourcemap-integration-test",
"version": "1.0.0",
"license": "MIT",
"private": true
}
Empty file.
@@ -0,0 +1,6 @@
{
"name": "parcel-sourcemap-integration-test",
"version": "1.0.0",
"license": "MIT",
"private": true
}
Empty file.
@@ -0,0 +1,6 @@
{
"name": "parcel-sourcemap-integration-test",
"version": "1.0.0",
"license": "MIT",
"private": true
}
Empty file.
@@ -0,0 +1,6 @@
{
"name": "parcel-sourcemap-integration-test",
"version": "1.0.0",
"license": "MIT",
"private": true
}
Empty file.
@@ -0,0 +1,6 @@
{
"name": "parcel-sourcemap-integration-test",
"version": "1.0.0",
"license": "MIT",
"private": true
}
Empty file.
@@ -0,0 +1,6 @@
{
"name": "parcel-sourcemap-integration-test",
"version": "1.0.0",
"license": "MIT",
"private": true
}
Empty file.
@@ -0,0 +1,6 @@
{
"name": "parcel-sourcemap-integration-test",
"version": "1.0.0",
"license": "MIT",
"private": true
}
Empty file.
10 changes: 6 additions & 4 deletions packages/core/integration-tests/test/javascript.js
Expand Up @@ -2099,15 +2099,17 @@ describe('javascript', function() {
path.join(__dirname, '/integration/bundle-text/index.js'),
);

assert.equal(
(await run(b)).default,
`body {
assert(
(await run(b)).default.startsWith(
`body {
background-color: #000000;
}
.svg-img {
background-image: url("data:image/svg+xml,%3Csvg%3E%0A%0A%3C%2Fsvg%3E%0A");
}`,
}
/*# sourceMappingURL=data:application/json;charset=utf-8;base64,`,
),
);
});

Expand Down
2 changes: 1 addition & 1 deletion packages/core/integration-tests/test/less.js
Expand Up @@ -108,7 +108,7 @@ describe('less', function() {
assert.equal(output(), 2);

let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8');
assert.equal(css, '');
assert.equal(css.trim(), '/*# sourceMappingURL=index.css.map */');
});

it('should support linking to assets with url() from less', async function() {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/integration-tests/test/sass.js
Expand Up @@ -101,7 +101,7 @@ describe('sass', function() {
assert.equal(output(), 2);

let css = await outputFS.readFile(path.join(distDir, 'index.css'), 'utf8');
assert.equal(css, '');
assert.equal(css.trim(), '/*# sourceMappingURL=index.css.map */');
});

it('should support linking to assets with url() from scss', async function() {
Expand Down

0 comments on commit 8e80016

Please sign in to comment.