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 50 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 @@ -38,6 +38,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 @@ -47,6 +48,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 @@ -66,7 +68,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
1 change: 1 addition & 0 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
15 changes: 14 additions & 1 deletion src/Bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ class Bundle {
this.assets = new Set();
this.childBundles = new Set();
this.siblingBundles = new Map();
this.offsets = new Map();
}

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

addAsset(asset) {
Expand Down Expand Up @@ -66,15 +71,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 @@ -68,6 +68,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 @@ -161,6 +166,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
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
36 changes: 31 additions & 5 deletions src/assets/JSAsset.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const fsVisitor = require('../visitors/fs');
const babel = require('../transforms/babel');
const generate = require('babel-generator').default;
const uglify = require('../transforms/uglify');
const sourceMaps = require('../utils/SourceMaps');

const IMPORT_RE = /\b(?:import\b|export\b|require\s*\()/;
const GLOBAL_RE = /\b(?:process|__dirname|__filename|global|Buffer)\b/;
Expand Down Expand Up @@ -117,16 +118,41 @@ class JSAsset extends Asset {
}

generate() {
// TODO: source maps
let code = this.isAstDirty
? generate(this.ast).code
: this.outputCode || this.contents;
let code;
if (this.isAstDirty) {
let opts = {
sourceMaps: this.options.sourcemaps,
sourceFileName: this.options.sourcemaps ? this.relativename : undefined
};
let generated = generate(this.ast, opts, this.contents);
if (this.sourcemap && generated.map) {
Copy link
Member

Choose a reason for hiding this comment

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

When/why does this case occur (there is already a source map)?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is when babel has to generate the code from ast after for example Typescript parsed the code. Typescript sets a sourcemap, although babel changes the sourcemap in these particular cases, and this function offsets it correctly again.
This happens in the typescript env test for example

this.sourcemap = sourceMaps.extendSourceMap(
this.sourcemap,
generated.map
);
} else {
this.sourcemap = this.options.sourcemaps ? generated.map : undefined;
}
code = generated.code;
}
code = code ? code : this.outputCode || this.contents;

if (this.options.sourcemaps) {
this.sourcemap = this.sourcemap
? this.sourcemap
: sourceMaps.getEmptyMap(this.relativename, this.contents);
}

if (this.globals.size > 0) {
code = Array.from(this.globals.values()).join('\n') + '\n' + code;
this.sourcemap = this.options.sourcemaps
? sourceMaps.offsetSourceMap(this.sourcemap, this.globals.size)
: undefined;
}

return {
js: code
js: code,
map: this.sourcemap
Copy link
Member

Choose a reason for hiding this comment

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

We'll also need to generate 1:1 source maps for files that we don't process with babel.

Copy link
Member Author

Choose a reason for hiding this comment

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

done

};
}

Expand Down
18 changes: 14 additions & 4 deletions src/assets/TypeScriptAsset.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,22 @@ class TypeScriptAsset extends JSAsset {
);
}
transpilerOptions.compilerOptions.noEmit = false;
transpilerOptions.compilerOptions.sourceMap = this.options.sourcemaps;

// Transpile Module using TypeScript and parse result as ast format through babylon
this.contents = typescript.transpileModule(
code,
transpilerOptions
).outputText;
let transpiled = typescript.transpileModule(code, transpilerOptions);
this.sourcemap = transpiled.sourceMapText;
if (this.sourcemap) {
this.sourcemap = JSON.parse(this.sourcemap);
this.sourcemap.sourcesContent = [this.contents];
// Remove the sourcemap URL
let content = transpiled.outputText;
transpiled.outputText = content.substring(
0,
content.lastIndexOf('//# sourceMappingURL')
);
}
this.contents = transpiled.outputText;
return await super.parse(this.contents);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ program
)
.option('--no-hmr', 'disable hot module replacement')
.option('--no-cache', 'disable the filesystem cache')
.option('--no-sourcemaps', 'disable sourcemaps')
.option('-V, --version', 'output the version number')
.action(bundle);

Expand All @@ -50,6 +51,7 @@ program
)
.option('--no-hmr', 'disable hot module replacement')
.option('--no-cache', 'disable the filesystem cache')
.option('--no-sourcemaps', 'disable sourcemaps')
.action(bundle);

program
Expand Down
16 changes: 14 additions & 2 deletions src/packagers/JSPackager.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const fs = require('fs');
const path = require('path');
const Packager = require('./Packager');
const urlJoin = require('../utils/urlJoin');
const lineCounter = require('../utils/textUtils').lineCounter;

const prelude = {
source: fs
Expand All @@ -23,6 +25,7 @@ class JSPackager extends Packager {

let preludeCode = this.options.minify ? prelude.minified : prelude.source;
await this.dest.write(preludeCode + '({');
this.lineOffset = lineCounter(preludeCode);
}

async addAsset(asset) {
Expand Down Expand Up @@ -52,7 +55,7 @@ class JSPackager extends Packager {
deps[dep.name] = this.dedupe.get(mod.generated.js) || mod.id;
}
}

this.bundle.addOffset(asset, this.lineOffset, 0);
await this.writeModule(asset.id, asset.generated.js, deps);
}

Expand All @@ -64,6 +67,7 @@ class JSPackager extends Packager {
wrapped += ']';

this.first = false;
this.lineOffset += lineCounter(wrapped) - 1;
await this.dest.write(wrapped);
}

Expand All @@ -87,7 +91,15 @@ class JSPackager extends Packager {
entry.push(this.bundle.entryAsset.id);
}

await this.dest.end('},{},' + JSON.stringify(entry) + ')');
await this.dest.write('},{},' + JSON.stringify(entry) + ')');
// Add sourcemap url
await this.dest.write(
Copy link
Member

Choose a reason for hiding this comment

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

This should only be added if sourcemaps are enabled right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ow yes, will change this

`\n//# sourceMappingURL=${urlJoin(
this.options.publicURL,
path.basename(this.bundle.name).slice(0, -3) + '.map'
)}`
);
await this.dest.end();
}
}

Expand Down
38 changes: 38 additions & 0 deletions src/packagers/SourcemapPackager.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const path = require('path');
const sourceMap = require('source-map');
const Packager = require('./Packager');
const sourceMapUtils = require('../utils/SourceMaps');

class SourcemapPackager extends Packager {
async start() {
this.generator = new sourceMap.SourceMapGenerator({
file: path.basename(this.bundle.name)
});
}

getOffsets(asset) {
let parent = this.bundle.parentBundle;
return parent.offsets.get(asset.relativename) || {line: 0, column: 0};
}

async addAsset(asset) {
if (asset.generated.map) {
Copy link
Member

Choose a reason for hiding this comment

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

If an asset is added to a map bundle, it should definitely have a generated map. did you find otherwise?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is probably a remain from the initial approach, i'll remove this and test a bit to make sure it doesn't break

this.generator = sourceMapUtils.combineSourceMaps(
asset.generated.map,
this.generator,
this.getOffsets(asset).line
);
}
}

async writeMap() {
await this.dest.write(this.generator.toString());
}

async end() {
await this.writeMap();
await super.end();
}
}

module.exports = SourcemapPackager;
2 changes: 2 additions & 0 deletions src/packagers/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const JSPackager = require('./JSPackager');
const CSSPackager = require('./CSSPackager');
const HTMLPackager = require('./HTMLPackager');
const SourceMapPackager = require('./SourcemapPackager');
const RawPackager = require('./RawPackager');

class PackagerRegistry {
Expand All @@ -10,6 +11,7 @@ class PackagerRegistry {
this.add('js', JSPackager);
this.add('css', CSSPackager);
this.add('html', HTMLPackager);
this.add('map', SourceMapPackager);
}

add(type, packager) {
Expand Down
Loading