From e9222c1d060c9316a0d2efa0e262858da45cb40f Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sat, 29 Dec 2018 09:52:09 +0100 Subject: [PATCH 01/40] Basic PostCSS sourcemaps --- .../parcel-bundler/src/assets/CSSAsset.js | 24 +++++++++++++++++++ .../src/packagers/CSSPackager.js | 23 ++++++++++++++++++ .../parcel-bundler/src/transforms/postcss.js | 5 ++++ 3 files changed, 52 insertions(+) diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 8c3b7cde3fb..1fb0c726b0a 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -3,6 +3,7 @@ const postcss = require('postcss'); const valueParser = require('postcss-value-parser'); const postcssTransform = require('../transforms/postcss'); const CssSyntaxError = require('postcss/lib/css-syntax-error'); +const SourceMap = require('../SourceMap'); const URL_RE = /url\s*\("?(?![a-z]+:)/; const IMPORT_RE = /@import/; @@ -125,6 +126,25 @@ class CSSAsset extends Asset { 'module.exports = ' + JSON.stringify(this.cssModules, null, 2) + ';'; } + let map; + if (this.options.sourceMaps && this.sourceMap) + map = new SourceMap( + this.sourceMap._mappings._array.map(v => ({ + source: v.source, + original: { + line: v.originalLine, + column: v.originalColumn + }, + generated: { + line: v.generatedLine, + column: v.generatedColumn + } + })), + { + [this.relativeName]: this.contents + } + ); + return [ { type: 'css', @@ -135,6 +155,10 @@ class CSSAsset extends Asset { type: 'js', value: js, hasDependencies: false + }, + { + type: 'map', + value: map } ]; } diff --git a/packages/core/parcel-bundler/src/packagers/CSSPackager.js b/packages/core/parcel-bundler/src/packagers/CSSPackager.js index a188fb1a24b..adf97001b20 100644 --- a/packages/core/parcel-bundler/src/packagers/CSSPackager.js +++ b/packages/core/parcel-bundler/src/packagers/CSSPackager.js @@ -1,6 +1,13 @@ +const path = require('path'); const Packager = require('./Packager'); +const lineCounter = require('../utils/lineCounter'); +const urlJoin = require('../utils/urlJoin'); class CSSPackager extends Packager { + async start() { + this.lineOffset = 0; + } + async addAsset(asset) { let css = asset.generated.css || ''; @@ -22,7 +29,23 @@ class CSSPackager extends Packager { css = `@media ${media.join(', ')} {\n${css.trim()}\n}\n`; } + this.bundle.addOffset(asset, this.lineOffset); await this.write(css); + this.lineOffset += lineCounter(css); + } + + async end() { + if (this.options.sourceMaps) { + // Add source map url if a map bundle exists + let mapBundle = this.bundle.siblingBundlesMap.get('map'); + if (mapBundle) { + let mapUrl = urlJoin( + this.options.publicURL, + path.basename(mapBundle.name) + ); + await this.write(`\n/*# sourceMappingURL=${mapUrl}*/`); + } + } } } diff --git a/packages/core/parcel-bundler/src/transforms/postcss.js b/packages/core/parcel-bundler/src/transforms/postcss.js index a2626640d8d..05da218f1e3 100644 --- a/packages/core/parcel-bundler/src/transforms/postcss.js +++ b/packages/core/parcel-bundler/src/transforms/postcss.js @@ -14,6 +14,7 @@ module.exports = async function(asset) { asset.ast.css = res.css; asset.ast.dirty = false; + asset.sourceMap = res.map; }; async function getConfig(asset) { @@ -30,6 +31,10 @@ async function getConfig(asset) { config = config || {}; + if (asset.options.sourceMaps) { + config.map = {inline: false, annotation: false, sourcesContent: false}; + } + if (typeof config !== 'object') { throw new Error('PostCSS config should be an object.'); } From d2ec796968b80c93d8334acc7bfd706e3b400877 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Mon, 31 Dec 2018 21:40:01 +0100 Subject: [PATCH 02/40] Support @ import with CSS sourcemap --- packages/core/parcel-bundler/src/Bundle.js | 6 +++--- .../core/parcel-bundler/src/assets/CSSAsset.js | 2 +- .../parcel-bundler/src/packagers/CSSPackager.js | 16 +++++++++++++--- .../src/packagers/SourceMapPackager.js | 2 +- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/core/parcel-bundler/src/Bundle.js b/packages/core/parcel-bundler/src/Bundle.js index 1847eb3eaec..549092c43a5 100644 --- a/packages/core/parcel-bundler/src/Bundle.js +++ b/packages/core/parcel-bundler/src/Bundle.js @@ -46,12 +46,12 @@ class Bundle { this.assets.delete(asset); } - addOffset(asset, line) { - this.offsets.set(asset, line); + addOffset(asset, line, column = 0) { + this.offsets.set(asset, [line, column]); } getOffset(asset) { - return this.offsets.get(asset) || 0; + return this.offsets.get(asset) || [0, 0]; } getSiblingBundle(type) { diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 1fb0c726b0a..122a3f9cd48 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -130,7 +130,7 @@ class CSSAsset extends Asset { if (this.options.sourceMaps && this.sourceMap) map = new SourceMap( this.sourceMap._mappings._array.map(v => ({ - source: v.source, + source: this.relativeName, original: { line: v.originalLine, column: v.originalColumn diff --git a/packages/core/parcel-bundler/src/packagers/CSSPackager.js b/packages/core/parcel-bundler/src/packagers/CSSPackager.js index adf97001b20..a4ced4bba03 100644 --- a/packages/core/parcel-bundler/src/packagers/CSSPackager.js +++ b/packages/core/parcel-bundler/src/packagers/CSSPackager.js @@ -6,6 +6,7 @@ const urlJoin = require('../utils/urlJoin'); class CSSPackager extends Packager { async start() { this.lineOffset = 0; + this.columnOffset = 0; } async addAsset(asset) { @@ -29,9 +30,18 @@ class CSSPackager extends Packager { css = `@media ${media.join(', ')} {\n${css.trim()}\n}\n`; } - this.bundle.addOffset(asset, this.lineOffset); - await this.write(css); - this.lineOffset += lineCounter(css); + let lineCount = lineCounter(css) - 1; + + if (lineCount == 0) { + this.bundle.addOffset(asset, this.lineOffset, this.columnOffset); + await this.write(css); + this.columnOffset = css.length; + } else { + this.bundle.addOffset(asset, this.lineOffset + 1, this.columnOffset); + await this.write(css + '\n'); + this.columnOffset = 0; + this.lineOffset += lineCounter(css); + } } async end() { diff --git a/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js b/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js index 1b570d14981..6f56a067fcc 100644 --- a/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js +++ b/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js @@ -10,7 +10,7 @@ class SourceMapPackager extends Packager { async addAsset(asset) { await this.sourceMap.addMap( asset.generated.map, - this.bundle.parentBundle.getOffset(asset) + ...this.bundle.parentBundle.getOffset(asset) ); } From 68da31cee31c450436c038c521faeab76c715c1a Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Tue, 1 Jan 2019 14:44:06 +0100 Subject: [PATCH 03/40] Add CSS sourcemap tests --- .../sourcemap-css-import/other-style.css | 5 + .../sourcemap-css-import/style.css | 6 + .../test/integration/sourcemap-css/style.css | 4 + .../core/integration-tests/test/sourcemaps.js | 156 ++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 packages/core/integration-tests/test/integration/sourcemap-css-import/other-style.css create mode 100644 packages/core/integration-tests/test/integration/sourcemap-css-import/style.css create mode 100644 packages/core/integration-tests/test/integration/sourcemap-css/style.css diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-import/other-style.css b/packages/core/integration-tests/test/integration/sourcemap-css-import/other-style.css new file mode 100644 index 00000000000..6d844850414 --- /dev/null +++ b/packages/core/integration-tests/test/integration/sourcemap-css-import/other-style.css @@ -0,0 +1,5 @@ + +div { + width: 100px; + height: 100px; +} diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-import/style.css b/packages/core/integration-tests/test/integration/sourcemap-css-import/style.css new file mode 100644 index 00000000000..055bb9a19ae --- /dev/null +++ b/packages/core/integration-tests/test/integration/sourcemap-css-import/style.css @@ -0,0 +1,6 @@ + +@import "./other-style.css"; + +body { + background-color: red; +} diff --git a/packages/core/integration-tests/test/integration/sourcemap-css/style.css b/packages/core/integration-tests/test/integration/sourcemap-css/style.css new file mode 100644 index 00000000000..0ac172751f5 --- /dev/null +++ b/packages/core/integration-tests/test/integration/sourcemap-css/style.css @@ -0,0 +1,4 @@ + +body { + background-color: red; +} diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index dad3d802d18..9d60202f87e 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -2,8 +2,17 @@ const assert = require('assert'); const fs = require('@parcel/fs'); const path = require('path'); const mapValidator = require('sourcemap-validator'); +const {SourceMapConsumer} = require('source-map'); const {bundler, bundle, run, assertBundleTree} = require('./utils'); +function indexToLineCol(str, index) { + const beforeIndex = str.slice(0, index); + return { + line: beforeIndex.split('\n').length, + column: index - beforeIndex.lastIndexOf('\n') - 1 + }; +} + describe('sourcemaps', function() { it('should create a valid sourcemap as a child of a JS bundle', async function() { let b = bundler(path.join(__dirname, '/integration/sourcemap/index.js')); @@ -314,4 +323,151 @@ describe('sourcemaps', function() { ); mapValidator(jsOutput, map); }); + + it('should create a valid sourcemap as a child of a CSS bundle', async function() { + let b = await bundle( + path.join(__dirname, '/integration/sourcemap-css/style.css'), + {minify: true} + ); + + await assertBundleTree(b, { + name: 'style.css', + assets: ['style.css'], + childBundles: [ + { + name: 'style.css.map', + type: 'map' + } + ] + }); + + let input = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-css/style.css') + )).toString(); + let raw = (await fs.readFile( + path.join(__dirname, '/dist/style.css') + )).toString(); + let map = (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString(); + + assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); + + let consumer = await new SourceMapConsumer(map); + + assert.deepStrictEqual( + consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('body'))), + { + source: '../integration/sourcemap-css/style.css', + name: null, + ...indexToLineCol(input, input.indexOf('body')) + }, + "map 'body'" + ); + + // assert.deepStrictEqual( + // consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('{'))), + // { + // source: '../integration/sourcemap-css/style.css', + // name: null, + // ...indexToLineCol(input, input.indexOf('{')) + // }, + // "map '{'" + // ); + + assert.deepStrictEqual( + consumer.originalPositionFor( + indexToLineCol(raw, raw.indexOf('background-color')) + ), + { + source: '../integration/sourcemap-css/style.css', + name: null, + ...indexToLineCol(input, input.indexOf('background-color')) + }, + "map 'background'-color" + ); + + // assert.deepStrictEqual( + // consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('}'))), + // { + // source: '../integration/sourcemap-css/style.css', + // name: null, + // ...indexToLineCol(input, input.indexOf('}')) + // }, + // "map '}'" + // ); + }); + + it('should create a valid sourcemap for a CSS bundle with imports', async function() { + let b = await bundle( + path.join(__dirname, '/integration/sourcemap-css-import/style.css'), + {minify: true} + ); + + await assertBundleTree(b, { + name: 'style.css', + assets: ['style.css', 'other-style.css'], + childBundles: [ + { + name: 'style.css.map', + type: 'map' + } + ] + }); + + let style = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-css-import/style.css') + )).toString(); + let otherStyle = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-css-import/other-style.css') + )).toString(); + let raw = (await fs.readFile( + path.join(__dirname, '/dist/style.css') + )).toString(); + let map = (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString(); + + assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); + + let consumer = await new SourceMapConsumer(map); + + // assert.deepStrictEqual( + // consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('body'))), + // { + // source: '../integration/sourcemap-css-import/style.css', + // name: null, + // ...indexToLineCol(style, style.indexOf('body')) + // } + // ); + + assert.deepStrictEqual( + consumer.originalPositionFor( + indexToLineCol(raw, raw.indexOf('background-color')) + ), + { + source: '../integration/sourcemap-css-import/style.css', + name: null, + ...indexToLineCol(style, style.indexOf('background-color')) + } + ); + + // assert.deepStrictEqual( + // consumer.originalPositionFor({line: 1, column: raw.indexOf('div')}), + // { + // source: '../integration/sourcemap-css-import/other-style.css', + // name: null, + // ...indexToLineCol(otherStyle, otherStyle.indexOf('div')) + // } + // ); + + assert.deepStrictEqual( + consumer.originalPositionFor({line: 1, column: raw.indexOf('width')}), + { + source: '../integration/sourcemap-css-import/other-style.css', + name: null, + ...indexToLineCol(otherStyle, otherStyle.indexOf('width')) + } + ); + }); }); From 62e7ce83d7d3787a965ffb302cced4ecf734ee33 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Tue, 1 Jan 2019 17:42:51 +0100 Subject: [PATCH 04/40] Fixup --- .../core/integration-tests/test/sourcemaps.js | 26 ++++++++++++------- .../src/packagers/CSSPackager.js | 2 +- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 9d60202f87e..619d3f78b67 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -360,7 +360,8 @@ describe('sourcemaps', function() { { source: '../integration/sourcemap-css/style.css', name: null, - ...indexToLineCol(input, input.indexOf('body')) + line: indexToLineCol(input, input.indexOf('body')).line, + column: indexToLineCol(input, input.indexOf('body')).column }, "map 'body'" ); @@ -382,9 +383,10 @@ describe('sourcemaps', function() { { source: '../integration/sourcemap-css/style.css', name: null, - ...indexToLineCol(input, input.indexOf('background-color')) + line: indexToLineCol(input, input.indexOf('background-color')).line, + column: indexToLineCol(input, input.indexOf('background-color')).column }, - "map 'background'-color" + "map 'background-color'" ); // assert.deepStrictEqual( @@ -438,7 +440,8 @@ describe('sourcemaps', function() { // source: '../integration/sourcemap-css-import/style.css', // name: null, // ...indexToLineCol(style, style.indexOf('body')) - // } + // }, + // "map 'body'" // ); assert.deepStrictEqual( @@ -448,8 +451,10 @@ describe('sourcemaps', function() { { source: '../integration/sourcemap-css-import/style.css', name: null, - ...indexToLineCol(style, style.indexOf('background-color')) - } + line: indexToLineCol(style, style.indexOf('background-color')).line, + column: indexToLineCol(style, style.indexOf('background-color')).column + }, + "map 'background-color'" ); // assert.deepStrictEqual( @@ -458,7 +463,8 @@ describe('sourcemaps', function() { // source: '../integration/sourcemap-css-import/other-style.css', // name: null, // ...indexToLineCol(otherStyle, otherStyle.indexOf('div')) - // } + // }, + // "map 'div'" // ); assert.deepStrictEqual( @@ -466,8 +472,10 @@ describe('sourcemaps', function() { { source: '../integration/sourcemap-css-import/other-style.css', name: null, - ...indexToLineCol(otherStyle, otherStyle.indexOf('width')) - } + line: indexToLineCol(otherStyle, otherStyle.indexOf('width')).line, + column: indexToLineCol(otherStyle, otherStyle.indexOf('width')).column + }, + "map 'width'" ); }); }); diff --git a/packages/core/parcel-bundler/src/packagers/CSSPackager.js b/packages/core/parcel-bundler/src/packagers/CSSPackager.js index a4ced4bba03..b5c619c31af 100644 --- a/packages/core/parcel-bundler/src/packagers/CSSPackager.js +++ b/packages/core/parcel-bundler/src/packagers/CSSPackager.js @@ -38,7 +38,7 @@ class CSSPackager extends Packager { this.columnOffset = css.length; } else { this.bundle.addOffset(asset, this.lineOffset + 1, this.columnOffset); - await this.write(css + '\n'); + await this.write('\n' + css); this.columnOffset = 0; this.lineOffset += lineCounter(css); } From 987e5cc92d6bcf444bb6791e32aa9e41b9614e1c Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Tue, 1 Jan 2019 17:58:07 +0100 Subject: [PATCH 05/40] Don't use object rest spread --- .../core/parcel-bundler/src/packagers/SourceMapPackager.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js b/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js index 6f56a067fcc..d72dbc2e51b 100644 --- a/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js +++ b/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js @@ -8,9 +8,11 @@ class SourceMapPackager extends Packager { } async addAsset(asset) { + let offsets = this.bundle.parentBundle.getOffset(asset); await this.sourceMap.addMap( asset.generated.map, - ...this.bundle.parentBundle.getOffset(asset) + offsets.line, + offsets.column ); } From e47fabdab379e9884cc5740d04b9c6aca2c3d0f7 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Thu, 3 Jan 2019 23:26:20 +0100 Subject: [PATCH 06/40] Fixups for code and tests --- .../sourcemap-css-import/another-style.css | 3 + .../sourcemap-css-import/style.css | 2 + .../core/integration-tests/test/sourcemaps.js | 98 +++++++++++-------- packages/core/integration-tests/test/vue.js | 28 +++--- .../parcel-bundler/src/assets/CSSAsset.js | 21 ++-- .../src/packagers/CSSPackager.js | 2 +- .../src/packagers/SourceMapPackager.js | 6 +- 7 files changed, 91 insertions(+), 69 deletions(-) create mode 100644 packages/core/integration-tests/test/integration/sourcemap-css-import/another-style.css diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-import/another-style.css b/packages/core/integration-tests/test/integration/sourcemap-css-import/another-style.css new file mode 100644 index 00000000000..107e9f29b84 --- /dev/null +++ b/packages/core/integration-tests/test/integration/sourcemap-css-import/another-style.css @@ -0,0 +1,3 @@ +main { + font-family: monospace; +} diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-import/style.css b/packages/core/integration-tests/test/integration/sourcemap-css-import/style.css index 055bb9a19ae..01ef4f07c71 100644 --- a/packages/core/integration-tests/test/integration/sourcemap-css-import/style.css +++ b/packages/core/integration-tests/test/integration/sourcemap-css-import/style.css @@ -4,3 +4,5 @@ body { background-color: red; } + +@import "./another-style.css"; diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 619d3f78b67..7d4faa00517 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -366,16 +366,6 @@ describe('sourcemaps', function() { "map 'body'" ); - // assert.deepStrictEqual( - // consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('{'))), - // { - // source: '../integration/sourcemap-css/style.css', - // name: null, - // ...indexToLineCol(input, input.indexOf('{')) - // }, - // "map '{'" - // ); - assert.deepStrictEqual( consumer.originalPositionFor( indexToLineCol(raw, raw.indexOf('background-color')) @@ -388,16 +378,6 @@ describe('sourcemaps', function() { }, "map 'background-color'" ); - - // assert.deepStrictEqual( - // consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('}'))), - // { - // source: '../integration/sourcemap-css/style.css', - // name: null, - // ...indexToLineCol(input, input.indexOf('}')) - // }, - // "map '}'" - // ); }); it('should create a valid sourcemap for a CSS bundle with imports', async function() { @@ -408,7 +388,7 @@ describe('sourcemaps', function() { await assertBundleTree(b, { name: 'style.css', - assets: ['style.css', 'other-style.css'], + assets: ['style.css', 'other-style.css', 'another-style.css'], childBundles: [ { name: 'style.css.map', @@ -423,6 +403,12 @@ describe('sourcemaps', function() { let otherStyle = (await fs.readFile( path.join(__dirname, '/integration/sourcemap-css-import/other-style.css') )).toString(); + let anotherStyle = (await fs.readFile( + path.join( + __dirname, + '/integration/sourcemap-css-import/another-style.css' + ) + )).toString(); let raw = (await fs.readFile( path.join(__dirname, '/dist/style.css') )).toString(); @@ -433,16 +419,16 @@ describe('sourcemaps', function() { assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); let consumer = await new SourceMapConsumer(map); - - // assert.deepStrictEqual( - // consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('body'))), - // { - // source: '../integration/sourcemap-css-import/style.css', - // name: null, - // ...indexToLineCol(style, style.indexOf('body')) - // }, - // "map 'body'" - // ); + assert.deepStrictEqual( + consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('body'))), + { + source: '../integration/sourcemap-css-import/style.css', + name: null, + line: indexToLineCol(style, style.indexOf('body')).line, + column: indexToLineCol(style, style.indexOf('body')).column + }, + "map 'body'" + ); assert.deepStrictEqual( consumer.originalPositionFor( @@ -457,18 +443,19 @@ describe('sourcemaps', function() { "map 'background-color'" ); - // assert.deepStrictEqual( - // consumer.originalPositionFor({line: 1, column: raw.indexOf('div')}), - // { - // source: '../integration/sourcemap-css-import/other-style.css', - // name: null, - // ...indexToLineCol(otherStyle, otherStyle.indexOf('div')) - // }, - // "map 'div'" - // ); + assert.deepStrictEqual( + consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('div'))), + { + source: '../integration/sourcemap-css-import/other-style.css', + name: null, + line: indexToLineCol(otherStyle, otherStyle.indexOf('div')).line, + column: indexToLineCol(otherStyle, otherStyle.indexOf('div')).column + }, + "map 'div'" + ); assert.deepStrictEqual( - consumer.originalPositionFor({line: 1, column: raw.indexOf('width')}), + consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('width'))), { source: '../integration/sourcemap-css-import/other-style.css', name: null, @@ -477,5 +464,34 @@ describe('sourcemaps', function() { }, "map 'width'" ); + + assert.deepStrictEqual( + consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('main'))), + { + source: '../integration/sourcemap-css-import/another-style.css', + name: null, + line: indexToLineCol(anotherStyle, anotherStyle.indexOf('main')).line, + column: indexToLineCol(anotherStyle, anotherStyle.indexOf('main')) + .column + }, + "map 'main'" + ); + + assert.deepStrictEqual( + consumer.originalPositionFor( + indexToLineCol(raw, raw.indexOf('font-family')) + ), + { + source: '../integration/sourcemap-css-import/another-style.css', + name: null, + line: indexToLineCol(anotherStyle, anotherStyle.indexOf('font-family')) + .line, + column: indexToLineCol( + anotherStyle, + anotherStyle.indexOf('font-family') + ).column + }, + "map 'font-family'" + ); }); }); diff --git a/packages/core/integration-tests/test/vue.js b/packages/core/integration-tests/test/vue.js index c53dbb5220f..acdc2c41f27 100644 --- a/packages/core/integration-tests/test/vue.js +++ b/packages/core/integration-tests/test/vue.js @@ -14,10 +14,10 @@ describe('vue', function() { assets: ['Basic.vue'], childBundles: [ { - type: 'css' + type: 'map' }, { - type: 'map' + type: 'css' } ] }); @@ -39,10 +39,10 @@ describe('vue', function() { assets: ['App.vue'], childBundles: [ { - type: 'css' + type: 'map' }, { - type: 'map' + type: 'css' }, { assets: ['logo.png'], @@ -67,10 +67,10 @@ describe('vue', function() { assets: ['pre-processors.vue'], childBundles: [ { - type: 'css' + type: 'map' }, { - type: 'map' + type: 'css' } ] }); @@ -131,10 +131,10 @@ describe('vue', function() { assets: ['App.vue'], childBundles: [ { - type: 'css' + type: 'map' }, { - type: 'map' + type: 'css' } ] }); @@ -162,10 +162,10 @@ describe('vue', function() { assets: ['App.vue'], childBundles: [ { - type: 'css' + type: 'map' }, { - type: 'map' + type: 'css' } ] }); @@ -207,10 +207,10 @@ describe('vue', function() { assets: ['insidecomp.vue'], childBundles: [ { - type: 'css' + type: 'map' }, { - type: 'map' + type: 'css' } ] }, @@ -241,10 +241,10 @@ describe('vue', function() { assets: ['Basic.vue'], childBundles: [ { - type: 'css' + type: 'map' }, { - type: 'map' + type: 'css' } ] }); diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 122a3f9cd48..4b3b64f379d 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -127,9 +127,10 @@ class CSSAsset extends Asset { } let map; - if (this.options.sourceMaps && this.sourceMap) - map = new SourceMap( - this.sourceMap._mappings._array.map(v => ({ + if (this.options.sourceMaps && this.sourceMap) { + const source = this.contents.split('\n'); + const mappings = this.sourceMap._mappings._array + .map(v => ({ source: this.relativeName, original: { line: v.originalLine, @@ -139,11 +140,15 @@ class CSSAsset extends Asset { line: v.generatedLine, column: v.generatedColumn } - })), - { - [this.relativeName]: this.contents - } - ); + })) + .filter( + ({original: {line, column}}) => + line - 1 < source.length && column < source[line - 1].length + ); + map = new SourceMap(mappings, { + [this.relativeName]: this.contents + }); + } return [ { diff --git a/packages/core/parcel-bundler/src/packagers/CSSPackager.js b/packages/core/parcel-bundler/src/packagers/CSSPackager.js index b5c619c31af..3b3cf5f2f7a 100644 --- a/packages/core/parcel-bundler/src/packagers/CSSPackager.js +++ b/packages/core/parcel-bundler/src/packagers/CSSPackager.js @@ -35,7 +35,7 @@ class CSSPackager extends Packager { if (lineCount == 0) { this.bundle.addOffset(asset, this.lineOffset, this.columnOffset); await this.write(css); - this.columnOffset = css.length; + this.columnOffset += css.length; } else { this.bundle.addOffset(asset, this.lineOffset + 1, this.columnOffset); await this.write('\n' + css); diff --git a/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js b/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js index d72dbc2e51b..69e6b375e55 100644 --- a/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js +++ b/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js @@ -9,11 +9,7 @@ class SourceMapPackager extends Packager { async addAsset(asset) { let offsets = this.bundle.parentBundle.getOffset(asset); - await this.sourceMap.addMap( - asset.generated.map, - offsets.line, - offsets.column - ); + await this.sourceMap.addMap(asset.generated.map, offsets[0], offsets[1]); } async end() { From 02abdbca0ebcff013cb11c449391f098004e63e6 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Fri, 4 Jan 2019 18:37:54 +0100 Subject: [PATCH 07/40] Source maps for SASS --- .../parcel-bundler/src/assets/CSSAsset.js | 19 +++++++++++++++++- .../parcel-bundler/src/assets/SASSAsset.js | 20 +++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 4b3b64f379d..4ff6ddce38e 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -13,6 +13,9 @@ class CSSAsset extends Asset { constructor(name, options) { super(name, options); this.type = 'css'; + this.previousSourceMap = this.options.rendition + ? this.options.rendition.map + : null; } mightHaveDependencies() { @@ -107,7 +110,7 @@ class CSSAsset extends Asset { return this.ast.root; } - generate() { + async generate() { let css = this.ast ? this.ast.render() : this.contents; let js = ''; @@ -148,6 +151,20 @@ class CSSAsset extends Asset { map = new SourceMap(mappings, { [this.relativeName]: this.contents }); + + if (this.previousSourceMap) { + map = await new SourceMap().extendSourceMap( + this.previousSourceMap, + map + ); + for (let i = 0; i < this.previousSourceMap.sourcesContent.length; i++) { + if (this.previousSourceMap.sourcesContent[i]) { + map.sources[ + this.previousSourceMap.sources[i] + ] = this.previousSourceMap.sourcesContent[i]; + } + } + } } return [ diff --git a/packages/core/parcel-bundler/src/assets/SASSAsset.js b/packages/core/parcel-bundler/src/assets/SASSAsset.js index 3760328e650..68970aa8638 100644 --- a/packages/core/parcel-bundler/src/assets/SASSAsset.js +++ b/packages/core/parcel-bundler/src/assets/SASSAsset.js @@ -54,6 +54,14 @@ class SASSAsset extends Asset { .catch(err => done(normalizeError(err))); }); + if (this.options.sourceMaps) { + opts.sourceMap = true; + opts.outFile = this.relativeName; + opts.file = this.relativeName; + opts.omitSourceMapUrl = true; + opts.sourceMapContents = true; + } + try { return await render(opts); } catch (err) { @@ -72,11 +80,19 @@ class SASSAsset extends Asset { } } - generate() { + async generate() { + let map; + if (this.ast.map) { + map = JSON.parse(this.ast.map.toString()); + map.sources = map.sources.map(v => + path.relative(this.options.rootDir, v.replace('file:', '')) + ); + } return [ { type: 'css', - value: this.ast ? this.ast.css.toString() : '' + value: this.ast ? this.ast.css.toString() : '', + map } ]; } From 8d8f6dbc41e1ef3d1d69b6f7c980ae2f06d1dca3 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Fri, 4 Jan 2019 18:46:29 +0100 Subject: [PATCH 08/40] LESS sourcemaps --- .../core/parcel-bundler/src/assets/LESSAsset.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/core/parcel-bundler/src/assets/LESSAsset.js b/packages/core/parcel-bundler/src/assets/LESSAsset.js index f9784899809..b424a1bcd1e 100644 --- a/packages/core/parcel-bundler/src/assets/LESSAsset.js +++ b/packages/core/parcel-bundler/src/assets/LESSAsset.js @@ -22,6 +22,9 @@ class LESSAsset extends Asset { {}; opts.filename = this.name; opts.plugins = (opts.plugins || []).concat(urlPlugin(this)); + if (this.options.sourceMaps) { + opts.sourceMap = {outputSourceFiles: true}; + } return await render(code, opts); } @@ -33,11 +36,19 @@ class LESSAsset extends Asset { } generate() { + let map; + if (this.ast.map) { + map = JSON.parse(this.ast.map.toString()); + map.sources = map.sources.map(v => + path.relative(this.options.rootDir, v) + ); + } return [ { type: 'css', value: this.ast ? this.ast.css : '', - hasDependencies: false + hasDependencies: false, + map } ]; } From e1e12faa2ba3e0afb4d6b1a6806e042aa9b4701e Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Fri, 4 Jan 2019 22:06:37 +0100 Subject: [PATCH 09/40] Cleanup SASS sourcemap generation --- packages/core/parcel-bundler/src/SourceMap.js | 1 - .../parcel-bundler/src/assets/CSSAsset.js | 63 +++++++++---------- .../parcel-bundler/src/assets/SASSAsset.js | 15 ++--- 3 files changed, 34 insertions(+), 45 deletions(-) diff --git a/packages/core/parcel-bundler/src/SourceMap.js b/packages/core/parcel-bundler/src/SourceMap.js index 82a3a7ba7e3..4f1c3a73b5e 100644 --- a/packages/core/parcel-bundler/src/SourceMap.js +++ b/packages/core/parcel-bundler/src/SourceMap.js @@ -340,7 +340,6 @@ class SourceMap { stringify(file, sourceRoot) { let generator = new SourceMapGenerator({file, sourceRoot}); - this.eachMapping(mapping => generator.addMapping(mapping)); Object.keys(this.sources).forEach(sourceName => generator.setSourceContent(sourceName, this.sources[sourceName]) diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 4ff6ddce38e..b45e5685ae6 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -130,40 +130,37 @@ class CSSAsset extends Asset { } let map; - if (this.options.sourceMaps && this.sourceMap) { - const source = this.contents.split('\n'); - const mappings = this.sourceMap._mappings._array - .map(v => ({ - source: this.relativeName, - original: { - line: v.originalLine, - column: v.originalColumn - }, - generated: { - line: v.generatedLine, - column: v.generatedColumn - } - })) - .filter( - ({original: {line, column}}) => - line - 1 < source.length && column < source[line - 1].length - ); - map = new SourceMap(mappings, { - [this.relativeName]: this.contents - }); - - if (this.previousSourceMap) { - map = await new SourceMap().extendSourceMap( - this.previousSourceMap, - map - ); - for (let i = 0; i < this.previousSourceMap.sourcesContent.length; i++) { - if (this.previousSourceMap.sourcesContent[i]) { - map.sources[ - this.previousSourceMap.sources[i] - ] = this.previousSourceMap.sourcesContent[i]; - } + if (this.options.sourceMaps) { + if (this.sourceMap) { + const source = this.contents.split('\n'); + const mappings = this.sourceMap._mappings._array + .map(v => ({ + source: this.relativeName, + original: { + line: v.originalLine, + column: v.originalColumn + }, + generated: { + line: v.generatedLine, + column: v.generatedColumn + } + })) + .filter( + ({original: {line, column}}) => + line - 1 < source.length && column < source[line - 1].length + ); + map = new SourceMap(mappings, { + [this.relativeName]: this.contents + }); + + if (this.previousSourceMap) { + map = await new SourceMap().extendSourceMap( + this.previousSourceMap, + map + ); } + } else if (this.previousSourceMap) { + map = this.previousSourceMap; } } diff --git a/packages/core/parcel-bundler/src/assets/SASSAsset.js b/packages/core/parcel-bundler/src/assets/SASSAsset.js index 68970aa8638..277afb0a1ed 100644 --- a/packages/core/parcel-bundler/src/assets/SASSAsset.js +++ b/packages/core/parcel-bundler/src/assets/SASSAsset.js @@ -56,8 +56,8 @@ class SASSAsset extends Asset { if (this.options.sourceMaps) { opts.sourceMap = true; - opts.outFile = this.relativeName; - opts.file = this.relativeName; + opts.file = this.name; + opts.outFile = this.name; opts.omitSourceMapUrl = true; opts.sourceMapContents = true; } @@ -80,19 +80,12 @@ class SASSAsset extends Asset { } } - async generate() { - let map; - if (this.ast.map) { - map = JSON.parse(this.ast.map.toString()); - map.sources = map.sources.map(v => - path.relative(this.options.rootDir, v.replace('file:', '')) - ); - } + generate() { return [ { type: 'css', value: this.ast ? this.ast.css.toString() : '', - map + map: this.ast.map ? this.ast.map.toString() : undefined } ]; } From d3f6ece1a6d2abc8e61f5d36d612dbd118e0fda2 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Fri, 4 Jan 2019 22:20:21 +0100 Subject: [PATCH 10/40] SASS sourcemap tests --- .../integration/sourcemap-less/style.less | 12 ++ .../sourcemap-sass-imported/other.scss | 5 + .../sourcemap-sass-imported/style.css | 5 + .../integration/sourcemap-sass/style.scss | 5 + .../core/integration-tests/test/sourcemaps.js | 135 ++++++++++++++++++ 5 files changed, 162 insertions(+) create mode 100644 packages/core/integration-tests/test/integration/sourcemap-less/style.less create mode 100644 packages/core/integration-tests/test/integration/sourcemap-sass-imported/other.scss create mode 100644 packages/core/integration-tests/test/integration/sourcemap-sass-imported/style.css create mode 100644 packages/core/integration-tests/test/integration/sourcemap-sass/style.scss diff --git a/packages/core/integration-tests/test/integration/sourcemap-less/style.less b/packages/core/integration-tests/test/integration/sourcemap-less/style.less new file mode 100644 index 00000000000..9de87c05afd --- /dev/null +++ b/packages/core/integration-tests/test/integration/sourcemap-less/style.less @@ -0,0 +1,12 @@ +@w: 100px; +@h: @w * 2; + +body { + font-family: monospace; +} + +div { + background-color: red; + width: @w; + height: @h; +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/sourcemap-sass-imported/other.scss b/packages/core/integration-tests/test/integration/sourcemap-sass-imported/other.scss new file mode 100644 index 00000000000..3498c8f2370 --- /dev/null +++ b/packages/core/integration-tests/test/integration/sourcemap-sass-imported/other.scss @@ -0,0 +1,5 @@ +$variable: monospace; + +div { + font-family: $variable; +} diff --git a/packages/core/integration-tests/test/integration/sourcemap-sass-imported/style.css b/packages/core/integration-tests/test/integration/sourcemap-sass-imported/style.css new file mode 100644 index 00000000000..b486b67de91 --- /dev/null +++ b/packages/core/integration-tests/test/integration/sourcemap-sass-imported/style.css @@ -0,0 +1,5 @@ +@import "./other.scss"; + +body { + color: red; +} diff --git a/packages/core/integration-tests/test/integration/sourcemap-sass/style.scss b/packages/core/integration-tests/test/integration/sourcemap-sass/style.scss new file mode 100644 index 00000000000..8ce95c4110e --- /dev/null +++ b/packages/core/integration-tests/test/integration/sourcemap-sass/style.scss @@ -0,0 +1,5 @@ +$variable: #333; + +body { + color: $variable; +} diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 7d4faa00517..25d0b82afe1 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -494,4 +494,139 @@ describe('sourcemaps', function() { "map 'font-family'" ); }); + + it('should create a valid sourcemap for a SASS asset', async function() { + let b = await bundle( + path.join(__dirname, '/integration/sourcemap-sass/style.scss'), + {minify: true} + ); + + await assertBundleTree(b, { + name: 'style.css', + assets: ['style.scss'], + childBundles: [ + { + name: 'style.css.map', + type: 'map' + } + ] + }); + + let input = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-sass/style.scss') + )).toString(); + let raw = (await fs.readFile( + path.join(__dirname, '/dist/style.css') + )).toString(); + let map = (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString(); + + assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); + + let consumer = await new SourceMapConsumer(map); + + assert.deepStrictEqual( + consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('body'))), + { + source: '../integration/sourcemap-sass/style.scss', + name: null, + line: indexToLineCol(input, input.indexOf('body')).line, + column: indexToLineCol(input, input.indexOf('body')).column + }, + "map 'body'" + ); + + assert.deepStrictEqual( + consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('color'))), + { + source: '../integration/sourcemap-sass/style.scss', + name: null, + line: indexToLineCol(input, input.indexOf('color')).line, + column: indexToLineCol(input, input.indexOf('color')).column + }, + "map 'color'" + ); + }); + + it('should create a valid sourcemap when a CSS asset imports SASS', async function() { + let b = await bundle( + path.join(__dirname, '/integration/sourcemap-sass-imported/style.css'), + {minify: true} + ); + + await assertBundleTree(b, { + name: 'style.css', + assets: ['style.css', 'other.scss'], + childBundles: [ + { + name: 'style.css.map', + type: 'map' + } + ] + }); + + let style = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-sass-imported/style.css') + )).toString(); + let other = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-sass-imported/other.scss') + )).toString(); + let raw = (await fs.readFile( + path.join(__dirname, '/dist/style.css') + )).toString(); + let map = (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString(); + + assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); + + let consumer = await new SourceMapConsumer(map); + + assert.deepStrictEqual( + consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('body'))), + { + source: '../integration/sourcemap-sass-imported/style.css', + name: null, + line: indexToLineCol(style, style.indexOf('body')).line, + column: indexToLineCol(style, style.indexOf('body')).column + }, + "map 'body'" + ); + + assert.deepStrictEqual( + consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('color'))), + { + source: '../integration/sourcemap-sass-imported/style.css', + name: null, + line: indexToLineCol(style, style.indexOf('color')).line, + column: indexToLineCol(style, style.indexOf('color')).column + }, + "map 'color'" + ); + + assert.deepStrictEqual( + consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('div'))), + { + source: '../integration/sourcemap-sass-imported/other.scss', + name: null, + line: indexToLineCol(other, other.indexOf('div')).line, + column: indexToLineCol(other, other.indexOf('div')).column + }, + "map 'div'" + ); + + assert.deepStrictEqual( + consumer.originalPositionFor( + indexToLineCol(raw, raw.indexOf('font-family')) + ), + { + source: '../integration/sourcemap-sass-imported/other.scss', + name: null, + line: indexToLineCol(other, other.indexOf('font-family')).line, + column: indexToLineCol(other, other.indexOf('font-family')).column + }, + "map 'font-family'" + ); + }); }); From cc15e59cd0e23ad2177b9162208ab8c19d249e92 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Fri, 4 Jan 2019 22:22:34 +0100 Subject: [PATCH 11/40] Add LESS sourcemap test --- .../integration/sourcemap-less/style.less | 13 ++--- .../core/integration-tests/test/sourcemaps.js | 54 +++++++++++++++++++ 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/packages/core/integration-tests/test/integration/sourcemap-less/style.less b/packages/core/integration-tests/test/integration/sourcemap-less/style.less index 9de87c05afd..e1a4d641769 100644 --- a/packages/core/integration-tests/test/integration/sourcemap-less/style.less +++ b/packages/core/integration-tests/test/integration/sourcemap-less/style.less @@ -1,12 +1,5 @@ -@w: 100px; -@h: @w * 2; - -body { - font-family: monospace; -} +@value: 100px * 2; div { - background-color: red; - width: @w; - height: @h; -} \ No newline at end of file + width: @value; +} diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 25d0b82afe1..72ed1266650 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -629,4 +629,58 @@ describe('sourcemaps', function() { "map 'font-family'" ); }); + + it('should create a valid sourcemap for a LESS asset', async function() { + let b = await bundle( + path.join(__dirname, '/integration/sourcemap-less/style.less'), + {minify: true} + ); + + await assertBundleTree(b, { + name: 'style.css', + assets: ['style.less'], + childBundles: [ + { + name: 'style.css.map', + type: 'map' + } + ] + }); + + let input = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-less/style.less') + )).toString(); + let raw = (await fs.readFile( + path.join(__dirname, '/dist/style.css') + )).toString(); + let map = (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString(); + + assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); + + let consumer = await new SourceMapConsumer(map); + + assert.deepStrictEqual( + consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('div'))), + { + source: '../integration/sourcemap-less/style.less', + name: null, + line: indexToLineCol(input, input.indexOf('div')).line, + column: indexToLineCol(input, input.indexOf('div')).column + }, + "map 'div'" + ); + + assert.deepStrictEqual( + consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('width'))), + { + source: '../integration/sourcemap-less/style.less', + name: null, + line: indexToLineCol(input, input.indexOf('width')).line, + column: indexToLineCol(input, input.indexOf('width')).column + }, + "map 'width'" + ); + }); }); From 1e54c1a10967c536d124beea520e0c3c0a606298 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sat, 5 Jan 2019 12:09:04 +0100 Subject: [PATCH 12/40] Cleanup CSSAsset sourcemap handling --- .../core/integration-tests/test/sourcemaps.js | 444 +++++++++--------- .../parcel-bundler/src/assets/CSSAsset.js | 68 ++- .../parcel-bundler/src/assets/SASSAsset.js | 2 +- 3 files changed, 267 insertions(+), 247 deletions(-) diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 72ed1266650..95416de0e29 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -2,17 +2,65 @@ const assert = require('assert'); const fs = require('@parcel/fs'); const path = require('path'); const mapValidator = require('sourcemap-validator'); +const SourceMap = require('parcel-bundler/src/SourceMap'); const {SourceMapConsumer} = require('source-map'); const {bundler, bundle, run, assertBundleTree} = require('./utils'); function indexToLineCol(str, index) { - const beforeIndex = str.slice(0, index); + let beforeIndex = str.slice(0, index); return { line: beforeIndex.split('\n').length, column: index - beforeIndex.lastIndexOf('\n') - 1 }; } +function checkSourceMapping({ + map, + source, + generated, + str, + sourcePath, + msg = '' +}) { + assert(generated.indexOf(str) !== -1, "'" + str + "' not in generated code"); + assert(source.indexOf(str) !== -1, "'" + str + "' not in source code"); + + let generatedPosition = indexToLineCol(generated, generated.indexOf(str)); + let sourcePosition = indexToLineCol(source, source.indexOf(str)); + + let index = map.findClosestGenerated( + generatedPosition.line, + generatedPosition.column + ); + + let mapping = map.mappings[index]; + assert(mapping, "no mapping for '" + str + "'" + msg); + + let generatedDiff = { + line: generatedPosition.line - mapping.generated.line, + column: generatedPosition.column - mapping.generated.column + }; + + let computedSourcePosition = { + line: mapping.original.line + generatedDiff.line, + column: mapping.original.column + generatedDiff.column + }; + + assert.deepStrictEqual( + { + line: computedSourcePosition.line, + column: computedSourcePosition.column, + source: mapping.source + }, + { + line: sourcePosition.line, + column: sourcePosition.column, + source: sourcePath + }, + "map '" + str + "'" + msg + ); +} + describe('sourcemaps', function() { it('should create a valid sourcemap as a child of a JS bundle', async function() { let b = bundler(path.join(__dirname, '/integration/sourcemap/index.js')); @@ -353,146 +401,126 @@ describe('sourcemaps', function() { assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); - let consumer = await new SourceMapConsumer(map); + let sourceMap = await new SourceMap().addMap(JSON.parse(map)); - assert.deepStrictEqual( - consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('body'))), - { - source: '../integration/sourcemap-css/style.css', - name: null, - line: indexToLineCol(input, input.indexOf('body')).line, - column: indexToLineCol(input, input.indexOf('body')).column - }, - "map 'body'" - ); + checkSourceMapping({ + map: sourceMap, + source: input, + generated: raw, + str: 'body', + sourcePath: '../integration/sourcemap-css/style.css' + }); - assert.deepStrictEqual( - consumer.originalPositionFor( - indexToLineCol(raw, raw.indexOf('background-color')) - ), - { - source: '../integration/sourcemap-css/style.css', - name: null, - line: indexToLineCol(input, input.indexOf('background-color')).line, - column: indexToLineCol(input, input.indexOf('background-color')).column - }, - "map 'background-color'" - ); + checkSourceMapping({ + map: sourceMap, + source: input, + generated: raw, + str: 'background-color', + sourcePath: '../integration/sourcemap-css/style.css' + }); }); it('should create a valid sourcemap for a CSS bundle with imports', async function() { - let b = await bundle( - path.join(__dirname, '/integration/sourcemap-css-import/style.css'), - {minify: true} - ); - - await assertBundleTree(b, { - name: 'style.css', - assets: ['style.css', 'other-style.css', 'another-style.css'], - childBundles: [ - { - name: 'style.css.map', - type: 'map' - } - ] - }); - - let style = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-css-import/style.css') - )).toString(); - let otherStyle = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-css-import/other-style.css') - )).toString(); - let anotherStyle = (await fs.readFile( - path.join( - __dirname, - '/integration/sourcemap-css-import/another-style.css' - ) - )).toString(); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/style.css') - )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString(); - - assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); - - let consumer = await new SourceMapConsumer(map); - assert.deepStrictEqual( - consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('body'))), - { - source: '../integration/sourcemap-css-import/style.css', - name: null, - line: indexToLineCol(style, style.indexOf('body')).line, - column: indexToLineCol(style, style.indexOf('body')).column - }, - "map 'body'" - ); - - assert.deepStrictEqual( - consumer.originalPositionFor( - indexToLineCol(raw, raw.indexOf('background-color')) - ), - { - source: '../integration/sourcemap-css-import/style.css', - name: null, - line: indexToLineCol(style, style.indexOf('background-color')).line, - column: indexToLineCol(style, style.indexOf('background-color')).column - }, - "map 'background-color'" - ); - - assert.deepStrictEqual( - consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('div'))), - { - source: '../integration/sourcemap-css-import/other-style.css', - name: null, - line: indexToLineCol(otherStyle, otherStyle.indexOf('div')).line, - column: indexToLineCol(otherStyle, otherStyle.indexOf('div')).column - }, - "map 'div'" - ); - - assert.deepStrictEqual( - consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('width'))), - { - source: '../integration/sourcemap-css-import/other-style.css', - name: null, - line: indexToLineCol(otherStyle, otherStyle.indexOf('width')).line, - column: indexToLineCol(otherStyle, otherStyle.indexOf('width')).column - }, - "map 'width'" - ); - - assert.deepStrictEqual( - consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('main'))), - { - source: '../integration/sourcemap-css-import/another-style.css', - name: null, - line: indexToLineCol(anotherStyle, anotherStyle.indexOf('main')).line, - column: indexToLineCol(anotherStyle, anotherStyle.indexOf('main')) - .column - }, - "map 'main'" - ); - - assert.deepStrictEqual( - consumer.originalPositionFor( - indexToLineCol(raw, raw.indexOf('font-family')) - ), - { - source: '../integration/sourcemap-css-import/another-style.css', - name: null, - line: indexToLineCol(anotherStyle, anotherStyle.indexOf('font-family')) - .line, - column: indexToLineCol( - anotherStyle, - anotherStyle.indexOf('font-family') - ).column - }, - "map 'font-family'" - ); + async function test(minify) { + let b = await bundle( + path.join(__dirname, '/integration/sourcemap-css-import/style.css'), + {minify} + ); + + await assertBundleTree(b, { + name: 'style.css', + assets: ['style.css', 'other-style.css', 'another-style.css'], + childBundles: [ + { + name: 'style.css.map', + type: 'map' + } + ] + }); + + let style = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-css-import/style.css') + )).toString(); + let otherStyle = (await fs.readFile( + path.join( + __dirname, + '/integration/sourcemap-css-import/other-style.css' + ) + )).toString(); + let anotherStyle = (await fs.readFile( + path.join( + __dirname, + '/integration/sourcemap-css-import/another-style.css' + ) + )).toString(); + let raw = (await fs.readFile( + path.join(__dirname, '/dist/style.css') + )).toString(); + let map = (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString(); + + assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); + + let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + + checkSourceMapping({ + map: sourceMap, + source: style, + generated: raw, + str: 'body', + sourcePath: '../integration/sourcemap-css-import/style.css', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + + checkSourceMapping({ + map: sourceMap, + source: style, + generated: raw, + str: 'background-color', + sourcePath: '../integration/sourcemap-css-import/style.css', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + + checkSourceMapping({ + map: sourceMap, + source: otherStyle, + generated: raw, + str: 'div', + sourcePath: '../integration/sourcemap-css-import/other-style.css', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + + checkSourceMapping({ + map: sourceMap, + source: otherStyle, + generated: raw, + str: 'width', + sourcePath: '../integration/sourcemap-css-import/other-style.css', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + + checkSourceMapping({ + map: sourceMap, + source: anotherStyle, + generated: raw, + str: 'main', + sourcePath: '../integration/sourcemap-css-import/another-style.css', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + + checkSourceMapping({ + map: sourceMap, + source: anotherStyle, + generated: raw, + str: 'font-family', + sourcePath: '../integration/sourcemap-css-import/another-style.css', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + } + + await test(false); + await test(true); }); it('should create a valid sourcemap for a SASS asset', async function() { @@ -524,29 +552,23 @@ describe('sourcemaps', function() { assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); - let consumer = await new SourceMapConsumer(map); + let sourceMap = await new SourceMap().addMap(JSON.parse(map)); - assert.deepStrictEqual( - consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('body'))), - { - source: '../integration/sourcemap-sass/style.scss', - name: null, - line: indexToLineCol(input, input.indexOf('body')).line, - column: indexToLineCol(input, input.indexOf('body')).column - }, - "map 'body'" - ); + checkSourceMapping({ + map: sourceMap, + source: input, + generated: raw, + str: 'body', + sourcePath: '../integration/sourcemap-sass/style.scss' + }); - assert.deepStrictEqual( - consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('color'))), - { - source: '../integration/sourcemap-sass/style.scss', - name: null, - line: indexToLineCol(input, input.indexOf('color')).line, - column: indexToLineCol(input, input.indexOf('color')).column - }, - "map 'color'" - ); + checkSourceMapping({ + map: sourceMap, + source: input, + generated: raw, + str: 'color', + sourcePath: '../integration/sourcemap-sass/style.scss' + }); }); it('should create a valid sourcemap when a CSS asset imports SASS', async function() { @@ -581,53 +603,39 @@ describe('sourcemaps', function() { assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); - let consumer = await new SourceMapConsumer(map); + let sourceMap = await new SourceMap().addMap(JSON.parse(map)); - assert.deepStrictEqual( - consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('body'))), - { - source: '../integration/sourcemap-sass-imported/style.css', - name: null, - line: indexToLineCol(style, style.indexOf('body')).line, - column: indexToLineCol(style, style.indexOf('body')).column - }, - "map 'body'" - ); + checkSourceMapping({ + map: sourceMap, + source: style, + generated: raw, + str: 'body', + sourcePath: '../integration/sourcemap-sass-imported/style.css' + }); - assert.deepStrictEqual( - consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('color'))), - { - source: '../integration/sourcemap-sass-imported/style.css', - name: null, - line: indexToLineCol(style, style.indexOf('color')).line, - column: indexToLineCol(style, style.indexOf('color')).column - }, - "map 'color'" - ); + checkSourceMapping({ + map: sourceMap, + source: style, + generated: raw, + str: 'color', + sourcePath: '../integration/sourcemap-sass-imported/style.css' + }); - assert.deepStrictEqual( - consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('div'))), - { - source: '../integration/sourcemap-sass-imported/other.scss', - name: null, - line: indexToLineCol(other, other.indexOf('div')).line, - column: indexToLineCol(other, other.indexOf('div')).column - }, - "map 'div'" - ); + checkSourceMapping({ + map: sourceMap, + source: other, + generated: raw, + str: 'div', + sourcePath: '../integration/sourcemap-sass-imported/other.scss' + }); - assert.deepStrictEqual( - consumer.originalPositionFor( - indexToLineCol(raw, raw.indexOf('font-family')) - ), - { - source: '../integration/sourcemap-sass-imported/other.scss', - name: null, - line: indexToLineCol(other, other.indexOf('font-family')).line, - column: indexToLineCol(other, other.indexOf('font-family')).column - }, - "map 'font-family'" - ); + checkSourceMapping({ + map: sourceMap, + source: other, + generated: raw, + str: 'font-family', + sourcePath: '../integration/sourcemap-sass-imported/other.scss' + }); }); it('should create a valid sourcemap for a LESS asset', async function() { @@ -659,28 +667,22 @@ describe('sourcemaps', function() { assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); - let consumer = await new SourceMapConsumer(map); + let sourceMap = await new SourceMap().addMap(JSON.parse(map)); - assert.deepStrictEqual( - consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('div'))), - { - source: '../integration/sourcemap-less/style.less', - name: null, - line: indexToLineCol(input, input.indexOf('div')).line, - column: indexToLineCol(input, input.indexOf('div')).column - }, - "map 'div'" - ); + checkSourceMapping({ + map: sourceMap, + source: input, + generated: raw, + str: 'div', + sourcePath: '../integration/sourcemap-less/style.less' + }); - assert.deepStrictEqual( - consumer.originalPositionFor(indexToLineCol(raw, raw.indexOf('width'))), - { - source: '../integration/sourcemap-less/style.less', - name: null, - line: indexToLineCol(input, input.indexOf('width')).line, - column: indexToLineCol(input, input.indexOf('width')).column - }, - "map 'width'" - ); + checkSourceMapping({ + map: sourceMap, + source: input, + generated: raw, + str: 'width', + sourcePath: '../integration/sourcemap-less/style.less' + }); }); }); diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index b45e5685ae6..a4ff64b7fd7 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -27,7 +27,9 @@ class CSSAsset extends Asset { } parse(code) { - let root = postcss.parse(code, {from: this.name, to: this.name}); + let root = postcss.parse(code, { + from: this.name + }); return new CSSAst(code, root); } @@ -104,14 +106,24 @@ class CSSAsset extends Asset { getCSSAst() { // Converts the ast to a CSS ast if needed, so we can apply postcss transforms. if (!(this.ast instanceof CSSAst)) { - this.ast = CSSAsset.prototype.parse.call(this, this.ast.render()); + this.ast = CSSAsset.prototype.parse.call( + this, + this.ast.render(this.name) + ); } return this.ast.root; } async generate() { - let css = this.ast ? this.ast.render() : this.contents; + let css; + if (this.ast) { + let result = this.ast.render(this.name); + css = result.css; + if (result.map) this.sourceMap = result.map; + } else { + css = this.contents; + } let js = ''; if (this.options.hmr) { @@ -132,26 +144,19 @@ class CSSAsset extends Asset { let map; if (this.options.sourceMaps) { if (this.sourceMap) { - const source = this.contents.split('\n'); - const mappings = this.sourceMap._mappings._array - .map(v => ({ - source: this.relativeName, - original: { - line: v.originalLine, - column: v.originalColumn - }, - generated: { - line: v.generatedLine, - column: v.generatedColumn - } - })) - .filter( + if (this.sourceMap instanceof SourceMap) { + map = this.sourceMap; + } else { + map = await new SourceMap([], { + [this.relativeName]: this.contents + }).addMap(this.sourceMap.toJSON()); + + const source = this.contents.split('\n'); + map.mappings = map.mappings.filter( ({original: {line, column}}) => line - 1 < source.length && column < source[line - 1].length ); - map = new SourceMap(mappings, { - [this.relativeName]: this.contents - }); + } if (this.previousSourceMap) { map = await new SourceMap().extendSourceMap( @@ -160,7 +165,9 @@ class CSSAsset extends Asset { ); } } else if (this.previousSourceMap) { - map = this.previousSourceMap; + map = await new SourceMap().addMap(this.previousSourceMap); + } else { + map = new SourceMap().generateEmptyMap(this.relativeName, css); } } @@ -215,13 +222,24 @@ class CSSAst { this.dirty = false; } - render() { + render(name) { if (this.dirty) { - this.css = ''; - postcss.stringify(this.root, c => (this.css += c)); + let {css, map} = this.root.toResult({ + to: name, + map: {inline: false, annotation: false, sourcesContent: false} + }); + + this.css = css; + + return { + css: this.css, + map + }; } - return this.css; + return { + css: this.css + }; } } diff --git a/packages/core/parcel-bundler/src/assets/SASSAsset.js b/packages/core/parcel-bundler/src/assets/SASSAsset.js index 277afb0a1ed..ef4e8076f0b 100644 --- a/packages/core/parcel-bundler/src/assets/SASSAsset.js +++ b/packages/core/parcel-bundler/src/assets/SASSAsset.js @@ -85,7 +85,7 @@ class SASSAsset extends Asset { { type: 'css', value: this.ast ? this.ast.css.toString() : '', - map: this.ast.map ? this.ast.map.toString() : undefined + map: this.ast.map ? JSON.parse(this.ast.map.toString()) : undefined } ]; } From 2570d94c2c4beed441f83827972143c309bd4298 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sat, 5 Jan 2019 12:29:41 +0100 Subject: [PATCH 13/40] Adjust tests --- packages/core/integration-tests/test/html.js | 12 ++++++++---- packages/core/integration-tests/test/parser.js | 6 +++++- packages/core/integration-tests/test/pug.js | 6 +++++- packages/core/integration-tests/test/sourcemaps.js | 1 - packages/core/parcel-bundler/src/assets/LESSAsset.js | 2 +- packages/core/parcel-bundler/src/assets/SASSAsset.js | 5 ++++- 6 files changed, 23 insertions(+), 9 deletions(-) diff --git a/packages/core/integration-tests/test/html.js b/packages/core/integration-tests/test/html.js index ed3962951e4..1dedb145908 100644 --- a/packages/core/integration-tests/test/html.js +++ b/packages/core/integration-tests/test/html.js @@ -24,7 +24,11 @@ describe('html', function() { { type: 'css', assets: ['index.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'html', @@ -219,9 +223,6 @@ describe('html', function() { type: 'css', assets: ['index.css'], childBundles: [ - { - type: 'map' - }, { type: 'js', assets: [ @@ -231,6 +232,9 @@ describe('html', function() { 'hmr-runtime.js' ], childBundles: [] + }, + { + type: 'map' } ] } diff --git a/packages/core/integration-tests/test/parser.js b/packages/core/integration-tests/test/parser.js index af10583255a..3250959cbc3 100644 --- a/packages/core/integration-tests/test/parser.js +++ b/packages/core/integration-tests/test/parser.js @@ -24,7 +24,11 @@ describe('parser', function() { { type: 'css', assets: ['index.cSs'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'html', diff --git a/packages/core/integration-tests/test/pug.js b/packages/core/integration-tests/test/pug.js index 79bc8f0f778..e7139e5d35e 100644 --- a/packages/core/integration-tests/test/pug.js +++ b/packages/core/integration-tests/test/pug.js @@ -24,7 +24,11 @@ describe('pug', function() { { type: 'css', assets: ['index.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'js', diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 95416de0e29..27d9fb31d98 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -3,7 +3,6 @@ const fs = require('@parcel/fs'); const path = require('path'); const mapValidator = require('sourcemap-validator'); const SourceMap = require('parcel-bundler/src/SourceMap'); -const {SourceMapConsumer} = require('source-map'); const {bundler, bundle, run, assertBundleTree} = require('./utils'); function indexToLineCol(str, index) { diff --git a/packages/core/parcel-bundler/src/assets/LESSAsset.js b/packages/core/parcel-bundler/src/assets/LESSAsset.js index b424a1bcd1e..8a914077e03 100644 --- a/packages/core/parcel-bundler/src/assets/LESSAsset.js +++ b/packages/core/parcel-bundler/src/assets/LESSAsset.js @@ -37,7 +37,7 @@ class LESSAsset extends Asset { generate() { let map; - if (this.ast.map) { + if (this.ast && this.ast.map) { map = JSON.parse(this.ast.map.toString()); map.sources = map.sources.map(v => path.relative(this.options.rootDir, v) diff --git a/packages/core/parcel-bundler/src/assets/SASSAsset.js b/packages/core/parcel-bundler/src/assets/SASSAsset.js index ef4e8076f0b..6e59ce921af 100644 --- a/packages/core/parcel-bundler/src/assets/SASSAsset.js +++ b/packages/core/parcel-bundler/src/assets/SASSAsset.js @@ -85,7 +85,10 @@ class SASSAsset extends Asset { { type: 'css', value: this.ast ? this.ast.css.toString() : '', - map: this.ast.map ? JSON.parse(this.ast.map.toString()) : undefined + map: + this.ast && this.ast.map + ? JSON.parse(this.ast.map.toString()) + : undefined } ]; } From f735ec3e8fc8ab8f0c893ac1621655be5338410f Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sat, 5 Jan 2019 14:11:25 +0100 Subject: [PATCH 14/40] Use existing CSS sourcemaps --- .../sourcemap-css-existing/library.css | 2 + .../sourcemap-css-existing/library.css.map | 1 + .../sourcemap-css-existing/library.raw.scss | 13 ++ .../sourcemap-css-existing/style.css | 5 + .../core/integration-tests/test/sourcemaps.js | 100 +++++++++++++- .../parcel-bundler/src/assets/CSSAsset.js | 128 +++++++++++++++--- .../src/packagers/CSSPackager.js | 2 +- 7 files changed, 226 insertions(+), 25 deletions(-) create mode 100644 packages/core/integration-tests/test/integration/sourcemap-css-existing/library.css create mode 100644 packages/core/integration-tests/test/integration/sourcemap-css-existing/library.css.map create mode 100644 packages/core/integration-tests/test/integration/sourcemap-css-existing/library.raw.scss create mode 100644 packages/core/integration-tests/test/integration/sourcemap-css-existing/style.css diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-existing/library.css b/packages/core/integration-tests/test/integration/sourcemap-css-existing/library.css new file mode 100644 index 00000000000..b13111e24ed --- /dev/null +++ b/packages/core/integration-tests/test/integration/sourcemap-css-existing/library.css @@ -0,0 +1,2 @@ +body{font:100% Helvetica,sans-serif;color:#333}body div{background-color:red;width:100px;height:100px} +/*# sourceMappingURL=library.css.map*/ \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-existing/library.css.map b/packages/core/integration-tests/test/integration/sourcemap-css-existing/library.css.map new file mode 100644 index 00000000000..579f260dfcf --- /dev/null +++ b/packages/core/integration-tests/test/integration/sourcemap-css-existing/library.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["library.scss"],"names":[],"mappings":"AAGA,KACE,+BACA,WAEA,SACC,qBACA,YACA","file":"library.css.map","sourceRoot":".","sourcesContent":["$font-stack: Helvetica, sans-serif;\n$primary-color: #333;\n\nbody {\n font: 100% $font-stack;\n color: $primary-color;\n\n div {\n \tbackground-color: red;\n \twidth: 100px;\n \theight: 100px;\n }\n}"]} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-existing/library.raw.scss b/packages/core/integration-tests/test/integration/sourcemap-css-existing/library.raw.scss new file mode 100644 index 00000000000..93097df8f38 --- /dev/null +++ b/packages/core/integration-tests/test/integration/sourcemap-css-existing/library.raw.scss @@ -0,0 +1,13 @@ +$font-stack: Helvetica, sans-serif; +$primary-color: #333; + +body { + font: 100% $font-stack; + color: $primary-color; + + div { + background-color: red; + width: 100px; + height: 100px; + } +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-existing/style.css b/packages/core/integration-tests/test/integration/sourcemap-css-existing/style.css new file mode 100644 index 00000000000..68f1f7062dd --- /dev/null +++ b/packages/core/integration-tests/test/integration/sourcemap-css-existing/style.css @@ -0,0 +1,5 @@ +@import "./library.css"; + +main { + display: none; +} diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 27d9fb31d98..09dc2c14905 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -18,13 +18,20 @@ function checkSourceMapping({ source, generated, str, + generatedStr = str, sourcePath, msg = '' }) { - assert(generated.indexOf(str) !== -1, "'" + str + "' not in generated code"); + assert( + generated.indexOf(generatedStr) !== -1, + "'" + generatedStr + "' not in generated code" + ); assert(source.indexOf(str) !== -1, "'" + str + "' not in source code"); - let generatedPosition = indexToLineCol(generated, generated.indexOf(str)); + let generatedPosition = indexToLineCol( + generated, + generated.indexOf(generatedStr) + ); let sourcePosition = indexToLineCol(source, source.indexOf(str)); let index = map.findClosestGenerated( @@ -398,7 +405,7 @@ describe('sourcemaps', function() { path.join(__dirname, '/dist/style.css.map') )).toString(); - assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); + assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); let sourceMap = await new SourceMap().addMap(JSON.parse(map)); @@ -459,7 +466,7 @@ describe('sourcemaps', function() { path.join(__dirname, '/dist/style.css.map') )).toString(); - assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); + assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); let sourceMap = await new SourceMap().addMap(JSON.parse(map)); @@ -549,7 +556,7 @@ describe('sourcemaps', function() { path.join(__dirname, '/dist/style.css.map') )).toString(); - assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); + assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); let sourceMap = await new SourceMap().addMap(JSON.parse(map)); @@ -600,7 +607,7 @@ describe('sourcemaps', function() { path.join(__dirname, '/dist/style.css.map') )).toString(); - assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); + assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); let sourceMap = await new SourceMap().addMap(JSON.parse(map)); @@ -664,7 +671,7 @@ describe('sourcemaps', function() { path.join(__dirname, '/dist/style.css.map') )).toString(); - assert(raw.includes('/*# sourceMappingURL=/style.css.map*/')); + assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); let sourceMap = await new SourceMap().addMap(JSON.parse(map)); @@ -684,4 +691,83 @@ describe('sourcemaps', function() { sourcePath: '../integration/sourcemap-less/style.less' }); }); + + it('should load existing sourcemaps for CSS files', async function() { + let b = await bundle( + path.join(__dirname, '/integration/sourcemap-css-existing/style.css'), + {minify: true} + ); + + await assertBundleTree(b, { + name: 'style.css', + assets: ['style.css', 'library.css'], + childBundles: [ + { + name: 'style.css.map', + type: 'map' + } + ] + }); + + let style = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-css-existing/style.css') + )).toString(); + let library = (await fs.readFile( + path.join( + __dirname, + '/integration/sourcemap-css-existing/library.raw.scss' + ) + )).toString(); + let raw = (await fs.readFile( + path.join(__dirname, '/dist/style.css') + )).toString(); + let map = (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString(); + + assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + + let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + + checkSourceMapping({ + map: sourceMap, + source: style, + generated: raw, + str: 'main', + sourcePath: '../integration/sourcemap-css-existing/style.css' + }); + + checkSourceMapping({ + map: sourceMap, + source: style, + generated: raw, + str: 'display', + sourcePath: '../integration/sourcemap-css-existing/style.css' + }); + + checkSourceMapping({ + map: sourceMap, + source: library, + generated: raw, + str: 'body', + sourcePath: '../integration/sourcemap-css-existing/library.scss' + }); + + checkSourceMapping({ + map: sourceMap, + source: library, + generated: raw, + str: 'div', + generatedStr: 'body div', + sourcePath: '../integration/sourcemap-css-existing/library.scss' + }); + + checkSourceMapping({ + map: sourceMap, + source: library, + generated: raw, + str: 'background-color', + sourcePath: '../integration/sourcemap-css-existing/library.scss' + }); + }); }); diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index a4ff64b7fd7..25199f79db2 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -1,13 +1,18 @@ const Asset = require('../Asset'); const postcss = require('postcss'); +const path = require('path'); +const fs = require('@parcel/fs'); const valueParser = require('postcss-value-parser'); const postcssTransform = require('../transforms/postcss'); const CssSyntaxError = require('postcss/lib/css-syntax-error'); const SourceMap = require('../SourceMap'); +const logger = require('@parcel/logger'); const URL_RE = /url\s*\("?(?![a-z]+:)/; const IMPORT_RE = /@import/; const PROTOCOL_RE = /^[a-z]+:/; +const SOURCEMAP_RE = /\/\*\s*[@#]\s*sourceMappingURL\s*=\s*([^\s]+)\s*\*\//; +const DATA_URL_RE = /^data:[^;]+(?:;charset=[^;]+)?;base64,(.*)/; class CSSAsset extends Asset { constructor(name, options) { @@ -99,6 +104,12 @@ class CSSAsset extends Asset { }); } + async pretransform() { + if (this.options.sourceMaps) { + await this.loadSourceMap(); + } + } + async transform() { await postcssTransform(this); } @@ -115,6 +126,71 @@ class CSSAsset extends Asset { return this.ast.root; } + async loadSourceMap() { + let match = this.contents.match(SOURCEMAP_RE); + if (match) { + this.contents = this.contents.replace(SOURCEMAP_RE, ''); + + let url = match[1]; + let dataURLMatch = url.match(DATA_URL_RE); + + try { + let json, filename; + if (dataURLMatch) { + filename = this.name; + json = new Buffer(dataURLMatch[1], 'base64').toString(); + } else { + filename = path.join(path.dirname(this.name), url); + json = await fs.readFile(filename, 'utf8'); + + // Add as a dep so we watch the source map for changes. + this.addDependency(filename, {includedInParent: true}); + } + + this.contentsSourceMap = JSON.parse(json); + + // Attempt to read missing source contents + if (!this.contentsSourceMap.sourcesContent) { + this.contentsSourceMap.sourcesContent = []; + } + + let missingSources = this.contentsSourceMap.sources.slice( + this.contentsSourceMap.sourcesContent.length + ); + if (missingSources.length) { + let contents = await Promise.all( + missingSources.map(async source => { + try { + let sourceFile = path.join( + path.dirname(filename), + this.contentsSourceMap.sourceRoot || '', + source + ); + let result = await fs.readFile(sourceFile, 'utf8'); + this.addDependency(sourceFile, {includedInParent: true}); + return result; + } catch (err) { + logger.warn( + `Could not load source file "${source}" in source map of "${ + this.relativeName + }".` + ); + } + }) + ); + + this.contentsSourceMap.sourcesContent = this.contentsSourceMap.sourcesContent.concat( + contents + ); + } + } catch (e) { + logger.warn( + `Could not load existing sourcemap of "${this.relativeName}".` + ); + } + } + } + async generate() { let css; if (this.ast) { @@ -146,29 +222,47 @@ class CSSAsset extends Asset { if (this.sourceMap) { if (this.sourceMap instanceof SourceMap) { map = this.sourceMap; - } else { + } else if (this.sourceMap) { + if (this.sourceMap.toJSON) { + // this.sourceMap instanceof SourceMapGenerator + map = this.sourceMap.toJSON(); + } else if (typeof this.sourceMap === 'string') { + map = JSON.parse(this.sourceMap); + } else { + map = this.sourceMap; + } + map = await new SourceMap([], { [this.relativeName]: this.contents - }).addMap(this.sourceMap.toJSON()); - - const source = this.contents.split('\n'); - map.mappings = map.mappings.filter( - ({original: {line, column}}) => - line - 1 < source.length && column < source[line - 1].length - ); - } - - if (this.previousSourceMap) { - map = await new SourceMap().extendSourceMap( - this.previousSourceMap, - map - ); + }).addMap(map); + + if (this.sourceMap.toJSON) { + // this.sourceMap instanceof SourceMapGenerator + let sourceLines = this.contents.split('\n'); + map.mappings = map.mappings.filter( + ({original: {line, column}}) => + line - 1 < sourceLines.length && + column < sourceLines[line - 1].length + ); + } } - } else if (this.previousSourceMap) { - map = await new SourceMap().addMap(this.previousSourceMap); } else { map = new SourceMap().generateEmptyMap(this.relativeName, css); } + + if (this.previousSourceMap) { + map = await new SourceMap().extendSourceMap( + this.previousSourceMap, + map + ); + } + + if (this.contentsSourceMap) { + map = await new SourceMap().extendSourceMap( + this.contentsSourceMap, + map + ); + } } return [ diff --git a/packages/core/parcel-bundler/src/packagers/CSSPackager.js b/packages/core/parcel-bundler/src/packagers/CSSPackager.js index 3b3cf5f2f7a..558fed375e6 100644 --- a/packages/core/parcel-bundler/src/packagers/CSSPackager.js +++ b/packages/core/parcel-bundler/src/packagers/CSSPackager.js @@ -53,7 +53,7 @@ class CSSPackager extends Packager { this.options.publicURL, path.basename(mapBundle.name) ); - await this.write(`\n/*# sourceMappingURL=${mapUrl}*/`); + await this.write(`\n/*# sourceMappingURL=${mapUrl} */`); } } } From 93bae077c8a2243bbf921a2ad1a0a4b285865266 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sat, 5 Jan 2019 19:00:03 +0100 Subject: [PATCH 15/40] Extract loadSourceMap into util file --- .../parcel-bundler/src/assets/CSSAsset.js | 73 +----------------- .../core/parcel-bundler/src/assets/JSAsset.js | 74 +----------------- .../parcel-bundler/src/utils/loadSourceMap.js | 75 +++++++++++++++++++ 3 files changed, 79 insertions(+), 143 deletions(-) create mode 100644 packages/core/parcel-bundler/src/utils/loadSourceMap.js diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 25199f79db2..58524f88d04 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -1,18 +1,14 @@ const Asset = require('../Asset'); const postcss = require('postcss'); -const path = require('path'); -const fs = require('@parcel/fs'); const valueParser = require('postcss-value-parser'); const postcssTransform = require('../transforms/postcss'); const CssSyntaxError = require('postcss/lib/css-syntax-error'); const SourceMap = require('../SourceMap'); -const logger = require('@parcel/logger'); +const loadSourceMap = require('../utils/loadSourceMap'); const URL_RE = /url\s*\("?(?![a-z]+:)/; const IMPORT_RE = /@import/; const PROTOCOL_RE = /^[a-z]+:/; -const SOURCEMAP_RE = /\/\*\s*[@#]\s*sourceMappingURL\s*=\s*([^\s]+)\s*\*\//; -const DATA_URL_RE = /^data:[^;]+(?:;charset=[^;]+)?;base64,(.*)/; class CSSAsset extends Asset { constructor(name, options) { @@ -106,7 +102,7 @@ class CSSAsset extends Asset { async pretransform() { if (this.options.sourceMaps) { - await this.loadSourceMap(); + this.contentsSourceMap = await loadSourceMap(this); } } @@ -126,71 +122,6 @@ class CSSAsset extends Asset { return this.ast.root; } - async loadSourceMap() { - let match = this.contents.match(SOURCEMAP_RE); - if (match) { - this.contents = this.contents.replace(SOURCEMAP_RE, ''); - - let url = match[1]; - let dataURLMatch = url.match(DATA_URL_RE); - - try { - let json, filename; - if (dataURLMatch) { - filename = this.name; - json = new Buffer(dataURLMatch[1], 'base64').toString(); - } else { - filename = path.join(path.dirname(this.name), url); - json = await fs.readFile(filename, 'utf8'); - - // Add as a dep so we watch the source map for changes. - this.addDependency(filename, {includedInParent: true}); - } - - this.contentsSourceMap = JSON.parse(json); - - // Attempt to read missing source contents - if (!this.contentsSourceMap.sourcesContent) { - this.contentsSourceMap.sourcesContent = []; - } - - let missingSources = this.contentsSourceMap.sources.slice( - this.contentsSourceMap.sourcesContent.length - ); - if (missingSources.length) { - let contents = await Promise.all( - missingSources.map(async source => { - try { - let sourceFile = path.join( - path.dirname(filename), - this.contentsSourceMap.sourceRoot || '', - source - ); - let result = await fs.readFile(sourceFile, 'utf8'); - this.addDependency(sourceFile, {includedInParent: true}); - return result; - } catch (err) { - logger.warn( - `Could not load source file "${source}" in source map of "${ - this.relativeName - }".` - ); - } - }) - ); - - this.contentsSourceMap.sourcesContent = this.contentsSourceMap.sourcesContent.concat( - contents - ); - } - } catch (e) { - logger.warn( - `Could not load existing sourcemap of "${this.relativeName}".` - ); - } - } - } - async generate() { let css; if (this.ast) { diff --git a/packages/core/parcel-bundler/src/assets/JSAsset.js b/packages/core/parcel-bundler/src/assets/JSAsset.js index 5e108895203..11cf1f90860 100644 --- a/packages/core/parcel-bundler/src/assets/JSAsset.js +++ b/packages/core/parcel-bundler/src/assets/JSAsset.js @@ -13,9 +13,7 @@ const generate = require('@babel/generator').default; const terser = require('../transforms/terser'); const SourceMap = require('../SourceMap'); const hoist = require('../scope-hoisting/hoist'); -const path = require('path'); -const fs = require('@parcel/fs'); -const logger = require('@parcel/logger'); +const loadSourceMap = require('../utils/loadSourceMap'); const IMPORT_RE = /\b(?:import\b|export\b|require\s*\()/; const ENV_RE = /\b(?:process\.env)\b/; @@ -23,8 +21,6 @@ const GLOBAL_RE = /\b(?:process|__dirname|__filename|global|Buffer|define)\b/; const FS_RE = /\breadFileSync\b/; const SW_RE = /\bnavigator\s*\.\s*serviceWorker\s*\.\s*register\s*\(/; const WORKER_RE = /\bnew\s*(?:Shared)?Worker\s*\(/; -const SOURCEMAP_RE = /\/\/\s*[@#]\s*sourceMappingURL\s*=\s*([^\s]+)/; -const DATA_URL_RE = /^data:[^;]+(?:;charset=[^;]+)?;base64,(.*)/; class JSAsset extends Asset { constructor(name, options) { @@ -82,75 +78,9 @@ class JSAsset extends Asset { walk.ancestor(this.ast, collectDependencies, this); } - async loadSourceMap() { - // Get original sourcemap if there is any - let match = this.contents.match(SOURCEMAP_RE); - if (match) { - this.contents = this.contents.replace(SOURCEMAP_RE, ''); - - let url = match[1]; - let dataURLMatch = url.match(DATA_URL_RE); - - try { - let json, filename; - if (dataURLMatch) { - filename = this.name; - json = new Buffer(dataURLMatch[1], 'base64').toString(); - } else { - filename = path.join(path.dirname(this.name), url); - json = await fs.readFile(filename, 'utf8'); - - // Add as a dep so we watch the source map for changes. - this.addDependency(filename, {includedInParent: true}); - } - - this.sourceMap = JSON.parse(json); - - // Attempt to read missing source contents - if (!this.sourceMap.sourcesContent) { - this.sourceMap.sourcesContent = []; - } - - let missingSources = this.sourceMap.sources.slice( - this.sourceMap.sourcesContent.length - ); - if (missingSources.length) { - let contents = await Promise.all( - missingSources.map(async source => { - try { - let sourceFile = path.join( - path.dirname(filename), - this.sourceMap.sourceRoot || '', - source - ); - let result = await fs.readFile(sourceFile, 'utf8'); - this.addDependency(sourceFile, {includedInParent: true}); - return result; - } catch (err) { - logger.warn( - `Could not load source file "${source}" in source map of "${ - this.relativeName - }".` - ); - } - }) - ); - - this.sourceMap.sourcesContent = this.sourceMap.sourcesContent.concat( - contents - ); - } - } catch (e) { - logger.warn( - `Could not load existing sourcemap of "${this.relativeName}".` - ); - } - } - } - async pretransform() { if (this.options.sourceMaps) { - await this.loadSourceMap(); + this.sourceMap = await loadSourceMap(this); } await babel(this); diff --git a/packages/core/parcel-bundler/src/utils/loadSourceMap.js b/packages/core/parcel-bundler/src/utils/loadSourceMap.js new file mode 100644 index 00000000000..d7fb5931009 --- /dev/null +++ b/packages/core/parcel-bundler/src/utils/loadSourceMap.js @@ -0,0 +1,75 @@ +const logger = require('@parcel/logger'); +const path = require('path'); +const fs = require('@parcel/fs'); + +const SOURCEMAP_RE = /(?:\/\*|\/\/)\s*[@#]\s*sourceMappingURL\s*=\s*([^\s*]+)(?:\s*\*\/)?/; +const DATA_URL_RE = /^data:[^;]+(?:;charset=[^;]+)?;base64,(.*)/; + +async function loadSourceMap(asset) { + // Get original sourcemap if there is any + let match = asset.contents.match(SOURCEMAP_RE); + let sourceMap; + if (match) { + asset.contents = asset.contents.replace(SOURCEMAP_RE, ''); + + let url = match[1]; + let dataURLMatch = url.match(DATA_URL_RE); + + try { + let json, filename; + if (dataURLMatch) { + filename = asset.name; + json = Buffer.from(dataURLMatch[1], 'base64').toString(); + } else { + filename = path.join(path.dirname(asset.name), url); + json = await fs.readFile(filename, 'utf8'); + + // Add as a dep so we watch the source map for changes. + asset.addDependency(filename, {includedInParent: true}); + } + + sourceMap = JSON.parse(json); + + // Attempt to read missing source contents + if (!sourceMap.sourcesContent) { + sourceMap.sourcesContent = []; + } + + let missingSources = sourceMap.sources.slice( + sourceMap.sourcesContent.length + ); + if (missingSources.length) { + let contents = await Promise.all( + missingSources.map(async source => { + try { + let sourceFile = path.join( + path.dirname(filename), + sourceMap.sourceRoot || '', + source + ); + let result = await fs.readFile(sourceFile, 'utf8'); + asset.addDependency(sourceFile, {includedInParent: true}); + return result; + } catch (err) { + logger.warn( + `Could not load source file "${source}" in source map of "${ + asset.relativeName + }".` + ); + } + }) + ); + + sourceMap.sourcesContent = sourceMap.sourcesContent.concat(contents); + } + } catch (e) { + logger.warn( + `Could not load existing sourcemap of "${asset.relativeName}".` + ); + sourceMap = undefined; + } + } + return sourceMap; +} + +module.exports = loadSourceMap; From bf9fbfd6d3fc14308586843fe1729a0e4315dbe8 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sat, 5 Jan 2019 19:27:59 +0100 Subject: [PATCH 16/40] Refactor CSSAsset sourcemap --- packages/core/parcel-bundler/src/SourceMap.js | 7 +++++++ .../parcel-bundler/src/assets/CSSAsset.js | 20 +++++++------------ .../parcel-bundler/src/transforms/postcss.js | 2 +- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/core/parcel-bundler/src/SourceMap.js b/packages/core/parcel-bundler/src/SourceMap.js index 4f1c3a73b5e..81ccc10c77c 100644 --- a/packages/core/parcel-bundler/src/SourceMap.js +++ b/packages/core/parcel-bundler/src/SourceMap.js @@ -38,7 +38,13 @@ class SourceMap { } async addMap(map, lineOffset = 0, columnOffset = 0) { + if (map.toJSON) { + // SourceMapGenerator + map = map.toJSON(); + } + if (!(map instanceof SourceMap) && map.version) { + // JSON let consumer = await this.getConsumer(map); consumer.eachMapping(mapping => { @@ -57,6 +63,7 @@ class SourceMap { } } else { if (!map.eachMapping) { + // not a SourceMapConsumer map = new SourceMap(map.mappings, map.sources); } diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 58524f88d04..9327e83e318 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -153,19 +153,13 @@ class CSSAsset extends Asset { if (this.sourceMap) { if (this.sourceMap instanceof SourceMap) { map = this.sourceMap; - } else if (this.sourceMap) { - if (this.sourceMap.toJSON) { - // this.sourceMap instanceof SourceMapGenerator - map = this.sourceMap.toJSON(); - } else if (typeof this.sourceMap === 'string') { - map = JSON.parse(this.sourceMap); - } else { - map = this.sourceMap; - } + } else { + map = + typeof this.sourceMap === 'string' + ? JSON.parse(this.sourceMap) + : this.sourceMap; - map = await new SourceMap([], { - [this.relativeName]: this.contents - }).addMap(map); + map = await new SourceMap().addMap(map); if (this.sourceMap.toJSON) { // this.sourceMap instanceof SourceMapGenerator @@ -251,7 +245,7 @@ class CSSAst { if (this.dirty) { let {css, map} = this.root.toResult({ to: name, - map: {inline: false, annotation: false, sourcesContent: false} + map: {inline: false, annotation: false, sourcesContent: true} }); this.css = css; diff --git a/packages/core/parcel-bundler/src/transforms/postcss.js b/packages/core/parcel-bundler/src/transforms/postcss.js index 05da218f1e3..f34b74da9d9 100644 --- a/packages/core/parcel-bundler/src/transforms/postcss.js +++ b/packages/core/parcel-bundler/src/transforms/postcss.js @@ -32,7 +32,7 @@ async function getConfig(asset) { config = config || {}; if (asset.options.sourceMaps) { - config.map = {inline: false, annotation: false, sourcesContent: false}; + config.map = {inline: false, annotation: false, sourcesContent: true}; } if (typeof config !== 'object') { From 8dfd04b8e8fa8f225e57a126d02e7ddfa9134b42 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sat, 5 Jan 2019 19:29:10 +0100 Subject: [PATCH 17/40] Run CSS sourcemap tests also without minify --- .../core/integration-tests/test/sourcemaps.js | 533 ++++++++++-------- 1 file changed, 293 insertions(+), 240 deletions(-) diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 09dc2c14905..b5c5474ef22 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -379,51 +379,60 @@ describe('sourcemaps', function() { }); it('should create a valid sourcemap as a child of a CSS bundle', async function() { - let b = await bundle( - path.join(__dirname, '/integration/sourcemap-css/style.css'), - {minify: true} - ); + async function test(minify) { + let b = await bundle( + path.join(__dirname, '/integration/sourcemap-css/style.css'), + {minify: true} + ); - await assertBundleTree(b, { - name: 'style.css', - assets: ['style.css'], - childBundles: [ - { - name: 'style.css.map', - type: 'map' - } - ] - }); + await assertBundleTree(b, { + name: 'style.css', + assets: ['style.css'], + childBundles: [ + { + name: 'style.css.map', + type: 'map' + } + ] + }); - let input = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-css/style.css') - )).toString(); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/style.css') - )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString(); + let input = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-css/style.css') + )).toString(); + let raw = (await fs.readFile( + path.join(__dirname, '/dist/style.css') + )).toString(); + let map = (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString(); - assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); - let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + assert(map.includes('background-color:')); - checkSourceMapping({ - map: sourceMap, - source: input, - generated: raw, - str: 'body', - sourcePath: '../integration/sourcemap-css/style.css' - }); + let sourceMap = await new SourceMap().addMap(JSON.parse(map)); - checkSourceMapping({ - map: sourceMap, - source: input, - generated: raw, - str: 'background-color', - sourcePath: '../integration/sourcemap-css/style.css' - }); + checkSourceMapping({ + map: sourceMap, + source: input, + generated: raw, + str: 'body', + sourcePath: '../integration/sourcemap-css/style.css', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + + checkSourceMapping({ + map: sourceMap, + source: input, + generated: raw, + str: 'background-color', + sourcePath: '../integration/sourcemap-css/style.css', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + } + + await test(false); + await test(true); }); it('should create a valid sourcemap for a CSS bundle with imports', async function() { @@ -468,6 +477,10 @@ describe('sourcemaps', function() { assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + assert(map.includes('background-color:')); + assert(map.includes('font-family:')); + assert(map.includes('width:')); + let sourceMap = await new SourceMap().addMap(JSON.parse(map)); checkSourceMapping({ @@ -530,244 +543,284 @@ describe('sourcemaps', function() { }); it('should create a valid sourcemap for a SASS asset', async function() { - let b = await bundle( - path.join(__dirname, '/integration/sourcemap-sass/style.scss'), - {minify: true} - ); + async function test(minify) { + let b = await bundle( + path.join(__dirname, '/integration/sourcemap-sass/style.scss'), + {minify} + ); - await assertBundleTree(b, { - name: 'style.css', - assets: ['style.scss'], - childBundles: [ - { - name: 'style.css.map', - type: 'map' - } - ] - }); + await assertBundleTree(b, { + name: 'style.css', + assets: ['style.scss'], + childBundles: [ + { + name: 'style.css.map', + type: 'map' + } + ] + }); - let input = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-sass/style.scss') - )).toString(); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/style.css') - )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString(); + let input = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-sass/style.scss') + )).toString(); + let raw = (await fs.readFile( + path.join(__dirname, '/dist/style.css') + )).toString(); + let map = (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString(); + + assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); - assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + assert(map.includes('$variable:')); - let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + let sourceMap = await new SourceMap().addMap(JSON.parse(map)); - checkSourceMapping({ - map: sourceMap, - source: input, - generated: raw, - str: 'body', - sourcePath: '../integration/sourcemap-sass/style.scss' - }); + checkSourceMapping({ + map: sourceMap, + source: input, + generated: raw, + str: 'body', + sourcePath: '../integration/sourcemap-sass/style.scss', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); - checkSourceMapping({ - map: sourceMap, - source: input, - generated: raw, - str: 'color', - sourcePath: '../integration/sourcemap-sass/style.scss' - }); + checkSourceMapping({ + map: sourceMap, + source: input, + generated: raw, + str: 'color', + sourcePath: '../integration/sourcemap-sass/style.scss', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + } + + await test(false); + await test(true); }); it('should create a valid sourcemap when a CSS asset imports SASS', async function() { - let b = await bundle( - path.join(__dirname, '/integration/sourcemap-sass-imported/style.css'), - {minify: true} - ); + async function test(minify) { + let b = await bundle( + path.join(__dirname, '/integration/sourcemap-sass-imported/style.css'), + {minify} + ); - await assertBundleTree(b, { - name: 'style.css', - assets: ['style.css', 'other.scss'], - childBundles: [ - { - name: 'style.css.map', - type: 'map' - } - ] - }); + await assertBundleTree(b, { + name: 'style.css', + assets: ['style.css', 'other.scss'], + childBundles: [ + { + name: 'style.css.map', + type: 'map' + } + ] + }); - let style = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-sass-imported/style.css') - )).toString(); - let other = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-sass-imported/other.scss') - )).toString(); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/style.css') - )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString(); + let style = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-sass-imported/style.css') + )).toString(); + let other = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-sass-imported/other.scss') + )).toString(); + let raw = (await fs.readFile( + path.join(__dirname, '/dist/style.css') + )).toString(); + let map = (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString(); - assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); - let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + assert(map.includes('$variable:')); + assert(map.includes('color:')); - checkSourceMapping({ - map: sourceMap, - source: style, - generated: raw, - str: 'body', - sourcePath: '../integration/sourcemap-sass-imported/style.css' - }); + let sourceMap = await new SourceMap().addMap(JSON.parse(map)); - checkSourceMapping({ - map: sourceMap, - source: style, - generated: raw, - str: 'color', - sourcePath: '../integration/sourcemap-sass-imported/style.css' - }); + checkSourceMapping({ + map: sourceMap, + source: style, + generated: raw, + str: 'body', + sourcePath: '../integration/sourcemap-sass-imported/style.css', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); - checkSourceMapping({ - map: sourceMap, - source: other, - generated: raw, - str: 'div', - sourcePath: '../integration/sourcemap-sass-imported/other.scss' - }); + checkSourceMapping({ + map: sourceMap, + source: style, + generated: raw, + str: 'color', + sourcePath: '../integration/sourcemap-sass-imported/style.css', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); - checkSourceMapping({ - map: sourceMap, - source: other, - generated: raw, - str: 'font-family', - sourcePath: '../integration/sourcemap-sass-imported/other.scss' - }); + checkSourceMapping({ + map: sourceMap, + source: other, + generated: raw, + str: 'div', + sourcePath: '../integration/sourcemap-sass-imported/other.scss', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + + checkSourceMapping({ + map: sourceMap, + source: other, + generated: raw, + str: 'font-family', + sourcePath: '../integration/sourcemap-sass-imported/other.scss', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + } + await test(false); + await test(true); }); it('should create a valid sourcemap for a LESS asset', async function() { - let b = await bundle( - path.join(__dirname, '/integration/sourcemap-less/style.less'), - {minify: true} - ); + async function test(minify) { + let b = await bundle( + path.join(__dirname, '/integration/sourcemap-less/style.less'), + {minify} + ); - await assertBundleTree(b, { - name: 'style.css', - assets: ['style.less'], - childBundles: [ - { - name: 'style.css.map', - type: 'map' - } - ] - }); + await assertBundleTree(b, { + name: 'style.css', + assets: ['style.less'], + childBundles: [ + { + name: 'style.css.map', + type: 'map' + } + ] + }); - let input = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-less/style.less') - )).toString(); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/style.css') - )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString(); + let input = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-less/style.less') + )).toString(); + let raw = (await fs.readFile( + path.join(__dirname, '/dist/style.css') + )).toString(); + let map = (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString(); - assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); - let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + assert(map.includes('@value:')); - checkSourceMapping({ - map: sourceMap, - source: input, - generated: raw, - str: 'div', - sourcePath: '../integration/sourcemap-less/style.less' - }); + let sourceMap = await new SourceMap().addMap(JSON.parse(map)); - checkSourceMapping({ - map: sourceMap, - source: input, - generated: raw, - str: 'width', - sourcePath: '../integration/sourcemap-less/style.less' - }); + checkSourceMapping({ + map: sourceMap, + source: input, + generated: raw, + str: 'div', + sourcePath: '../integration/sourcemap-less/style.less', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + + checkSourceMapping({ + map: sourceMap, + source: input, + generated: raw, + str: 'width', + sourcePath: '../integration/sourcemap-less/style.less', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + } + await test(false); + await test(true); }); it('should load existing sourcemaps for CSS files', async function() { - let b = await bundle( - path.join(__dirname, '/integration/sourcemap-css-existing/style.css'), - {minify: true} - ); + async function test(minify) { + let b = await bundle( + path.join(__dirname, '/integration/sourcemap-css-existing/style.css'), + {minify} + ); - await assertBundleTree(b, { - name: 'style.css', - assets: ['style.css', 'library.css'], - childBundles: [ - { - name: 'style.css.map', - type: 'map' - } - ] - }); + await assertBundleTree(b, { + name: 'style.css', + assets: ['style.css', 'library.css'], + childBundles: [ + { + name: 'style.css.map', + type: 'map' + } + ] + }); - let style = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-css-existing/style.css') - )).toString(); - let library = (await fs.readFile( - path.join( - __dirname, - '/integration/sourcemap-css-existing/library.raw.scss' - ) - )).toString(); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/style.css') - )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString(); + let style = (await fs.readFile( + path.join(__dirname, '/integration/sourcemap-css-existing/style.css') + )).toString(); + let library = (await fs.readFile( + path.join( + __dirname, + '/integration/sourcemap-css-existing/library.raw.scss' + ) + )).toString(); + let raw = (await fs.readFile( + path.join(__dirname, '/dist/style.css') + )).toString(); + let map = (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString(); - assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); - let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + assert(map.includes('$font-stack:')); + assert(map.includes('display:')); - checkSourceMapping({ - map: sourceMap, - source: style, - generated: raw, - str: 'main', - sourcePath: '../integration/sourcemap-css-existing/style.css' - }); + let sourceMap = await new SourceMap().addMap(JSON.parse(map)); - checkSourceMapping({ - map: sourceMap, - source: style, - generated: raw, - str: 'display', - sourcePath: '../integration/sourcemap-css-existing/style.css' - }); + checkSourceMapping({ + map: sourceMap, + source: style, + generated: raw, + str: 'main', + sourcePath: '../integration/sourcemap-css-existing/style.css', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); - checkSourceMapping({ - map: sourceMap, - source: library, - generated: raw, - str: 'body', - sourcePath: '../integration/sourcemap-css-existing/library.scss' - }); + checkSourceMapping({ + map: sourceMap, + source: style, + generated: raw, + str: 'display', + sourcePath: '../integration/sourcemap-css-existing/style.css', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); - checkSourceMapping({ - map: sourceMap, - source: library, - generated: raw, - str: 'div', - generatedStr: 'body div', - sourcePath: '../integration/sourcemap-css-existing/library.scss' - }); + checkSourceMapping({ + map: sourceMap, + source: library, + generated: raw, + str: 'body', + sourcePath: '../integration/sourcemap-css-existing/library.scss', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); - checkSourceMapping({ - map: sourceMap, - source: library, - generated: raw, - str: 'background-color', - sourcePath: '../integration/sourcemap-css-existing/library.scss' - }); + checkSourceMapping({ + map: sourceMap, + source: library, + generated: raw, + str: 'div', + generatedStr: 'body div', + sourcePath: '../integration/sourcemap-css-existing/library.scss', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + + checkSourceMapping({ + map: sourceMap, + source: library, + generated: raw, + str: 'background-color', + sourcePath: '../integration/sourcemap-css-existing/library.scss', + msg: ' ' + (minify ? 'with' : 'without') + ' minification' + }); + } + await test(false); + await test(true); }); }); From 4d934de7c297c0fabe7504016117e66a081a8c36 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sun, 6 Jan 2019 00:16:46 +0100 Subject: [PATCH 18/40] Source maps for imported CSS without minify --- packages/core/parcel-bundler/src/SourceMap.js | 7 +-- .../parcel-bundler/src/assets/CSSAsset.js | 53 ++++++++++--------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/packages/core/parcel-bundler/src/SourceMap.js b/packages/core/parcel-bundler/src/SourceMap.js index 81ccc10c77c..7ec0ea740f0 100644 --- a/packages/core/parcel-bundler/src/SourceMap.js +++ b/packages/core/parcel-bundler/src/SourceMap.js @@ -43,8 +43,10 @@ class SourceMap { map = map.toJSON(); } - if (!(map instanceof SourceMap) && map.version) { - // JSON + if ( + (!(map instanceof SourceMap) && map.version) || + typeof map === 'string' + ) { let consumer = await this.getConsumer(map); consumer.eachMapping(mapping => { @@ -63,7 +65,6 @@ class SourceMap { } } else { if (!map.eachMapping) { - // not a SourceMapConsumer map = new SourceMap(map.mappings, map.sources); } diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 9327e83e318..092f199de87 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -10,11 +10,19 @@ const URL_RE = /url\s*\("?(?![a-z]+:)/; const IMPORT_RE = /@import/; const PROTOCOL_RE = /^[a-z]+:/; +async function sourceMapReplaceOrExtend(extension, base) { + if (base) { + return await new SourceMap().extendSourceMap(extension, base); + } else { + return await new SourceMap().addMap(extension); + } +} + class CSSAsset extends Asset { constructor(name, options) { super(name, options); this.type = 'css'; - this.previousSourceMap = this.options.rendition + this.sourceMapFromPipeline = this.options.rendition ? this.options.rendition.map : null; } @@ -102,7 +110,7 @@ class CSSAsset extends Asset { async pretransform() { if (this.options.sourceMaps) { - this.contentsSourceMap = await loadSourceMap(this); + this.sourceMapExisting = await loadSourceMap(this); } } @@ -154,39 +162,34 @@ class CSSAsset extends Asset { if (this.sourceMap instanceof SourceMap) { map = this.sourceMap; } else { - map = - typeof this.sourceMap === 'string' - ? JSON.parse(this.sourceMap) - : this.sourceMap; - - map = await new SourceMap().addMap(map); + map = await new SourceMap().addMap(this.sourceMap); if (this.sourceMap.toJSON) { - // this.sourceMap instanceof SourceMapGenerator - let sourceLines = this.contents.split('\n'); + // a SourceMapGenerator, PostCSS's sourcemaps contain invalid entries + let sourceLines = {}; + for (let [path, content] of Object.entries(map.sources)) { + sourceLines[path] = content.split('\n'); + } + map.mappings = map.mappings.filter( - ({original: {line, column}}) => - line - 1 < sourceLines.length && - column < sourceLines[line - 1].length + ({source, original: {line, column}}) => + line - 1 < sourceLines[source].length && + column < sourceLines[source][line - 1].length ); } } - } else { - map = new SourceMap().generateEmptyMap(this.relativeName, css); } - if (this.previousSourceMap) { - map = await new SourceMap().extendSourceMap( - this.previousSourceMap, - map - ); + if (this.sourceMapFromPipeline) { + map = await sourceMapReplaceOrExtend(this.sourceMapFromPipeline, map); } - if (this.contentsSourceMap) { - map = await new SourceMap().extendSourceMap( - this.contentsSourceMap, - map - ); + if (this.sourceMapExisting) { + map = await sourceMapReplaceOrExtend(this.sourceMapExisting, map); + } + + if (!map) { + map = new SourceMap().generateEmptyMap(this.relativeName, css); } } From cab31b5eff27ecd340f8b6009a4c46dfa6086956 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sun, 6 Jan 2019 17:53:25 +0100 Subject: [PATCH 19/40] Cleanup --- .../parcel-bundler/src/assets/CSSAsset.js | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 092f199de87..a6c0ac80aa2 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -10,19 +10,11 @@ const URL_RE = /url\s*\("?(?![a-z]+:)/; const IMPORT_RE = /@import/; const PROTOCOL_RE = /^[a-z]+:/; -async function sourceMapReplaceOrExtend(extension, base) { - if (base) { - return await new SourceMap().extendSourceMap(extension, base); - } else { - return await new SourceMap().addMap(extension); - } -} - class CSSAsset extends Asset { constructor(name, options) { super(name, options); this.type = 'css'; - this.sourceMapFromPipeline = this.options.rendition + this.previousSourceMap = this.options.rendition ? this.options.rendition.map : null; } @@ -109,8 +101,8 @@ class CSSAsset extends Asset { } async pretransform() { - if (this.options.sourceMaps) { - this.sourceMapExisting = await loadSourceMap(this); + if (this.options.sourceMaps && !this.previousSourceMap) { + this.previousSourceMap = await loadSourceMap(this); } } @@ -180,12 +172,15 @@ class CSSAsset extends Asset { } } - if (this.sourceMapFromPipeline) { - map = await sourceMapReplaceOrExtend(this.sourceMapFromPipeline, map); - } - - if (this.sourceMapExisting) { - map = await sourceMapReplaceOrExtend(this.sourceMapExisting, map); + if (this.previousSourceMap) { + if (map) { + map = await new SourceMap().extendSourceMap( + this.previousSourceMap, + map + ); + } else { + map = await new SourceMap().addMap(this.previousSourceMap); + } } if (!map) { From 5ec11df87a5ccd988eaad57bc5c220e6bfbe6576 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Mon, 7 Jan 2019 16:23:29 +0100 Subject: [PATCH 20/40] Correct CSS sourcemaps source paths --- .../core/integration-tests/test/sourcemaps.js | 134 ++++++++++-------- .../parcel-bundler/src/assets/CSSAsset.js | 11 +- 2 files changed, 80 insertions(+), 65 deletions(-) diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index b5c5474ef22..5a154099878 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -402,22 +402,24 @@ describe('sourcemaps', function() { let raw = (await fs.readFile( path.join(__dirname, '/dist/style.css') )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString(); + let map = JSON.parse( + (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString() + ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + assert(map.sourceRoot == '../integration/sourcemap-css'); - assert(map.includes('background-color:')); - - let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + let sourceMap = await new SourceMap().addMap(map); + assert.equal(sourceMap.sources['style.css'], input); checkSourceMapping({ map: sourceMap, source: input, generated: raw, str: 'body', - sourcePath: '../integration/sourcemap-css/style.css', + sourcePath: 'style.css', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -426,7 +428,7 @@ describe('sourcemaps', function() { source: input, generated: raw, str: 'background-color', - sourcePath: '../integration/sourcemap-css/style.css', + sourcePath: 'style.css', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); } @@ -471,24 +473,26 @@ describe('sourcemaps', function() { let raw = (await fs.readFile( path.join(__dirname, '/dist/style.css') )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString(); + let map = JSON.parse( + (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString() + ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + assert(map.sourceRoot == '../integration/sourcemap-css-import'); - assert(map.includes('background-color:')); - assert(map.includes('font-family:')); - assert(map.includes('width:')); - - let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + let sourceMap = await new SourceMap().addMap(map); + assert.equal(sourceMap.sources['style.css'], style); + assert.equal(sourceMap.sources['other-style.css'], otherStyle); + assert.equal(sourceMap.sources['another-style.css'], anotherStyle); checkSourceMapping({ map: sourceMap, source: style, generated: raw, str: 'body', - sourcePath: '../integration/sourcemap-css-import/style.css', + sourcePath: 'style.css', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -497,7 +501,7 @@ describe('sourcemaps', function() { source: style, generated: raw, str: 'background-color', - sourcePath: '../integration/sourcemap-css-import/style.css', + sourcePath: 'style.css', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -506,7 +510,7 @@ describe('sourcemaps', function() { source: otherStyle, generated: raw, str: 'div', - sourcePath: '../integration/sourcemap-css-import/other-style.css', + sourcePath: 'other-style.css', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -515,7 +519,7 @@ describe('sourcemaps', function() { source: otherStyle, generated: raw, str: 'width', - sourcePath: '../integration/sourcemap-css-import/other-style.css', + sourcePath: 'other-style.css', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -524,7 +528,7 @@ describe('sourcemaps', function() { source: anotherStyle, generated: raw, str: 'main', - sourcePath: '../integration/sourcemap-css-import/another-style.css', + sourcePath: 'another-style.css', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -533,7 +537,7 @@ describe('sourcemaps', function() { source: anotherStyle, generated: raw, str: 'font-family', - sourcePath: '../integration/sourcemap-css-import/another-style.css', + sourcePath: 'another-style.css', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); } @@ -566,22 +570,24 @@ describe('sourcemaps', function() { let raw = (await fs.readFile( path.join(__dirname, '/dist/style.css') )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString(); + let map = JSON.parse( + (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString() + ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + assert(map.sourceRoot == '../integration/sourcemap-sass'); - assert(map.includes('$variable:')); - - let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + let sourceMap = await new SourceMap().addMap(map); + assert.equal(sourceMap.sources['style.scss'], input); checkSourceMapping({ map: sourceMap, source: input, generated: raw, str: 'body', - sourcePath: '../integration/sourcemap-sass/style.scss', + sourcePath: 'style.scss', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -590,7 +596,7 @@ describe('sourcemaps', function() { source: input, generated: raw, str: 'color', - sourcePath: '../integration/sourcemap-sass/style.scss', + sourcePath: 'style.scss', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); } @@ -626,23 +632,25 @@ describe('sourcemaps', function() { let raw = (await fs.readFile( path.join(__dirname, '/dist/style.css') )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString(); + let map = JSON.parse( + (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString() + ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + assert(map.sourceRoot == '../integration/sourcemap-sass-imported'); - assert(map.includes('$variable:')); - assert(map.includes('color:')); - - let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + let sourceMap = await new SourceMap().addMap(map); + assert.equal(sourceMap.sources['style.css'], style); + assert.equal(sourceMap.sources['other.scss'], other); checkSourceMapping({ map: sourceMap, source: style, generated: raw, str: 'body', - sourcePath: '../integration/sourcemap-sass-imported/style.css', + sourcePath: 'style.css', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -651,7 +659,7 @@ describe('sourcemaps', function() { source: style, generated: raw, str: 'color', - sourcePath: '../integration/sourcemap-sass-imported/style.css', + sourcePath: 'style.css', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -660,7 +668,7 @@ describe('sourcemaps', function() { source: other, generated: raw, str: 'div', - sourcePath: '../integration/sourcemap-sass-imported/other.scss', + sourcePath: 'other.scss', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -669,7 +677,7 @@ describe('sourcemaps', function() { source: other, generated: raw, str: 'font-family', - sourcePath: '../integration/sourcemap-sass-imported/other.scss', + sourcePath: 'other.scss', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); } @@ -701,22 +709,24 @@ describe('sourcemaps', function() { let raw = (await fs.readFile( path.join(__dirname, '/dist/style.css') )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString(); + let map = JSON.parse( + (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString() + ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + assert(map.sourceRoot == '../integration/sourcemap-less'); - assert(map.includes('@value:')); - - let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + let sourceMap = await new SourceMap().addMap(map); + assert.equal(sourceMap.sources['style.less'], input); checkSourceMapping({ map: sourceMap, source: input, generated: raw, str: 'div', - sourcePath: '../integration/sourcemap-less/style.less', + sourcePath: 'style.less', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -725,7 +735,7 @@ describe('sourcemaps', function() { source: input, generated: raw, str: 'width', - sourcePath: '../integration/sourcemap-less/style.less', + sourcePath: 'style.less', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); } @@ -763,23 +773,25 @@ describe('sourcemaps', function() { let raw = (await fs.readFile( path.join(__dirname, '/dist/style.css') )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString(); + let map = JSON.parse( + (await fs.readFile( + path.join(__dirname, '/dist/style.css.map') + )).toString() + ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); + assert(map.sourceRoot == '../integration/sourcemap-css-existing'); - assert(map.includes('$font-stack:')); - assert(map.includes('display:')); - - let sourceMap = await new SourceMap().addMap(JSON.parse(map)); + let sourceMap = await new SourceMap().addMap(map); + assert.equal(sourceMap.sources['style.css'], style); + assert.equal(sourceMap.sources['library.scss'], library); checkSourceMapping({ map: sourceMap, source: style, generated: raw, str: 'main', - sourcePath: '../integration/sourcemap-css-existing/style.css', + sourcePath: 'style.css', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -788,7 +800,7 @@ describe('sourcemaps', function() { source: style, generated: raw, str: 'display', - sourcePath: '../integration/sourcemap-css-existing/style.css', + sourcePath: 'style.css', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -797,7 +809,7 @@ describe('sourcemaps', function() { source: library, generated: raw, str: 'body', - sourcePath: '../integration/sourcemap-css-existing/library.scss', + sourcePath: 'library.scss', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -807,7 +819,7 @@ describe('sourcemaps', function() { generated: raw, str: 'div', generatedStr: 'body div', - sourcePath: '../integration/sourcemap-css-existing/library.scss', + sourcePath: 'library.scss', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -816,7 +828,7 @@ describe('sourcemaps', function() { source: library, generated: raw, str: 'background-color', - sourcePath: '../integration/sourcemap-css-existing/library.scss', + sourcePath: 'library.scss', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); } diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index a6c0ac80aa2..b79a2c2bb00 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -151,10 +151,13 @@ class CSSAsset extends Asset { let map; if (this.options.sourceMaps) { if (this.sourceMap) { - if (this.sourceMap instanceof SourceMap) { - map = this.sourceMap; - } else { - map = await new SourceMap().addMap(this.sourceMap); + map = this.sourceMap; + if (!(this.sourceMap instanceof SourceMap)) { + if (this.sourceMap.toJSON) { + map = this.sourceMap.toJSON(); + } + + map = await new SourceMap().addMap(map); if (this.sourceMap.toJSON) { // a SourceMapGenerator, PostCSS's sourcemaps contain invalid entries From fd11a128f4cbb152af81e44359181b80bf6aa682 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Mon, 7 Jan 2019 16:48:13 +0100 Subject: [PATCH 21/40] Update CSS sourcemap part on import --- .../test/integration/sourcemap-css-existing/style.css | 2 +- .../sourcemap-css-existing/{ => test}/library.css | 0 .../sourcemap-css-existing/{ => test}/library.css.map | 0 .../sourcemap-css-existing/{ => test}/library.raw.scss | 0 packages/core/integration-tests/test/sourcemaps.js | 10 +++++----- packages/core/parcel-bundler/src/assets/CSSAsset.js | 8 ++++++++ packages/core/parcel-bundler/test/sourcemaps.js | 1 - 7 files changed, 14 insertions(+), 7 deletions(-) rename packages/core/integration-tests/test/integration/sourcemap-css-existing/{ => test}/library.css (100%) rename packages/core/integration-tests/test/integration/sourcemap-css-existing/{ => test}/library.css.map (100%) rename packages/core/integration-tests/test/integration/sourcemap-css-existing/{ => test}/library.raw.scss (100%) diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-existing/style.css b/packages/core/integration-tests/test/integration/sourcemap-css-existing/style.css index 68f1f7062dd..191ad2bf43d 100644 --- a/packages/core/integration-tests/test/integration/sourcemap-css-existing/style.css +++ b/packages/core/integration-tests/test/integration/sourcemap-css-existing/style.css @@ -1,4 +1,4 @@ -@import "./library.css"; +@import "./test/library.css"; main { display: none; diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-existing/library.css b/packages/core/integration-tests/test/integration/sourcemap-css-existing/test/library.css similarity index 100% rename from packages/core/integration-tests/test/integration/sourcemap-css-existing/library.css rename to packages/core/integration-tests/test/integration/sourcemap-css-existing/test/library.css diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-existing/library.css.map b/packages/core/integration-tests/test/integration/sourcemap-css-existing/test/library.css.map similarity index 100% rename from packages/core/integration-tests/test/integration/sourcemap-css-existing/library.css.map rename to packages/core/integration-tests/test/integration/sourcemap-css-existing/test/library.css.map diff --git a/packages/core/integration-tests/test/integration/sourcemap-css-existing/library.raw.scss b/packages/core/integration-tests/test/integration/sourcemap-css-existing/test/library.raw.scss similarity index 100% rename from packages/core/integration-tests/test/integration/sourcemap-css-existing/library.raw.scss rename to packages/core/integration-tests/test/integration/sourcemap-css-existing/test/library.raw.scss diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 5a154099878..662f18f6315 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -767,7 +767,7 @@ describe('sourcemaps', function() { let library = (await fs.readFile( path.join( __dirname, - '/integration/sourcemap-css-existing/library.raw.scss' + '/integration/sourcemap-css-existing/test/library.raw.scss' ) )).toString(); let raw = (await fs.readFile( @@ -784,7 +784,7 @@ describe('sourcemaps', function() { let sourceMap = await new SourceMap().addMap(map); assert.equal(sourceMap.sources['style.css'], style); - assert.equal(sourceMap.sources['library.scss'], library); + assert.equal(sourceMap.sources['test/library.scss'], library); checkSourceMapping({ map: sourceMap, @@ -809,7 +809,7 @@ describe('sourcemaps', function() { source: library, generated: raw, str: 'body', - sourcePath: 'library.scss', + sourcePath: 'test/library.scss', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -819,7 +819,7 @@ describe('sourcemaps', function() { generated: raw, str: 'div', generatedStr: 'body div', - sourcePath: 'library.scss', + sourcePath: 'test/library.scss', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -828,7 +828,7 @@ describe('sourcemaps', function() { source: library, generated: raw, str: 'background-color', - sourcePath: 'library.scss', + sourcePath: 'test/library.scss', msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); } diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index b79a2c2bb00..20ec5ba6cbd 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -5,6 +5,7 @@ const postcssTransform = require('../transforms/postcss'); const CssSyntaxError = require('postcss/lib/css-syntax-error'); const SourceMap = require('../SourceMap'); const loadSourceMap = require('../utils/loadSourceMap'); +const path = require('path'); const URL_RE = /url\s*\("?(?![a-z]+:)/; const IMPORT_RE = /@import/; @@ -176,6 +177,13 @@ class CSSAsset extends Asset { } if (this.previousSourceMap) { + this.previousSourceMap.sources = this.previousSourceMap.sources.map(v => + path.join( + path.dirname(this.relativeName), + this.previousSourceMap.sourceRoot || '', + v + ) + ); if (map) { map = await new SourceMap().extendSourceMap( this.previousSourceMap, diff --git a/packages/core/parcel-bundler/test/sourcemaps.js b/packages/core/parcel-bundler/test/sourcemaps.js index 8e6b41cbea4..075a63415c5 100644 --- a/packages/core/parcel-bundler/test/sourcemaps.js +++ b/packages/core/parcel-bundler/test/sourcemaps.js @@ -1,5 +1,4 @@ const assert = require('assert'); -const fs = require('@parcel/fs'); const SourceMap = require('../src/SourceMap'); describe('sourcemaps', function() { From 25f07f5a6905eb9714ad53b60e8d486623e90fef Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Fri, 11 Jan 2019 08:57:28 +0100 Subject: [PATCH 22/40] Fix emitted sourceMap file property Spec: "An optional name of the *generated* code that this source map is associated with." --- packages/core/parcel-bundler/src/packagers/SourceMapPackager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js b/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js index 69e6b375e55..0d2f545e84d 100644 --- a/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js +++ b/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js @@ -13,7 +13,7 @@ class SourceMapPackager extends Packager { } async end() { - let file = path.basename(this.bundle.name); + let file = path.basename(this.bundle.parentBundle.name); await this.write( this.sourceMap.stringify( From 34251e7044fe0522534d1f68ca9b01466331c5c3 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Fri, 11 Jan 2019 21:17:46 +0100 Subject: [PATCH 23/40] Upgrade postcss to leverage bugfix --- packages/core/parcel-bundler/package.json | 2 +- .../parcel-bundler/src/assets/CSSAsset.js | 45 +++++-------------- .../parcel-bundler/src/transforms/postcss.js | 2 +- yarn.lock | 25 +++++++++++ 4 files changed, 39 insertions(+), 35 deletions(-) diff --git a/packages/core/parcel-bundler/package.json b/packages/core/parcel-bundler/package.json index 5fa76b6ed63..c7eb7aff571 100644 --- a/packages/core/parcel-bundler/package.json +++ b/packages/core/parcel-bundler/package.json @@ -58,7 +58,7 @@ "node-forge": "^0.7.1", "node-libs-browser": "^2.0.0", "opn": "^5.1.0", - "postcss": "^7.0.5", + "postcss": "^7.0.11", "postcss-value-parser": "^3.3.1", "posthtml": "^0.11.2", "posthtml-parser": "^0.4.0", diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 20ec5ba6cbd..24aba4d1b6d 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -149,31 +149,9 @@ class CSSAsset extends Asset { 'module.exports = ' + JSON.stringify(this.cssModules, null, 2) + ';'; } - let map; if (this.options.sourceMaps) { if (this.sourceMap) { - map = this.sourceMap; - if (!(this.sourceMap instanceof SourceMap)) { - if (this.sourceMap.toJSON) { - map = this.sourceMap.toJSON(); - } - - map = await new SourceMap().addMap(map); - - if (this.sourceMap.toJSON) { - // a SourceMapGenerator, PostCSS's sourcemaps contain invalid entries - let sourceLines = {}; - for (let [path, content] of Object.entries(map.sources)) { - sourceLines[path] = content.split('\n'); - } - - map.mappings = map.mappings.filter( - ({source, original: {line, column}}) => - line - 1 < sourceLines[source].length && - column < sourceLines[source][line - 1].length - ); - } - } + this.sourceMap = await new SourceMap().addMap(this.sourceMap); } if (this.previousSourceMap) { @@ -184,18 +162,19 @@ class CSSAsset extends Asset { v ) ); - if (map) { - map = await new SourceMap().extendSourceMap( + if (this.sourceMap) { + this.sourceMap = await new SourceMap().extendSourceMap( this.previousSourceMap, - map + this.sourceMap ); } else { - map = await new SourceMap().addMap(this.previousSourceMap); + this.sourceMap = await new SourceMap().addMap(this.previousSourceMap); } - } - - if (!map) { - map = new SourceMap().generateEmptyMap(this.relativeName, css); + } else if (!this.sourceMap) { + this.sourceMap = new SourceMap().generateEmptyMap( + this.relativeName, + css + ); } } @@ -212,7 +191,7 @@ class CSSAsset extends Asset { }, { type: 'map', - value: map + value: this.sourceMap } ]; } @@ -261,7 +240,7 @@ class CSSAst { return { css: this.css, - map + map: map ? map.toJSON() : null }; } diff --git a/packages/core/parcel-bundler/src/transforms/postcss.js b/packages/core/parcel-bundler/src/transforms/postcss.js index f34b74da9d9..ddc39a61c9e 100644 --- a/packages/core/parcel-bundler/src/transforms/postcss.js +++ b/packages/core/parcel-bundler/src/transforms/postcss.js @@ -14,7 +14,7 @@ module.exports = async function(asset) { asset.ast.css = res.css; asset.ast.dirty = false; - asset.sourceMap = res.map; + asset.sourceMap = res.map ? res.map.toJSON() : null; }; async function getConfig(asset) { diff --git a/yarn.lock b/yarn.lock index a848cd60b05..bbe3f5336dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2719,6 +2719,15 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + character-parser@^2.1.1: version "2.2.0" resolved "https://registry.yarnpkg.com/character-parser/-/character-parser-2.2.0.tgz#c7ce28f36d4bcd9744e5ffc2c5fcde1c73261fc0" @@ -8320,6 +8329,15 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.2, postcss@^7.0.5: source-map "^0.6.1" supports-color "^5.5.0" +postcss@^7.0.11: + version "7.0.11" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.11.tgz#f63c513b78026d66263bb2ca995bf02e3d1a697d" + integrity sha512-9AXb//5UcjeOEof9T+yPw3XTa5SL207ZOIC/lHYP4mbUTEh4M0rDAQekQpVANCZdwQwKhBtFZCk3i3h3h2hdWg== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + posthtml-extend@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/posthtml-extend/-/posthtml-extend-0.2.1.tgz#d023ce7ce4dd6071071b50e315dfefa87da8a979" @@ -9878,6 +9896,13 @@ supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0: dependencies: has-flag "^3.0.0" +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + svgo@^1.0.0, svgo@^1.0.5: version "1.1.1" resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.1.1.tgz#12384b03335bcecd85cfa5f4e3375fed671cb985" From 3b71860713139a4f908d80f5d613097edc99f8e6 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Wed, 16 Jan 2019 23:59:20 +0100 Subject: [PATCH 24/40] Sourcemaps for multiple asset types (WIP) --- packages/core/parcel-bundler/src/Bundle.js | 8 +++++++- packages/core/parcel-bundler/src/Bundler.js | 1 + packages/core/parcel-bundler/src/Pipeline.js | 1 + packages/core/parcel-bundler/src/assets/CSSAsset.js | 11 +++++------ packages/core/parcel-bundler/src/assets/JSAsset.js | 12 +++++++++--- .../src/packagers/SourceMapPackager.js | 8 +++++++- .../core/parcel-bundler/src/transforms/terser.js | 2 +- 7 files changed, 31 insertions(+), 12 deletions(-) diff --git a/packages/core/parcel-bundler/src/Bundle.js b/packages/core/parcel-bundler/src/Bundle.js index 549092c43a5..64a1b41299b 100644 --- a/packages/core/parcel-bundler/src/Bundle.js +++ b/packages/core/parcel-bundler/src/Bundle.js @@ -39,6 +39,8 @@ class Bundle { addAsset(asset) { asset.bundles.add(this); this.assets.add(asset); + if (this.type != 'map' && asset.sourceMaps) + this.getSiblingBundle('map').addAsset(asset); } removeAsset(asset) { @@ -126,7 +128,11 @@ class Bundle { ? this.getHash() : Path.basename(this.name, ext) ).slice(-8); - let entryAsset = this.entryAsset || this.parentBundle.entryAsset; + let entryAsset = this; + while (entryAsset.entryAsset == null) { + entryAsset = entryAsset.parentBundle; + } + entryAsset = entryAsset.entryAsset; let name = Path.basename(entryAsset.name, Path.extname(entryAsset.name)); let isMainEntry = entryAsset.options.entryFiles[0] === entryAsset.name; let isEntry = diff --git a/packages/core/parcel-bundler/src/Bundler.js b/packages/core/parcel-bundler/src/Bundler.js index 98238faa5a2..d46ceb7d405 100644 --- a/packages/core/parcel-bundler/src/Bundler.js +++ b/packages/core/parcel-bundler/src/Bundler.js @@ -561,6 +561,7 @@ class Bundler extends EventEmitter { asset.buildTime = asset.endTime - asset.startTime; asset.id = processed.id; asset.generated = processed.generated; + asset.sourceMaps = processed.sourceMaps; asset.hash = processed.hash; asset.cacheData = processed.cacheData; diff --git a/packages/core/parcel-bundler/src/Pipeline.js b/packages/core/parcel-bundler/src/Pipeline.js index e076fa90f81..0294b803f3f 100644 --- a/packages/core/parcel-bundler/src/Pipeline.js +++ b/packages/core/parcel-bundler/src/Pipeline.js @@ -34,6 +34,7 @@ class Pipeline { id: asset.id, dependencies: Array.from(asset.dependencies.values()), generated: generatedMap, + sourceMaps: asset.sourceMaps, error: error, hash: asset.hash, cacheData: asset.cacheData diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 24aba4d1b6d..80238c99d84 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -178,20 +178,19 @@ class CSSAsset extends Asset { } } + this.sourceMaps = { + css: this.sourceMap + }; + return [ { type: 'css', - value: css, - cssModules: this.cssModules + value: css }, { type: 'js', value: js, hasDependencies: false - }, - { - type: 'map', - value: this.sourceMap } ]; } diff --git a/packages/core/parcel-bundler/src/assets/JSAsset.js b/packages/core/parcel-bundler/src/assets/JSAsset.js index 11cf1f90860..5066c7c76a3 100644 --- a/packages/core/parcel-bundler/src/assets/JSAsset.js +++ b/packages/core/parcel-bundler/src/assets/JSAsset.js @@ -187,10 +187,16 @@ class JSAsset extends Asset { } } - return { - js: code, - map: this.sourceMap + this.sourceMaps = { + js: this.sourceMap }; + + return [ + { + type: 'js', + value: code + } + ]; } generateErrorMessage(err) { diff --git a/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js b/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js index 0d2f545e84d..063eedea2f1 100644 --- a/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js +++ b/packages/core/parcel-bundler/src/packagers/SourceMapPackager.js @@ -9,7 +9,13 @@ class SourceMapPackager extends Packager { async addAsset(asset) { let offsets = this.bundle.parentBundle.getOffset(asset); - await this.sourceMap.addMap(asset.generated.map, offsets[0], offsets[1]); + if (asset.sourceMaps[asset.type]) { + await this.sourceMap.addMap( + asset.sourceMaps[asset.type], + offsets[0], + offsets[1] + ); + } } async end() { diff --git a/packages/core/parcel-bundler/src/transforms/terser.js b/packages/core/parcel-bundler/src/transforms/terser.js index 75249dd2e58..64f9e38e8b3 100644 --- a/packages/core/parcel-bundler/src/transforms/terser.js +++ b/packages/core/parcel-bundler/src/transforms/terser.js @@ -5,7 +5,7 @@ module.exports = async function(asset) { await asset.parseIfNeeded(); // Convert AST into JS - let source = (await asset.generate()).js; + let source = (await asset.generate())[0].value; let customConfig = await asset.getConfig(['.uglifyrc', '.terserrc']); let options = { From 0bd315bc159b635f33daca33843be8c0364b565a Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Thu, 17 Jan 2019 23:51:06 +0100 Subject: [PATCH 25/40] Cleanup --- packages/core/parcel-bundler/src/Asset.js | 13 +++++++++++++ packages/core/parcel-bundler/src/Bundle.js | 5 +++-- packages/core/parcel-bundler/src/assets/CSSAsset.js | 7 ++----- .../core/parcel-bundler/src/assets/HTMLAsset.js | 2 ++ packages/core/parcel-bundler/src/assets/JSAsset.js | 9 +++------ .../parcel-bundler/src/assets/TypeScriptAsset.js | 2 +- packages/core/parcel-bundler/src/assets/VueAsset.js | 1 + 7 files changed, 25 insertions(+), 14 deletions(-) diff --git a/packages/core/parcel-bundler/src/Asset.js b/packages/core/parcel-bundler/src/Asset.js index 92b443a021b..8b8fbaeda76 100644 --- a/packages/core/parcel-bundler/src/Asset.js +++ b/packages/core/parcel-bundler/src/Asset.js @@ -212,6 +212,19 @@ class Asset { } async postProcess(generated) { + let hasMap = false; + let sourceMaps = {}; + for (let rendition of generated) { + if (rendition.map && rendition.type == this.type) { + sourceMaps[rendition.type] = rendition.map; + hasMap = true; + } + } + + if (hasMap) { + this.sourceMaps = sourceMaps; + } + return generated; } diff --git a/packages/core/parcel-bundler/src/Bundle.js b/packages/core/parcel-bundler/src/Bundle.js index 64a1b41299b..3bd5448b285 100644 --- a/packages/core/parcel-bundler/src/Bundle.js +++ b/packages/core/parcel-bundler/src/Bundle.js @@ -39,8 +39,9 @@ class Bundle { addAsset(asset) { asset.bundles.add(this); this.assets.add(asset); - if (this.type != 'map' && asset.sourceMaps) + if (this.type != 'map' && asset.sourceMaps) { this.getSiblingBundle('map').addAsset(asset); + } } removeAsset(asset) { @@ -129,7 +130,7 @@ class Bundle { : Path.basename(this.name, ext) ).slice(-8); let entryAsset = this; - while (entryAsset.entryAsset == null) { + while (!entryAsset.entryAsset && entryAsset.parentBundle) { entryAsset = entryAsset.parentBundle; } entryAsset = entryAsset.entryAsset; diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 80238c99d84..910f9f3143b 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -178,14 +178,11 @@ class CSSAsset extends Asset { } } - this.sourceMaps = { - css: this.sourceMap - }; - return [ { type: 'css', - value: css + value: css, + map: this.sourceMap }, { type: 'js', diff --git a/packages/core/parcel-bundler/src/assets/HTMLAsset.js b/packages/core/parcel-bundler/src/assets/HTMLAsset.js index e2646c7fbee..4143a0bd31d 100644 --- a/packages/core/parcel-bundler/src/assets/HTMLAsset.js +++ b/packages/core/parcel-bundler/src/assets/HTMLAsset.js @@ -262,6 +262,8 @@ class HTMLAsset extends Asset { } async postProcess(generated) { + generated = await super.postProcess(generated); + // Replace inline scripts and styles with processed results. for (let rendition of generated) { let {type, node} = rendition.meta; diff --git a/packages/core/parcel-bundler/src/assets/JSAsset.js b/packages/core/parcel-bundler/src/assets/JSAsset.js index 5066c7c76a3..556382e529a 100644 --- a/packages/core/parcel-bundler/src/assets/JSAsset.js +++ b/packages/core/parcel-bundler/src/assets/JSAsset.js @@ -79,7 +79,7 @@ class JSAsset extends Asset { } async pretransform() { - if (this.options.sourceMaps) { + if (this.options.sourceMaps && !this.sourceMap) { this.sourceMap = await loadSourceMap(this); } @@ -187,14 +187,11 @@ class JSAsset extends Asset { } } - this.sourceMaps = { - js: this.sourceMap - }; - return [ { type: 'js', - value: code + value: code, + map: this.sourceMap } ]; } diff --git a/packages/core/parcel-bundler/src/assets/TypeScriptAsset.js b/packages/core/parcel-bundler/src/assets/TypeScriptAsset.js index 715a8ea94c2..7e6795e9914 100644 --- a/packages/core/parcel-bundler/src/assets/TypeScriptAsset.js +++ b/packages/core/parcel-bundler/src/assets/TypeScriptAsset.js @@ -60,7 +60,7 @@ class TypeScriptAsset extends Asset { { type: 'js', value: transpiled.outputText, - sourceMap + map: sourceMap } ]; } diff --git a/packages/core/parcel-bundler/src/assets/VueAsset.js b/packages/core/parcel-bundler/src/assets/VueAsset.js index 2214c08bc7d..4f3ae9ecb90 100644 --- a/packages/core/parcel-bundler/src/assets/VueAsset.js +++ b/packages/core/parcel-bundler/src/assets/VueAsset.js @@ -59,6 +59,7 @@ class VueAsset extends Asset { } async postProcess(generated) { + generated = await super.postProcess(generated); let result = []; let hasScoped = this.ast.styles.some(s => s.scoped); From 95a2b82707753b6c5ef9dd20ca8c4960ba35ffa7 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Wed, 30 Jan 2019 19:01:30 +0100 Subject: [PATCH 26/40] Put sourcemaps into correct bundle only, make tests pass --- packages/core/integration-tests/test/css.js | 44 ++++++++++++++--- packages/core/integration-tests/test/glob.js | 6 ++- packages/core/integration-tests/test/html.js | 30 +++++++++--- packages/core/integration-tests/test/less.js | 42 +++++++++++++--- packages/core/integration-tests/test/sass.js | 49 ++++++++++++++++--- .../core/integration-tests/test/sourcemaps.js | 11 +++++ .../core/integration-tests/test/stylus.js | 30 ++++++++++-- packages/core/parcel-bundler/src/Bundle.js | 7 ++- .../core/parcel-bundler/src/assets/JSAsset.js | 2 +- 9 files changed, 183 insertions(+), 38 deletions(-) diff --git a/packages/core/integration-tests/test/css.js b/packages/core/integration-tests/test/css.js index c022343cac8..613b27a158c 100644 --- a/packages/core/integration-tests/test/css.js +++ b/packages/core/integration-tests/test/css.js @@ -17,7 +17,11 @@ describe('css', function() { { name: 'index.css', assets: ['index.css', 'local.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -46,7 +50,11 @@ describe('css', function() { { name: 'index.css', assets: ['index.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' @@ -58,7 +66,11 @@ describe('css', function() { { type: 'css', assets: ['local.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' @@ -85,7 +97,11 @@ describe('css', function() { { name: 'index.css', assets: ['index.css', 'other.css', 'local.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { name: 'index.js.map', @@ -118,7 +134,11 @@ describe('css', function() { { name: 'index.css', assets: ['index.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' @@ -173,7 +193,11 @@ describe('css', function() { { name: 'index.css', assets: ['index.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' @@ -271,7 +295,11 @@ describe('css', function() { { name: 'index.css', assets: ['index.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' @@ -325,7 +353,7 @@ describe('css', function() { ); assert(css.includes('.local')); assert(css.includes('.index')); - assert(!css.includes('\n')); + assert.equal(css.split('\n').length, 2); // sourceMappingURL }); it('should automatically install postcss plugins with npm if needed', async function() { diff --git a/packages/core/integration-tests/test/glob.js b/packages/core/integration-tests/test/glob.js index 9663d7be4b6..f1697324893 100644 --- a/packages/core/integration-tests/test/glob.js +++ b/packages/core/integration-tests/test/glob.js @@ -54,7 +54,11 @@ describe('glob', function() { { name: 'index.css', assets: ['index.css', 'other.css', 'local.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' diff --git a/packages/core/integration-tests/test/html.js b/packages/core/integration-tests/test/html.js index 1dedb145908..c9dac054d9a 100644 --- a/packages/core/integration-tests/test/html.js +++ b/packages/core/integration-tests/test/html.js @@ -155,7 +155,11 @@ describe('html', function() { { type: 'css', assets: ['index.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' @@ -189,7 +193,11 @@ describe('html', function() { { type: 'css', assets: ['index.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' @@ -223,6 +231,9 @@ describe('html', function() { type: 'css', assets: ['index.css'], childBundles: [ + { + type: 'map' + }, { type: 'js', assets: [ @@ -231,10 +242,11 @@ describe('html', function() { 'css-loader.js', 'hmr-runtime.js' ], - childBundles: [] - }, - { - type: 'map' + childBundles: [ + { + type: 'map' + } + ] } ] } @@ -261,7 +273,11 @@ describe('html', function() { { type: 'css', assets: ['index.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' diff --git a/packages/core/integration-tests/test/less.js b/packages/core/integration-tests/test/less.js index da522dd66d0..dc79376182a 100644 --- a/packages/core/integration-tests/test/less.js +++ b/packages/core/integration-tests/test/less.js @@ -17,7 +17,11 @@ describe('less', function() { { name: 'index.css', assets: ['index.less'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -48,7 +52,11 @@ describe('less', function() { { name: 'index.css', assets: ['index.less'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -80,7 +88,11 @@ describe('less', function() { { name: 'index.css', assets: ['index.less'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -112,7 +124,11 @@ describe('less', function() { { name: 'index.css', assets: ['index.less'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -125,7 +141,11 @@ describe('less', function() { path.join(__dirname, '/dist/index.css'), 'utf8' ); - assert.equal(css, ''); + assert( + /^\/\*# sourceMappingURL=\/\w*\.css\.map \*\/$/.test( + css.replace('\n', '') + ) + ); }); it('should support linking to assets with url() from less', async function() { @@ -143,7 +163,11 @@ describe('less', function() { { name: 'index.css', assets: ['index.less'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'woff2', @@ -191,7 +215,11 @@ describe('less', function() { { name: 'index.css', assets: ['index.less'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); diff --git a/packages/core/integration-tests/test/sass.js b/packages/core/integration-tests/test/sass.js index 5febcbd0e64..258ce6c0d07 100644 --- a/packages/core/integration-tests/test/sass.js +++ b/packages/core/integration-tests/test/sass.js @@ -17,7 +17,11 @@ describe('sass', function() { { name: 'index.css', assets: ['index.sass'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -46,7 +50,11 @@ describe('sass', function() { { name: 'index.css', assets: ['index.scss'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -77,7 +85,11 @@ describe('sass', function() { { name: 'index.css', assets: ['index.scss'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -110,7 +122,11 @@ describe('sass', function() { { name: 'index.css', assets: ['index.scss'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -123,7 +139,11 @@ describe('sass', function() { path.join(__dirname, '/dist/index.css'), 'utf8' ); - assert.equal(css, ''); + assert( + /^\/\*# sourceMappingURL=\/\w*\.css\.map \*\/$/.test( + css.replace('\n', '') + ) + ); }); it('should support linking to assets with url() from scss', async function() { @@ -146,7 +166,11 @@ describe('sass', function() { { name: 'index.css', assets: ['index.scss'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'woff2', @@ -194,7 +218,11 @@ describe('sass', function() { { name: 'index.css', assets: ['index.scss'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -218,7 +246,12 @@ describe('sass', function() { await assertBundleTree(b, { name: 'index.css', - assets: ['index.sass'] + assets: ['index.sass'], + childBundles: [ + { + type: 'map' + } + ] }); let css = (await fs.readFile( diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 662f18f6315..0f9bf7ffeb1 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -106,6 +106,7 @@ describe('sourcemaps', function() { ), 'combining sourceRoot and sources object should resolve to the original file' ); + assert.equal(mapObject.sources.length, 1); let output = await run(bu); assert.equal(typeof output, 'function'); @@ -134,6 +135,7 @@ describe('sourcemaps', function() { let map = (await fs.readFile( path.join(__dirname, '/dist/index.js.map') )).toString(); + assert.equal(JSON.parse(map).sources.length, 1); mapValidator(raw, map); let output = await run(b); @@ -163,6 +165,7 @@ describe('sourcemaps', function() { let map = (await fs.readFile( path.join(__dirname, '/dist/index.js.map') )).toString(); + assert.equal(JSON.parse(map).sources.length, 2); mapValidator(raw, map); let output = await run(b); @@ -224,6 +227,7 @@ describe('sourcemaps', function() { let map = (await fs.readFile( path.join(__dirname, '/dist/index.js.map') )).toString(); + assert.equal(JSON.parse(map).sources.length, 3); mapValidator(raw, map); let output = await run(b); @@ -267,6 +271,7 @@ describe('sourcemaps', function() { ); let map = (await fs.readFile(path.join(sourcemapReference))).toString(); + assert.equal(JSON.parse(map).sources.length, 2); mapValidator(jsOutput, map); }); @@ -412,6 +417,7 @@ describe('sourcemaps', function() { assert(map.sourceRoot == '../integration/sourcemap-css'); let sourceMap = await new SourceMap().addMap(map); + assert.equal(Object.keys(sourceMap.sources).length, 1); assert.equal(sourceMap.sources['style.css'], input); checkSourceMapping({ @@ -483,6 +489,7 @@ describe('sourcemaps', function() { assert(map.sourceRoot == '../integration/sourcemap-css-import'); let sourceMap = await new SourceMap().addMap(map); + assert.equal(Object.keys(sourceMap.sources).length, 3); assert.equal(sourceMap.sources['style.css'], style); assert.equal(sourceMap.sources['other-style.css'], otherStyle); assert.equal(sourceMap.sources['another-style.css'], anotherStyle); @@ -580,6 +587,7 @@ describe('sourcemaps', function() { assert(map.sourceRoot == '../integration/sourcemap-sass'); let sourceMap = await new SourceMap().addMap(map); + assert.equal(Object.keys(sourceMap.sources).length, 1); assert.equal(sourceMap.sources['style.scss'], input); checkSourceMapping({ @@ -642,6 +650,7 @@ describe('sourcemaps', function() { assert(map.sourceRoot == '../integration/sourcemap-sass-imported'); let sourceMap = await new SourceMap().addMap(map); + assert.equal(Object.keys(sourceMap.sources).length, 2); assert.equal(sourceMap.sources['style.css'], style); assert.equal(sourceMap.sources['other.scss'], other); @@ -719,6 +728,7 @@ describe('sourcemaps', function() { assert(map.sourceRoot == '../integration/sourcemap-less'); let sourceMap = await new SourceMap().addMap(map); + assert.equal(Object.keys(sourceMap.sources).length, 1); assert.equal(sourceMap.sources['style.less'], input); checkSourceMapping({ @@ -783,6 +793,7 @@ describe('sourcemaps', function() { assert(map.sourceRoot == '../integration/sourcemap-css-existing'); let sourceMap = await new SourceMap().addMap(map); + assert.equal(Object.keys(sourceMap.sources).length, 2); assert.equal(sourceMap.sources['style.css'], style); assert.equal(sourceMap.sources['test/library.scss'], library); diff --git a/packages/core/integration-tests/test/stylus.js b/packages/core/integration-tests/test/stylus.js index 40458ed46ed..fe572036f91 100644 --- a/packages/core/integration-tests/test/stylus.js +++ b/packages/core/integration-tests/test/stylus.js @@ -17,7 +17,11 @@ describe('stylus', function() { { name: 'index.css', assets: ['index.styl'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -50,7 +54,11 @@ describe('stylus', function() { { name: 'index.css', assets: ['index.styl'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -84,7 +92,11 @@ describe('stylus', function() { { name: 'index.css', assets: ['index.styl'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'woff2', @@ -132,7 +144,11 @@ describe('stylus', function() { { name: 'index.css', assets: ['index.styl'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); @@ -163,7 +179,11 @@ describe('stylus', function() { { name: 'index.css', assets: ['index.styl'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] } ] }); diff --git a/packages/core/parcel-bundler/src/Bundle.js b/packages/core/parcel-bundler/src/Bundle.js index 3bd5448b285..16d44aeed87 100644 --- a/packages/core/parcel-bundler/src/Bundle.js +++ b/packages/core/parcel-bundler/src/Bundle.js @@ -39,7 +39,12 @@ class Bundle { addAsset(asset) { asset.bundles.add(this); this.assets.add(asset); - if (this.type != 'map' && asset.sourceMaps) { + if ( + this.type != 'map' && + this.type == asset.type && + asset.options.sourceMaps && + asset.sourceMaps + ) { this.getSiblingBundle('map').addAsset(asset); } } diff --git a/packages/core/parcel-bundler/src/assets/JSAsset.js b/packages/core/parcel-bundler/src/assets/JSAsset.js index 556382e529a..56d400f65d3 100644 --- a/packages/core/parcel-bundler/src/assets/JSAsset.js +++ b/packages/core/parcel-bundler/src/assets/JSAsset.js @@ -32,7 +32,7 @@ class JSAsset extends Asset { this.outputCode = null; this.cacheData.env = {}; this.rendition = options.rendition; - this.sourceMap = this.rendition ? this.rendition.sourceMap : null; + this.sourceMap = this.rendition ? this.rendition.map : null; } shouldInvalidate(cacheData) { From 3db7f8337934958990f194c19fa0aac589f1af23 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Wed, 30 Jan 2019 21:21:11 +0100 Subject: [PATCH 27/40] Cleanup css packaging --- .../src/packagers/CSSPackager.js | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/core/parcel-bundler/src/packagers/CSSPackager.js b/packages/core/parcel-bundler/src/packagers/CSSPackager.js index 558fed375e6..ec2f5c6c8e1 100644 --- a/packages/core/parcel-bundler/src/packagers/CSSPackager.js +++ b/packages/core/parcel-bundler/src/packagers/CSSPackager.js @@ -30,17 +30,28 @@ class CSSPackager extends Packager { css = `@media ${media.join(', ')} {\n${css.trim()}\n}\n`; } - let lineCount = lineCounter(css) - 1; + if (asset.options.sourceMaps) { + let lineCount = lineCounter(css); - if (lineCount == 0) { - this.bundle.addOffset(asset, this.lineOffset, this.columnOffset); - await this.write(css); - this.columnOffset += css.length; + if (lineCount == 1) { + this.bundle.addOffset(asset, this.lineOffset, this.columnOffset); + await this.write(css); + this.columnOffset += css.length; + } else { + const lines = css.split('\n'); + if (this.columnOffset == 0) { + this.bundle.addOffset(asset, this.lineOffset, 0); + await this.write(css + '\n'); + } else { + this.columnOffset = 0; + this.bundle.addOffset(asset, this.lineOffset + 1, 0); + this.columnOffset = lines[lines.length - 1].length; + await this.write('\n' + css); + } + this.lineOffset += lineCount; + } } else { - this.bundle.addOffset(asset, this.lineOffset + 1, this.columnOffset); - await this.write('\n' + css); - this.columnOffset = 0; - this.lineOffset += lineCounter(css); + await this.write(css); } } From 50a436cf09c51f8c917153af82365cf0629a1c96 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Wed, 30 Jan 2019 21:43:07 +0100 Subject: [PATCH 28/40] Unbreak Vue + CSS modules --- packages/core/parcel-bundler/src/assets/CSSAsset.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/parcel-bundler/src/assets/CSSAsset.js b/packages/core/parcel-bundler/src/assets/CSSAsset.js index 910f9f3143b..80965c87aca 100644 --- a/packages/core/parcel-bundler/src/assets/CSSAsset.js +++ b/packages/core/parcel-bundler/src/assets/CSSAsset.js @@ -182,6 +182,7 @@ class CSSAsset extends Asset { { type: 'css', value: css, + cssModules: this.cssModules, map: this.sourceMap }, { From f840ac785bfdcd17b2dbf0de3886e7b8804a8803 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Thu, 31 Jan 2019 23:46:21 +0100 Subject: [PATCH 29/40] Fix tests on Node 6 --- packages/core/integration-tests/test/sourcemaps.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 0f9bf7ffeb1..f75d4dfd11f 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -2,7 +2,10 @@ const assert = require('assert'); const fs = require('@parcel/fs'); const path = require('path'); const mapValidator = require('sourcemap-validator'); -const SourceMap = require('parcel-bundler/src/SourceMap'); +const SourceMap = + parseInt(process.versions.node, 10) < 8 + ? require('parcel-bundler/lib/SourceMap') + : require('parcel-bundler/src/SourceMap'); const {bundler, bundle, run, assertBundleTree} = require('./utils'); function indexToLineCol(str, index) { From 7a25eb596cd52ba81f9ffab8e5bd15b2faf98280 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Thu, 14 Feb 2019 21:56:50 +0100 Subject: [PATCH 30/40] Make Sourcemap bundles have same hash as parent bundle --- packages/core/parcel-bundler/src/Bundle.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/core/parcel-bundler/src/Bundle.js b/packages/core/parcel-bundler/src/Bundle.js index 16d44aeed87..478693c3030 100644 --- a/packages/core/parcel-bundler/src/Bundle.js +++ b/packages/core/parcel-bundler/src/Bundle.js @@ -122,14 +122,14 @@ class Bundle { getHashedBundleName(contentHash) { // If content hashing is enabled, generate a hash from all assets in the bundle. // Otherwise, use a hash of the filename so it remains consistent across builds. + + if (this.type == 'map') { + return this.parentBundle.getHashedBundleName(contentHash) + '.map'; + } + let basename = Path.basename(this.name); let ext = Path.extname(basename); - if (this.type === 'map') { - // Using this instead of Path.extname because the source map files have long - // extensions like '.js.map' but extname only return the last piece (.map). - ext = basename.substring(basename.indexOf('.')); - } let hash = (contentHash ? this.getHash() : Path.basename(this.name, ext) From 1245c9518ab19254de7967bc3f21cfd793b045e9 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Thu, 14 Feb 2019 22:04:29 +0100 Subject: [PATCH 31/40] Test --- packages/core/integration-tests/test/html.js | 2 +- packages/core/test-utils/src/utils.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core/integration-tests/test/html.js b/packages/core/integration-tests/test/html.js index 7b4dde1bcee..523a6b1219d 100644 --- a/packages/core/integration-tests/test/html.js +++ b/packages/core/integration-tests/test/html.js @@ -215,7 +215,7 @@ describe('html', function() { ); }); - it('should insert sibling JS bundles for CSS files in the HEAD', async function() { + it.only('should insert sibling JS bundles for CSS files in the HEAD', async function() { let b = await bundle( path.join(__dirname, '/integration/html-css-js/index.html'), { diff --git a/packages/core/test-utils/src/utils.js b/packages/core/test-utils/src/utils.js index 10a8cd1649f..22fbbac5e77 100644 --- a/packages/core/test-utils/src/utils.js +++ b/packages/core/test-utils/src/utils.js @@ -141,6 +141,7 @@ async function assertBundleTree(bundle, tree) { ? -1 : 1 ); + console.log(children.map(b => path.basename(b.name))); assert.equal( bundle.childBundles.size, childBundles.length, From 00f82aa1d107c9286bbbe97d155a607ca0c29f17 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sat, 16 Feb 2019 20:57:41 +0100 Subject: [PATCH 32/40] Make integration-test childBundles order stable --- packages/core/integration-tests/test/css.js | 17 ++++++------ packages/core/integration-tests/test/html.js | 8 +++--- packages/core/integration-tests/test/vue.js | 28 ++++++++++---------- packages/core/test-utils/src/utils.js | 19 +++++++------ 4 files changed, 38 insertions(+), 34 deletions(-) diff --git a/packages/core/integration-tests/test/css.js b/packages/core/integration-tests/test/css.js index 56edd47b410..3ac0058ee9d 100644 --- a/packages/core/integration-tests/test/css.js +++ b/packages/core/integration-tests/test/css.js @@ -17,9 +17,6 @@ describe('css', function() { name: 'index.js', assets: ['index.js', 'index.css', 'local.js', 'local.css'], childBundles: [ - { - name: 'index.js.map' - }, { name: 'index.css', assets: ['index.css', 'local.css'], @@ -28,6 +25,9 @@ describe('css', function() { type: 'map' } ] + }, + { + name: 'index.js.map' } ] }); @@ -54,20 +54,18 @@ describe('css', function() { ], childBundles: [ { + type: 'css', name: 'index.css', assets: ['index.css'], childBundles: [ { - type: 'map' + name: 'index.css.map' } ] }, - { - type: 'map' - }, { type: 'js', - assets: ['local.js', 'local.css'], + assets: ['local.css', 'local.js'], childBundles: [ { type: 'css', @@ -82,6 +80,9 @@ describe('css', function() { type: 'map' } ] + }, + { + name: 'index.js.map' } ] }); diff --git a/packages/core/integration-tests/test/html.js b/packages/core/integration-tests/test/html.js index 523a6b1219d..30921296ef8 100644 --- a/packages/core/integration-tests/test/html.js +++ b/packages/core/integration-tests/test/html.js @@ -215,7 +215,7 @@ describe('html', function() { ); }); - it.only('should insert sibling JS bundles for CSS files in the HEAD', async function() { + it('should insert sibling JS bundles for CSS files in the HEAD', async function() { let b = await bundle( path.join(__dirname, '/integration/html-css-js/index.html'), { @@ -231,9 +231,6 @@ describe('html', function() { type: 'css', assets: ['index.css'], childBundles: [ - { - type: 'map' - }, { type: 'js', assets: [ @@ -247,6 +244,9 @@ describe('html', function() { type: 'map' } ] + }, + { + type: 'map' } ] } diff --git a/packages/core/integration-tests/test/vue.js b/packages/core/integration-tests/test/vue.js index c337cfc34e1..b27c5a7b4ea 100644 --- a/packages/core/integration-tests/test/vue.js +++ b/packages/core/integration-tests/test/vue.js @@ -14,10 +14,10 @@ describe('vue', function() { assets: ['Basic.vue'], childBundles: [ { - type: 'map' + type: 'css' }, { - type: 'css' + type: 'map' } ] }); @@ -39,10 +39,10 @@ describe('vue', function() { assets: ['App.vue'], childBundles: [ { - type: 'map' + type: 'css' }, { - type: 'css' + type: 'map' }, { assets: ['logo.png'], @@ -67,10 +67,10 @@ describe('vue', function() { assets: ['pre-processors.vue'], childBundles: [ { - type: 'map' + type: 'css' }, { - type: 'css' + type: 'map' } ] }); @@ -131,10 +131,10 @@ describe('vue', function() { assets: ['App.vue'], childBundles: [ { - type: 'map' + type: 'css' }, { - type: 'css' + type: 'map' } ] }); @@ -162,10 +162,10 @@ describe('vue', function() { assets: ['App.vue'], childBundles: [ { - type: 'map' + type: 'css' }, { - type: 'css' + type: 'map' } ] }); @@ -207,10 +207,10 @@ describe('vue', function() { assets: ['insidecomp.vue'], childBundles: [ { - type: 'map' + type: 'css' }, { - type: 'css' + type: 'map' } ] }, @@ -241,10 +241,10 @@ describe('vue', function() { assets: ['Basic.vue'], childBundles: [ { - type: 'map' + type: 'css' }, { - type: 'css' + type: 'map' } ] }); diff --git a/packages/core/test-utils/src/utils.js b/packages/core/test-utils/src/utils.js index 22fbbac5e77..cd197a93abb 100644 --- a/packages/core/test-utils/src/utils.js +++ b/packages/core/test-utils/src/utils.js @@ -134,14 +134,17 @@ async function assertBundleTree(bundle, tree) { let childBundles = Array.isArray(tree) ? tree : tree.childBundles; if (childBundles) { - let children = Array.from(bundle.childBundles).sort( - (a, b) => - Array.from(a.assets).sort()[0].basename < - Array.from(b.assets).sort()[0].basename - ? -1 - : 1 - ); - console.log(children.map(b => path.basename(b.name))); + let children = Array.from(bundle.childBundles).sort((a, b) => { + let assetA = Array.from(a.assets).sort()[0]; + let assetB = Array.from(a.assets).sort()[0]; + if (assetA.basename < assetB.basename) { + return -1; + } else if (assetA.basename > assetB.basename) { + return 1; + } else { + return a.type < b.type ? -1 : 1; + } + }); assert.equal( bundle.childBundles.size, childBundles.length, From d0c9be1b8f5a05591d44af38e2200955d4ae322f Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sat, 16 Feb 2019 21:32:14 +0100 Subject: [PATCH 33/40] Whoops, fixup --- packages/core/integration-tests/test/css.js | 14 +++++++------- packages/core/test-utils/src/utils.js | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/core/integration-tests/test/css.js b/packages/core/integration-tests/test/css.js index 3ac0058ee9d..0887488ea41 100644 --- a/packages/core/integration-tests/test/css.js +++ b/packages/core/integration-tests/test/css.js @@ -17,6 +17,9 @@ describe('css', function() { name: 'index.js', assets: ['index.js', 'index.css', 'local.js', 'local.css'], childBundles: [ + { + name: 'index.js.map' + }, { name: 'index.css', assets: ['index.css', 'local.css'], @@ -25,9 +28,6 @@ describe('css', function() { type: 'map' } ] - }, - { - name: 'index.js.map' } ] }); @@ -59,10 +59,13 @@ describe('css', function() { assets: ['index.css'], childBundles: [ { - name: 'index.css.map' + type: 'map' } ] }, + { + name: 'index.js.map' + }, { type: 'js', assets: ['local.css', 'local.js'], @@ -80,9 +83,6 @@ describe('css', function() { type: 'map' } ] - }, - { - name: 'index.js.map' } ] }); diff --git a/packages/core/test-utils/src/utils.js b/packages/core/test-utils/src/utils.js index cd197a93abb..57d972ea1f8 100644 --- a/packages/core/test-utils/src/utils.js +++ b/packages/core/test-utils/src/utils.js @@ -136,7 +136,7 @@ async function assertBundleTree(bundle, tree) { if (childBundles) { let children = Array.from(bundle.childBundles).sort((a, b) => { let assetA = Array.from(a.assets).sort()[0]; - let assetB = Array.from(a.assets).sort()[0]; + let assetB = Array.from(b.assets).sort()[0]; if (assetA.basename < assetB.basename) { return -1; } else if (assetA.basename > assetB.basename) { From 0119cabf1d48748bdcaa0e5931119d5cd6e17e69 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sat, 16 Feb 2019 22:37:52 +0100 Subject: [PATCH 34/40] Fix CSS test timeout on Windows --- packages/core/parcel-bundler/src/packagers/CSSPackager.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/core/parcel-bundler/src/packagers/CSSPackager.js b/packages/core/parcel-bundler/src/packagers/CSSPackager.js index ec2f5c6c8e1..03e91dd3d09 100644 --- a/packages/core/parcel-bundler/src/packagers/CSSPackager.js +++ b/packages/core/parcel-bundler/src/packagers/CSSPackager.js @@ -67,6 +67,7 @@ class CSSPackager extends Packager { await this.write(`\n/*# sourceMappingURL=${mapUrl} */`); } } + await super.end(); } } From dd1355e09bfe696742f77c306423391f424494df Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sun, 17 Feb 2019 21:35:53 +0100 Subject: [PATCH 35/40] Cleanup sourcemap testing --- .../core/integration-tests/test/sourcemaps.js | 200 +++++++++--------- 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 0b51d1196be..208222b4efc 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -86,12 +86,11 @@ describe('sourcemaps', function() { ] }); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/index.js') - )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/index.js.map') - )).toString(); + let raw = await fs.readFile(path.join(__dirname, '/dist/index.js'), 'utf8'); + let map = await fs.readFile( + path.join(__dirname, '/dist/index.js.map'), + 'utf8' + ); mapValidator(raw, map); let mapObject = JSON.parse(map); assert( @@ -132,12 +131,11 @@ describe('sourcemaps', function() { ] }); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/index.js') - )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/index.js.map') - )).toString(); + let raw = await fs.readFile(path.join(__dirname, '/dist/index.js'), 'utf8'); + let map = await fs.readFile( + path.join(__dirname, '/dist/index.js.map'), + 'utf8' + ); assert.equal(JSON.parse(map).sources.length, 1); mapValidator(raw, map); @@ -162,12 +160,11 @@ describe('sourcemaps', function() { ] }); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/index.js') - )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/index.js.map') - )).toString(); + let raw = await fs.readFile(path.join(__dirname, '/dist/index.js'), 'utf8'); + let map = await fs.readFile( + path.join(__dirname, '/dist/index.js.map'), + 'utf8' + ); assert.equal(JSON.parse(map).sources.length, 2); mapValidator(raw, map); @@ -192,12 +189,11 @@ describe('sourcemaps', function() { ] }); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/index.js') - )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/index.js.map') - )).toString(); + let raw = await fs.readFile(path.join(__dirname, '/dist/index.js'), 'utf8'); + let map = await fs.readFile( + path.join(__dirname, '/dist/index.js.map'), + 'utf8' + ); mapValidator(raw, map); let output = await run(b); @@ -224,12 +220,11 @@ describe('sourcemaps', function() { ] }); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/index.js') - )).toString(); - let map = (await fs.readFile( - path.join(__dirname, '/dist/index.js.map') - )).toString(); + let raw = await fs.readFile(path.join(__dirname, '/dist/index.js'), 'utf8'); + let map = await fs.readFile( + path.join(__dirname, '/dist/index.js.map'), + 'utf8' + ); assert.equal(JSON.parse(map).sources.length, 3); mapValidator(raw, map); @@ -259,9 +254,10 @@ describe('sourcemaps', function() { ] }); - let jsOutput = (await fs.readFile( - Array.from(b.childBundles)[0].name - )).toString(); + let jsOutput = await fs.readFile( + Array.from(b.childBundles)[0].name, + 'utf8' + ); let sourcemapReference = path.join( __dirname, @@ -273,7 +269,7 @@ describe('sourcemaps', function() { 'referenced sourcemap should exist' ); - let map = (await fs.readFile(path.join(sourcemapReference))).toString(); + let map = await fs.readFile(path.join(sourcemapReference), 'utf8'); assert.equal(JSON.parse(map).sources.length, 2); mapValidator(jsOutput, map); }); @@ -434,16 +430,16 @@ describe('sourcemaps', function() { ] }); - let input = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-css/style.css') - )).toString(); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/style.css') - )).toString(); + let input = await fs.readFile( + path.join(__dirname, '/integration/sourcemap-css/style.css'), + 'utf8' + ); + let raw = await fs.readFile( + path.join(__dirname, '/dist/style.css'), + 'utf8' + ); let map = JSON.parse( - (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString() + await fs.readFile(path.join(__dirname, '/dist/style.css.map'), 'utf8') ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); @@ -494,28 +490,30 @@ describe('sourcemaps', function() { ] }); - let style = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-css-import/style.css') - )).toString(); - let otherStyle = (await fs.readFile( + let style = await fs.readFile( + path.join(__dirname, '/integration/sourcemap-css-import/style.css'), + 'utf8' + ); + let otherStyle = await fs.readFile( path.join( __dirname, '/integration/sourcemap-css-import/other-style.css' - ) - )).toString(); - let anotherStyle = (await fs.readFile( + ), + 'utf8' + ); + let anotherStyle = await fs.readFile( path.join( __dirname, '/integration/sourcemap-css-import/another-style.css' - ) - )).toString(); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/style.css') - )).toString(); + ), + 'utf8' + ); + let raw = await fs.readFile( + path.join(__dirname, '/dist/style.css'), + 'utf8' + ); let map = JSON.parse( - (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString() + await fs.readFile(path.join(__dirname, '/dist/style.css.map'), 'utf8') ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); @@ -604,16 +602,16 @@ describe('sourcemaps', function() { ] }); - let input = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-sass/style.scss') - )).toString(); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/style.css') - )).toString(); + let input = await fs.readFile( + path.join(__dirname, '/integration/sourcemap-sass/style.scss'), + 'utf8' + ); + let raw = await fs.readFile( + path.join(__dirname, '/dist/style.css'), + 'utf8' + ); let map = JSON.parse( - (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString() + await fs.readFile(path.join(__dirname, '/dist/style.css.map'), 'utf8') ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); @@ -664,19 +662,20 @@ describe('sourcemaps', function() { ] }); - let style = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-sass-imported/style.css') - )).toString(); - let other = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-sass-imported/other.scss') - )).toString(); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/style.css') - )).toString(); + let style = await fs.readFile( + path.join(__dirname, '/integration/sourcemap-sass-imported/style.css'), + 'utf8' + ); + let other = await fs.readFile( + path.join(__dirname, '/integration/sourcemap-sass-imported/other.scss'), + 'utf8' + ); + let raw = await fs.readFile( + path.join(__dirname, '/dist/style.css'), + 'utf8' + ); let map = JSON.parse( - (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString() + await fs.readFile(path.join(__dirname, '/dist/style.css.map'), 'utf8') ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); @@ -745,16 +744,16 @@ describe('sourcemaps', function() { ] }); - let input = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-less/style.less') - )).toString(); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/style.css') - )).toString(); + let input = await fs.readFile( + path.join(__dirname, '/integration/sourcemap-less/style.less'), + 'utf8' + ); + let raw = await fs.readFile( + path.join(__dirname, '/dist/style.css'), + 'utf8' + ); let map = JSON.parse( - (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString() + await fs.readFile(path.join(__dirname, '/dist/style.css.map'), 'utf8') ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); @@ -804,22 +803,23 @@ describe('sourcemaps', function() { ] }); - let style = (await fs.readFile( - path.join(__dirname, '/integration/sourcemap-css-existing/style.css') - )).toString(); - let library = (await fs.readFile( + let style = await fs.readFile( + path.join(__dirname, '/integration/sourcemap-css-existing/style.css'), + 'utf8' + ); + let library = await fs.readFile( path.join( __dirname, '/integration/sourcemap-css-existing/test/library.raw.scss' - ) - )).toString(); - let raw = (await fs.readFile( - path.join(__dirname, '/dist/style.css') - )).toString(); + ), + 'utf8' + ); + let raw = await fs.readFile( + path.join(__dirname, '/dist/style.css'), + 'utf8' + ); let map = JSON.parse( - (await fs.readFile( - path.join(__dirname, '/dist/style.css.map') - )).toString() + await fs.readFile(path.join(__dirname, '/dist/style.css.map'), 'utf8') ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); From 100e68fd5a9d49f32e15273bed5cf3b3153539d1 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Sat, 23 Feb 2019 17:27:42 +0100 Subject: [PATCH 36/40] Fix sourcemap tests on Windows --- .../core/integration-tests/test/sourcemaps.js | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index 208222b4efc..e56ee7d1b31 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -1,6 +1,7 @@ const assert = require('assert'); const fs = require('@parcel/fs'); const path = require('path'); +const os = require('os'); const mapValidator = require('sourcemap-validator'); const SourceMap = parseInt(process.versions.node, 10) < 8 @@ -443,7 +444,10 @@ describe('sourcemaps', function() { ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); - assert(map.sourceRoot == '../integration/sourcemap-css'); + assert.equal( + map.sourceRoot, + path.normalize('../integration/sourcemap-css') + ); let sourceMap = await new SourceMap().addMap(map); assert.equal(Object.keys(sourceMap.sources).length, 1); @@ -517,7 +521,10 @@ describe('sourcemaps', function() { ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); - assert(map.sourceRoot == '../integration/sourcemap-css-import'); + assert.equal( + map.sourceRoot, + path.normalize('../integration/sourcemap-css-import') + ); let sourceMap = await new SourceMap().addMap(map); assert.equal(Object.keys(sourceMap.sources).length, 3); @@ -615,7 +622,10 @@ describe('sourcemaps', function() { ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); - assert(map.sourceRoot == '../integration/sourcemap-sass'); + assert.equal( + map.sourceRoot, + path.normalize('../integration/sourcemap-sass') + ); let sourceMap = await new SourceMap().addMap(map); assert.equal(Object.keys(sourceMap.sources).length, 1); @@ -679,7 +689,10 @@ describe('sourcemaps', function() { ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); - assert(map.sourceRoot == '../integration/sourcemap-sass-imported'); + assert.equal( + map.sourceRoot, + path.normalize('../integration/sourcemap-sass-imported') + ); let sourceMap = await new SourceMap().addMap(map); assert.equal(Object.keys(sourceMap.sources).length, 2); @@ -757,11 +770,17 @@ describe('sourcemaps', function() { ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); - assert(map.sourceRoot == '../integration/sourcemap-less'); + assert.equal( + map.sourceRoot, + path.normalize('../integration/sourcemap-less') + ); let sourceMap = await new SourceMap().addMap(map); assert.equal(Object.keys(sourceMap.sources).length, 1); - assert.equal(sourceMap.sources['style.less'], input); + assert.equal( + sourceMap.sources['style.less'], + input.replace(new RegExp(os.EOL, 'g'), '\n') + ); checkSourceMapping({ map: sourceMap, @@ -823,12 +842,18 @@ describe('sourcemaps', function() { ); assert(raw.includes('/*# sourceMappingURL=/style.css.map */')); - assert(map.sourceRoot == '../integration/sourcemap-css-existing'); + assert.equal( + map.sourceRoot, + path.normalize('../integration/sourcemap-css-existing') + ); let sourceMap = await new SourceMap().addMap(map); assert.equal(Object.keys(sourceMap.sources).length, 2); assert.equal(sourceMap.sources['style.css'], style); - assert.equal(sourceMap.sources['test/library.scss'], library); + assert.equal( + sourceMap.sources[path.normalize('test/library.scss')], + library.replace(new RegExp(os.EOL, 'g'), '\n') + ); checkSourceMapping({ map: sourceMap, @@ -853,7 +878,7 @@ describe('sourcemaps', function() { source: library, generated: raw, str: 'body', - sourcePath: 'test/library.scss', + sourcePath: path.normalize('test/library.scss'), msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -863,7 +888,7 @@ describe('sourcemaps', function() { generated: raw, str: 'div', generatedStr: 'body div', - sourcePath: 'test/library.scss', + sourcePath: path.normalize('test/library.scss'), msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); @@ -872,7 +897,7 @@ describe('sourcemaps', function() { source: library, generated: raw, str: 'background-color', - sourcePath: 'test/library.scss', + sourcePath: path.normalize('test/library.scss'), msg: ' ' + (minify ? 'with' : 'without') + ' minification' }); } From c43360f0e174659755918e6acbb940a6fcb04dab Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Wed, 27 Feb 2019 13:47:36 +0100 Subject: [PATCH 37/40] Invalidate cache based on --no-source-maps --- packages/core/parcel-bundler/src/FSCache.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/core/parcel-bundler/src/FSCache.js b/packages/core/parcel-bundler/src/FSCache.js index dedee45b2ea..80fbd4b8197 100644 --- a/packages/core/parcel-bundler/src/FSCache.js +++ b/packages/core/parcel-bundler/src/FSCache.js @@ -7,7 +7,14 @@ const logger = require('@parcel/logger'); const {isGlob, glob} = require('./utils/glob'); // These keys can affect the output, so if they differ, the cache should not match -const OPTION_KEYS = ['publicURL', 'minify', 'hmr', 'target', 'scopeHoist']; +const OPTION_KEYS = [ + 'publicURL', + 'minify', + 'hmr', + 'target', + 'scopeHoist', + 'sourceMaps' +]; class FSCache { constructor(options) { From c2a4302b96bfdc4e25452044557660a8cd8b1483 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Wed, 27 Feb 2019 14:02:35 +0100 Subject: [PATCH 38/40] Fix tests --- packages/core/integration-tests/test/css.js | 30 +++++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/core/integration-tests/test/css.js b/packages/core/integration-tests/test/css.js index 90e8cb72ba3..d55db7e807f 100644 --- a/packages/core/integration-tests/test/css.js +++ b/packages/core/integration-tests/test/css.js @@ -354,7 +354,11 @@ describe('css', function() { { name: 'index.css', assets: ['composes-1.css', 'composes-2.css', 'mixins.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' @@ -412,7 +416,11 @@ describe('css', function() { { name: 'index2.css', assets: ['composes-3.css', 'mixins.scss'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' @@ -447,7 +455,11 @@ describe('css', function() { { name: 'index3.css', assets: ['composes-4.css', 'mixins.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' @@ -487,7 +499,11 @@ describe('css', function() { { name: 'index4.css', assets: ['composes-5.css', 'mixins-intermediate.css', 'mixins.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' @@ -525,7 +541,11 @@ describe('css', function() { { name: 'index5.css', assets: ['composes-6.css', 'mixins.css'], - childBundles: [] + childBundles: [ + { + type: 'map' + } + ] }, { type: 'map' From d1be7c773cb20fbd11dcdc7b8ef163895aef4769 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Tue, 5 Mar 2019 18:14:51 +0100 Subject: [PATCH 39/40] Compatibility --- packages/core/integration-tests/test/sourcemaps.js | 2 +- packages/core/parcel-bundler/src/Asset.js | 14 +------------- packages/core/parcel-bundler/src/Pipeline.js | 13 +++++++++++++ .../core/parcel-bundler/src/assets/HTMLAsset.js | 2 -- packages/core/parcel-bundler/src/assets/JSAsset.js | 9 +++------ .../core/parcel-bundler/src/assets/VueAsset.js | 1 - 6 files changed, 18 insertions(+), 23 deletions(-) diff --git a/packages/core/integration-tests/test/sourcemaps.js b/packages/core/integration-tests/test/sourcemaps.js index e56ee7d1b31..1a412cf1904 100644 --- a/packages/core/integration-tests/test/sourcemaps.js +++ b/packages/core/integration-tests/test/sourcemaps.js @@ -654,7 +654,7 @@ describe('sourcemaps', function() { await test(true); }); - it('should create a valid sourcemap when a CSS asset imports SASS', async function() { + it('should create a valid sourcemap when for a CSS asset importing SASS', async function() { async function test(minify) { let b = await bundle( path.join(__dirname, '/integration/sourcemap-sass-imported/style.css'), diff --git a/packages/core/parcel-bundler/src/Asset.js b/packages/core/parcel-bundler/src/Asset.js index 13ede86f8da..ce46f9f07e5 100644 --- a/packages/core/parcel-bundler/src/Asset.js +++ b/packages/core/parcel-bundler/src/Asset.js @@ -34,6 +34,7 @@ class Asset { this.ast = null; this.generated = null; this.hash = null; + this.sourceMaps = null; this.parentDeps = new Set(); this.dependencies = new Map(); this.depAssets = new Map(); @@ -219,19 +220,6 @@ class Asset { } async postProcess(generated) { - let hasMap = false; - let sourceMaps = {}; - for (let rendition of generated) { - if (rendition.map && rendition.type == this.type) { - sourceMaps[rendition.type] = rendition.map; - hasMap = true; - } - } - - if (hasMap) { - this.sourceMaps = sourceMaps; - } - return generated; } diff --git a/packages/core/parcel-bundler/src/Pipeline.js b/packages/core/parcel-bundler/src/Pipeline.js index 0294b803f3f..0b016006fbc 100644 --- a/packages/core/parcel-bundler/src/Pipeline.js +++ b/packages/core/parcel-bundler/src/Pipeline.js @@ -93,6 +93,19 @@ class Pipeline { throw asset.generateErrorMessage(err); } + let hasMap = false; + let sourceMaps = {}; + for (let rendition of generated) { + if (rendition.map && rendition.type == asset.type) { + sourceMaps[rendition.type] = rendition.map; + hasMap = true; + } + } + + if (hasMap) { + asset.sourceMaps = sourceMaps; + } + asset.generated = generated; asset.hash = await asset.generateHash(); diff --git a/packages/core/parcel-bundler/src/assets/HTMLAsset.js b/packages/core/parcel-bundler/src/assets/HTMLAsset.js index a27ef8a9500..2bbdd363458 100644 --- a/packages/core/parcel-bundler/src/assets/HTMLAsset.js +++ b/packages/core/parcel-bundler/src/assets/HTMLAsset.js @@ -271,8 +271,6 @@ class HTMLAsset extends Asset { } async postProcess(generated) { - generated = await super.postProcess(generated); - // Replace inline scripts and styles with processed results. for (let rendition of generated) { let {type, node} = rendition.meta; diff --git a/packages/core/parcel-bundler/src/assets/JSAsset.js b/packages/core/parcel-bundler/src/assets/JSAsset.js index 2fa31386a31..5d42aca05a7 100644 --- a/packages/core/parcel-bundler/src/assets/JSAsset.js +++ b/packages/core/parcel-bundler/src/assets/JSAsset.js @@ -139,9 +139,6 @@ class JSAsset extends Asset { } async generate() { - let enableSourceMaps = - this.options.sourceMaps && - (!this.rendition || !!this.rendition.sourceMap); let code; if (this.isAstDirty) { let opts = { @@ -151,7 +148,7 @@ class JSAsset extends Asset { let generated = generate(this.ast, opts, this.contents); - if (enableSourceMaps && generated.rawMappings) { + if (this.options.sourceMaps && generated.rawMappings) { let rawMap = new SourceMap(generated.rawMappings, { [this.relativeName]: this.contents }); @@ -173,7 +170,7 @@ class JSAsset extends Asset { code = this.outputCode != null ? this.outputCode : this.contents; } - if (enableSourceMaps && !this.sourceMap) { + if (this.options.sourceMaps && !this.sourceMap) { this.sourceMap = new SourceMap().generateEmptyMap( this.relativeName, this.contents @@ -182,7 +179,7 @@ class JSAsset extends Asset { if (this.globals.size > 0) { code = Array.from(this.globals.values()).join('\n') + '\n' + code; - if (enableSourceMaps) { + if (this.options.sourceMaps) { if (!(this.sourceMap instanceof SourceMap)) { this.sourceMap = await new SourceMap().addMap(this.sourceMap); } diff --git a/packages/core/parcel-bundler/src/assets/VueAsset.js b/packages/core/parcel-bundler/src/assets/VueAsset.js index c9ee00d5fd2..ce9bb946794 100644 --- a/packages/core/parcel-bundler/src/assets/VueAsset.js +++ b/packages/core/parcel-bundler/src/assets/VueAsset.js @@ -60,7 +60,6 @@ class VueAsset extends Asset { } async postProcess(generated) { - generated = await super.postProcess(generated); let result = []; let hasScoped = this.ast.styles.some(s => s.scoped); From 9d5ec0b7d933a5cbe478e490581cdb78306cf9a9 Mon Sep 17 00:00:00 2001 From: Niklas Mischkulnig Date: Tue, 5 Mar 2019 18:39:18 +0100 Subject: [PATCH 40/40] Fix vue sourcemaps --- packages/core/parcel-bundler/src/assets/VueAsset.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/core/parcel-bundler/src/assets/VueAsset.js b/packages/core/parcel-bundler/src/assets/VueAsset.js index ce9bb946794..ade65249427 100644 --- a/packages/core/parcel-bundler/src/assets/VueAsset.js +++ b/packages/core/parcel-bundler/src/assets/VueAsset.js @@ -35,7 +35,7 @@ class VueAsset extends Asset { parts.push({ type: descriptor.script.lang || 'js', value: descriptor.script.content, - sourceMap: descriptor.script.map + map: descriptor.script.map }); } @@ -117,15 +117,11 @@ class VueAsset extends Asset { if (js) { result.push({ type: 'js', - value: js + value: js, + map: this.options.sourceMaps && this.ast.script && generated[0].map }); } - let map = generated.find(r => r.type === 'map'); - if (map) { - result.push(map); - } - let css = this.compileStyle(generated, scopeId); if (css) { result.push({