Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JS Source Maps support #506

Merged
merged 76 commits into from
Jan 22, 2018
Merged
Show file tree
Hide file tree
Changes from 72 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
fedbd52
Merge pull request #1 from parcel-bundler/master
Dec 9, 2017
3f31fc5
Merge branch 'master' of github.com:DeMoorJasper/parcel
DeMoorJasper Dec 9, 2017
b09d15f
Merge pull request #4 from parcel-bundler/master
Dec 11, 2017
80b3431
Merge branch 'master' of github.com:DeMoorJasper/parcel
DeMoorJasper Dec 11, 2017
392bbc9
run prettier
DeMoorJasper Dec 11, 2017
e616cc2
Merge pull request #7 from parcel-bundler/master
Dec 12, 2017
1d90425
stuff
DeMoorJasper Dec 12, 2017
51bfe22
Merge pull request #9 from parcel-bundler/master
Dec 15, 2017
2d393d2
Merge pull request #12 from parcel-bundler/master
Dec 31, 2017
85c7587
Merge branch 'master' of github.com:DeMoorJasper/parcel
DeMoorJasper Dec 31, 2017
3c3cb77
Merge pull request #14 from parcel-bundler/master
Jan 2, 2018
9e7e46b
Merge branch 'master' of github.com:DeMoorJasper/parcel
DeMoorJasper Jan 2, 2018
44f7a89
initial sourcemap
DeMoorJasper Jan 7, 2018
f24bdd7
improve sourcemap constructor
DeMoorJasper Jan 8, 2018
a5b5ce2
also support SourceMapConsumer as addMap input
DeMoorJasper Jan 8, 2018
243d543
some cleanup and fixes
DeMoorJasper Jan 8, 2018
a2056df
Merge pull request #16 from parcel-bundler/master
Jan 8, 2018
c3f40bd
Merge branch 'feature/source-maps' of github.com:DeMoorJasper/parcel …
DeMoorJasper Jan 8, 2018
f6cadb5
add lineOffset and 1:1 sourcemaps
DeMoorJasper Jan 8, 2018
a6a0d9a
add lineOffset and 1:1 sourcemaps
DeMoorJasper Jan 8, 2018
cef8a8b
fix conflicts
DeMoorJasper Jan 8, 2018
5157b02
slight sourcemaputil improvement
DeMoorJasper Jan 8, 2018
ca829e5
use babel-generator instead of double generating
DeMoorJasper Jan 8, 2018
6d8f4da
add 1:1 sourcemap for untranspiled assets
DeMoorJasper Jan 9, 2018
d101c48
update offset
DeMoorJasper Jan 9, 2018
7d9532b
fix source paths
DeMoorJasper Jan 9, 2018
35a1b6f
fix conflicts
DeMoorJasper Jan 10, 2018
156736f
Merge branch 'parcel-bundler-master' into feature/source-maps
DeMoorJasper Jan 10, 2018
40fe5bc
Better offset solution
DeMoorJasper Jan 10, 2018
4840a59
fix sourceContent not being set by babel-generator
DeMoorJasper Jan 10, 2018
42c52b6
fix small offset bug
DeMoorJasper Jan 10, 2018
607d5a0
add sourcemap option and offset when globals are added
DeMoorJasper Jan 10, 2018
6e89578
add cli option to disable sourcemaps
DeMoorJasper Jan 10, 2018
bb74a14
ts & coffeescript support
DeMoorJasper Jan 10, 2018
897b494
fix most tests
DeMoorJasper Jan 10, 2018
401b12c
All tests (except hmr) fixed + bugfix for ts
DeMoorJasper Jan 11, 2018
b28c167
fix hmr tests
DeMoorJasper Jan 11, 2018
ec0f552
comment out error throwing in tests
DeMoorJasper Jan 11, 2018
220bdf8
fix windows tests
DeMoorJasper Jan 11, 2018
d0498f9
add sourcemap tests
DeMoorJasper Jan 11, 2018
603a12d
Merge branch 'feature/source-maps' of github.com:DeMoorJasper/parcel …
DeMoorJasper Jan 11, 2018
0c97ebf
add comment to why throwing errors is commented out in tests
DeMoorJasper Jan 11, 2018
7e29f10
Merge pull request #18 from parcel-bundler/master
Jan 12, 2018
be46eee
Merge branch 'feature/source-maps' of github.com:DeMoorJasper/parcel …
DeMoorJasper Jan 12, 2018
e09aaa2
update with circular fix, now throws on test failures
DeMoorJasper Jan 12, 2018
032d475
fix generator for invalid maps
DeMoorJasper Jan 15, 2018
b7f6500
Merge branch 'master' into feature/source-maps
Jan 15, 2018
05741c0
Merge branch 'master' into feature/source-maps
Jan 15, 2018
126f522
Merge branch 'feature/source-maps' of github.com:DeMoorJasper/parcel …
DeMoorJasper Jan 15, 2018
2bc0f2b
fix tests
DeMoorJasper Jan 15, 2018
dd5a018
Merge branch 'master' into feature/source-maps
Jan 16, 2018
46f2054
Merge branch 'feature/source-maps' of github.com:DeMoorJasper/parcel …
DeMoorJasper Jan 16, 2018
f942bfe
Merge branch 'master' into feature/source-maps
Jan 16, 2018
42598ff
Merge branch 'feature/source-maps' of github.com:DeMoorJasper/parcel …
DeMoorJasper Jan 16, 2018
8b9ad40
fix tiny issues
DeMoorJasper Jan 16, 2018
cf4f426
small performance improvement
DeMoorJasper Jan 16, 2018
11a5010
rewrite sourcemap handling, less generator constructing overhead and …
DeMoorJasper Jan 16, 2018
d3c86bd
extendSourceMap bugfix
DeMoorJasper Jan 16, 2018
9568714
Use babel rawMappings to remove encoding step
DeMoorJasper Jan 16, 2018
1222fb9
small performance fixes
DeMoorJasper Jan 16, 2018
c013456
improve linecounter
DeMoorJasper Jan 17, 2018
06a48b9
Merge pull request #21 from parcel-bundler/master
Jan 17, 2018
56e6ea6
Merge branch 'feature/source-maps' of github.com:DeMoorJasper/parcel …
DeMoorJasper Jan 17, 2018
5567ee5
small performance improvement and bugfix
DeMoorJasper Jan 17, 2018
c4eb40f
small improvement
DeMoorJasper Jan 18, 2018
310d22f
change for source-map 0.7 compatibility, improves performance a lil
DeMoorJasper Jan 19, 2018
be42812
switch to official npm release
DeMoorJasper Jan 21, 2018
0e57597
Merge pull request #23 from DeMoorJasper/source-map-0.7
Jan 21, 2018
2abb918
Merge branch 'feature/source-maps' of github.com:DeMoorJasper/parcel …
DeMoorJasper Jan 21, 2018
f39c21e
tiny improvement
DeMoorJasper Jan 21, 2018
90b85d1
only install source-map 0.7 if possible
DeMoorJasper Jan 21, 2018
8c81116
remove optional 0.7 dep
DeMoorJasper Jan 21, 2018
0b95aae
Minor refactorings
devongovett Jan 22, 2018
9908e9e
Store precomputed line count as part of source map
devongovett Jan 22, 2018
01db40c
Clean up
devongovett Jan 22, 2018
11b89c6
Last cleanup
devongovett Jan 22, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ lib
!test/**/node_modules
.vscode/
.idea/
*.min.js
*.min.js
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"resolve": "^1.4.0",
"sanitize-filename": "^1.6.1",
"serve-static": "^1.12.4",
"source-map": "0.6.1",
"uglify-es": "^3.2.1",
"v8-compile-cache": "^1.1.0",
"worker-farm": "^1.4.1",
Expand All @@ -48,6 +49,7 @@
"babel-cli": "^6.26.0",
"babel-preset-env": "^1.6.1",
"bsb-js": "^1.0.1",
"codecov": "^3.0.0",
"coffeescript": "^2.0.3",
"cross-env": "^5.1.1",
"eslint": "^4.13.0",
Expand All @@ -67,7 +69,7 @@
"rimraf": "^2.6.1",
"stylus": "^0.54.5",
"typescript": "^2.6.2",
"codecov": "^3.0.0"
"sourcemap-validator": "^1.0.6"
},
"scripts": {
"test": "cross-env NODE_ENV=test mocha",
Expand Down
5 changes: 3 additions & 2 deletions src/Asset.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class Asset {
this.options = options;
this.encoding = 'utf8';
this.type = path.extname(this.name).slice(1);
this.relativename = path.relative(this.options.rootDir, this.name);

this.processed = false;
this.contents = null;
Expand Down Expand Up @@ -125,7 +126,7 @@ class Asset {
// do nothing by default
}

generate() {
async generate() {
return {
[this.type]: this.contents
};
Expand All @@ -137,7 +138,7 @@ class Asset {
await this.pretransform();
await this.getDependencies();
await this.transform();
this.generated = this.generate();
this.generated = await this.generate();
this.hash = this.generateHash();
}

Expand Down
17 changes: 15 additions & 2 deletions src/Bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ class Bundle {
this.entryAsset = null;
this.assets = new Set();
this.childBundles = new Set();
this.siblingBundles = new Set;
this.siblingBundles = new Set();
this.siblingBundlesMap = new Map();
this.offsets = new Map();
}

addOffset(asset, line, column) {
this.offsets.set(asset.relativename, {line, column});
}

static createWithAsset(asset, parentBundle) {
Expand Down Expand Up @@ -89,15 +94,23 @@ class Bundle {
newHashes.set(this.name, hash);

let promises = [];
let mappings = [];
if (!oldHashes || oldHashes.get(this.name) !== hash) {
promises.push(this._package(bundler));
}

for (let bundle of this.childBundles.values()) {
promises.push(bundle.package(bundler, oldHashes, newHashes));
if (bundle.type === 'map') {
mappings.push(bundle);
} else {
promises.push(bundle.package(bundler, oldHashes, newHashes));
}
}

await Promise.all(promises);
for (let bundle of mappings) {
await bundle.package(bundler, oldHashes, newHashes);
}
return newHashes;
}

Expand Down
7 changes: 7 additions & 0 deletions src/Bundler.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ class Bundler extends EventEmitter {
logLevel: typeof options.logLevel === 'number' ? options.logLevel : 3,
mainFile: this.mainFile,
hmrPort: options.hmrPort || 0,
rootDir: Path.dirname(this.mainFile),
sourcemaps:
typeof options.sourcemaps === 'boolean'
? options.sourcemaps
: !isProduction,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should we disable sourcemaps in production? Isn't that where they are most useful since code is minified? Let's get some feedback on this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think there are usecases for disabling sourcemaps in production. how about enabling it by default and adding an option --disable-sourcemaps - so we can choose at build-time?

hmrHostname: options.hmrHostname || ''
};
}
Expand Down Expand Up @@ -204,6 +209,8 @@ class Bundler extends EventEmitter {

if (process.env.NODE_ENV === 'production') {
process.exitCode = 1;
} else if (process.env.NODE_ENV === 'test' && !this.hmr) {
throw err;
}
} finally {
this.pending = false;
Expand Down
192 changes: 192 additions & 0 deletions src/SourceMap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
const sourceMap = require('source-map');
const textUtils = require('./utils/textUtils');

class SourceMap {
constructor(file) {
this.sources = {};
this.mappings = [];
this.file = file;
}

copyConstructor(map) {
let sourcemap = new SourceMap();
sourcemap.mappings = map.mappings;
sourcemap.sources = map.sources;
sourcemap.file = map.file;
return sourcemap;
}

isConsumer(map) {
return map && map.computeColumnSpans;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just do map instanceof sourceMap.SourceMapConsumer? This check currently seems somewhat brittle since they could change the internal implementation.

}

async getConsumer(map) {
if (this.isConsumer(map)) {
return map;
}
return await new sourceMap.SourceMapConsumer(map);
}

async addMap(map, lineOffset = 0, columnOffset = 0) {
if (!isSourceMapInstance(map) && map.version) {
let consumer = await this.getConsumer(map);

consumer.eachMapping(mapping => {
this.addConsumerMapping(mapping, lineOffset, columnOffset);
if (!this.sources[mapping.source]) {
this.sources[mapping.source] = consumer.sourceContentFor(
mapping.source,
true
);
}
});
if (consumer.destroy) {
// Only needs to happen in source-map 0.7
consumer.destroy();
}
} else {
if (!map.eachMapping) {
map = this.copyConstructor(map);
}
if (lineOffset === 0 && columnOffset === 0) {
this.concatMappings(map.mappings);
} else {
map.eachMapping(mapping => {
this.addMapping(mapping, lineOffset, columnOffset);
});
}
Object.keys(map.sources).forEach(sourceName => {
if (!this.sources[sourceName]) {
this.sources[sourceName] = map.sources[sourceName];
}
});
}
}

concatMappings(mappings) {
this.mappings = this.mappings.concat(mappings);
}

addMapping(mapping, lineOffset = 0, columnOffset = 0) {
mapping.generated = {
line: mapping.generated.line + lineOffset,
column: mapping.generated.column + columnOffset
};
this.mappings.push(mapping);
}

addConsumerMapping(mapping, lineOffset = 0, columnOffset = 0) {
if (
!mapping.source ||
!mapping.originalLine ||
(!mapping.originalColumn && mapping.originalColumn !== 0)
) {
return;
}

this.mappings.push({
source: mapping.source,
original: {
line: mapping.originalLine,
column: mapping.originalColumn
},
generated: {
line: mapping.generatedLine + lineOffset,
column: mapping.generatedColumn + columnOffset
},
name: mapping.name
});
}

eachMapping(callback) {
this.mappings.forEach(callback);
}

generateEmptyMap(sourceName, sourceContent) {
this.sources[sourceName] = sourceContent;
let lines = textUtils.lineCounter(sourceContent);
for (let line = 1; line < lines + 1; line++) {
this.addMapping({
source: sourceName,
original: {
line: line,
column: 0
},
generated: {
line: line,
column: 0
}
});
}
return this;
}

async extendSourceMap(original, extension) {
if (!isSourceMapInstance(extension)) {
throw new Error(
'[SOURCEMAP] Type of extension should be a SourceMap instance!'
);
}

original = await this.getConsumer(original);
extension.eachMapping(mapping => {
let originalMapping = original.originalPositionFor({
line: mapping.original.line,
column: mapping.original.column
});

if (!originalMapping.line) {
return false;
}

this.addMapping({
source: originalMapping.source,
name: originalMapping.name,
original: {
line: originalMapping.line,
column: originalMapping.column
},
generated: {
line: mapping.generated.line,
column: mapping.generated.column
}
});
if (!this.sources[originalMapping.source]) {
this.sources[originalMapping.source] = original.sourceContentFor(
originalMapping.source,
true
);
}
});
if (original.destroy) {
// Only needs to happen in source-map 0.7
original.destroy();
}
}

offset(lineOffset = 0, columnOffset = 0) {
this.mappings.map(mapping => {
mapping.generated.line = mapping.generated.line + lineOffset;
mapping.generated.column = mapping.generated.column + columnOffset;
return mapping;
});
}

stringify() {
let generator = new sourceMap.SourceMapGenerator({
file: this.file
});
this.eachMapping(mapping => generator.addMapping(mapping));
Object.keys(this.sources).forEach(sourceName =>
generator.setSourceContent(sourceName, this.sources[sourceName])
);
return generator.toString();
}
}

function isSourceMapInstance(map) {
return !map.sources.length;
}

module.exports = SourceMap;
module.exports.isSourceMapInstance = isSourceMapInstance;
10 changes: 9 additions & 1 deletion src/assets/CoffeeScriptAsset.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ class CoffeeScriptAsset extends JSAsset {
let coffee = await localRequire('coffeescript', this.name);

// Transpile Module using CoffeeScript and parse result as ast format through babylon
this.contents = coffee.compile(code, {});
let transpiled = coffee.compile(code, {
sourceMap: this.options.sourcemaps
});
if (transpiled.sourceMap) {
this.sourcemap = transpiled.sourceMap.generate();
this.sourcemap.sources = [this.relativename];
this.sourcemap.sourcesContent = [this.contents];
}
this.contents = this.options.sourcemaps ? transpiled.js : transpiled;
return await super.parse(this.contents);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/assets/GlobAsset.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ class GlobAsset extends Asset {
return matches;
}

generate() {
async generate() {
return {
js: 'module.exports = ' + generate(this.contents) + ';'
js: 'module.exports = ' + (await generate(this.contents)) + ';'
};
}
}
Expand Down
Loading