Browse Source

Merge branch 'master' into gh-468

semi-dynamic-namespace-imports
Rich-Harris 8 years ago
parent
commit
0ad42d8b81
  1. 5
      CHANGELOG.md
  2. 6
      package.json
  3. 7
      rollup.config.js
  4. 24
      src/Bundle.js
  5. 3
      src/Module.js
  6. 1
      src/rollup.js
  7. 75
      src/utils/collapseSourcemaps.js
  8. 4
      src/utils/transform.js
  9. 2
      src/utils/transformBundle.js
  10. 63
      test/sourcemaps/loaders/_config.js
  11. 1
      test/sourcemaps/loaders/bar.js
  12. 1
      test/sourcemaps/loaders/foo.js
  13. 4
      test/sourcemaps/loaders/main.js
  14. 2
      test/test.js

5
CHANGELOG.md

@ -1,5 +1,10 @@
# rollup changelog # rollup changelog
## 0.31.2
* Allow `load` plugins to provide sourcemap ([#715](https://github.com/rollup/rollup/pull/715))
* Allow `sourceMapFile` in config options ([#717](https://github.com/rollup/rollup/issues/717))
## 0.31.1 ## 0.31.1
* Logging for errors emitted by `rollup-watch` ([#712](https://github.com/rollup/rollup/issues/712)) * Logging for errors emitted by `rollup-watch` ([#712](https://github.com/rollup/rollup/issues/712))

6
package.json

@ -1,9 +1,9 @@
{ {
"name": "rollup", "name": "rollup",
"version": "0.31.1", "version": "0.31.2",
"description": "Next-generation ES6 module bundler", "description": "Next-generation ES6 module bundler",
"main": "dist/rollup.js", "main": "dist/rollup.js",
"jsnext:main": "src/rollup.js", "jsnext:main": "dist/rollup.es.js",
"bin": { "bin": {
"rollup": "./bin/rollup" "rollup": "./bin/rollup"
}, },
@ -14,7 +14,7 @@
"test-coverage": "rm -rf coverage/* && istanbul cover --report json node_modules/.bin/_mocha -- -u exports -R spec test/test.js", "test-coverage": "rm -rf coverage/* && istanbul cover --report json node_modules/.bin/_mocha -- -u exports -R spec test/test.js",
"posttest-coverage": "remap-istanbul -i coverage/coverage-final.json -o coverage/coverage-remapped.json -b dist && remap-istanbul -i coverage/coverage-final.json -o coverage/coverage-remapped.lcov -t lcovonly -b dist && remap-istanbul -i coverage/coverage-final.json -o coverage/coverage-remapped -t html -b dist", "posttest-coverage": "remap-istanbul -i coverage/coverage-final.json -o coverage/coverage-remapped.json -b dist && remap-istanbul -i coverage/coverage-final.json -o coverage/coverage-remapped.lcov -t lcovonly -b dist && remap-istanbul -i coverage/coverage-final.json -o coverage/coverage-remapped -t html -b dist",
"ci": "npm run test-coverage && codecov < coverage/coverage-remapped.lcov", "ci": "npm run test-coverage && codecov < coverage/coverage-remapped.lcov",
"build": "git rev-parse HEAD > .commithash && rollup -c -o dist/rollup.js", "build": "git rev-parse HEAD > .commithash && rollup -c",
"build:cli": "rollup -c rollup.config.cli.js", "build:cli": "rollup -c rollup.config.cli.js",
"build:browser": "git rev-parse HEAD > .commithash && rollup -c rollup.config.browser.js -o dist/rollup.browser.js", "build:browser": "git rev-parse HEAD > .commithash && rollup -c rollup.config.browser.js -o dist/rollup.browser.js",
"prepublish": "npm run lint && npm test && npm run build:browser", "prepublish": "npm run lint && npm test && npm run build:browser",

7
rollup.config.js

@ -20,7 +20,6 @@ var banner = readFileSync( 'src/banner.js', 'utf-8' )
export default { export default {
entry: 'src/rollup.js', entry: 'src/rollup.js',
format: 'cjs',
plugins: [ plugins: [
buble({ buble({
include: [ 'src/**', 'node_modules/acorn/**' ] include: [ 'src/**', 'node_modules/acorn/**' ]
@ -40,5 +39,9 @@ export default {
external: [ 'fs' ], external: [ 'fs' ],
banner: banner, banner: banner,
sourceMap: true, sourceMap: true,
moduleName: 'rollup' moduleName: 'rollup',
targets: [
{ dest: 'dist/rollup.js', format: 'cjs' },
{ dest: 'dist/rollup.es.js', format: 'es6' }
]
}; };

24
src/Bundle.js

@ -46,12 +46,11 @@ export default class Bundle {
.concat( resolveId ) .concat( resolveId )
); );
this.load = first( const loaders = this.plugins
this.plugins .map( plugin => plugin.load )
.map( plugin => plugin.load ) .filter( Boolean );
.filter( Boolean ) this.hasLoaders = loaders.length !== 0;
.concat( load ) this.load = first( loaders.concat( load ) );
);
this.transformers = this.plugins this.transformers = this.plugins
.map( plugin => plugin.transform ) .map( plugin => plugin.transform )
@ -204,9 +203,9 @@ export default class Bundle {
return transform( source, id, this.transformers ); return transform( source, id, this.transformers );
}) })
.then( source => { .then( source => {
const { code, originalCode, ast, sourceMapChain } = source; const { code, originalCode, originalSourceMap, ast, sourceMapChain } = source;
const module = new Module({ id, code, originalCode, ast, sourceMapChain, bundle: this }); const module = new Module({ id, code, originalCode, originalSourceMap, ast, sourceMapChain, bundle: this });
this.modules.push( module ); this.modules.push( module );
this.moduleById.set( id, module ); this.moduleById.set( id, module );
@ -342,10 +341,11 @@ export default class Bundle {
let file = options.sourceMapFile || options.dest; let file = options.sourceMapFile || options.dest;
if ( file ) file = resolve( typeof process !== 'undefined' ? process.cwd() : '', file ); if ( file ) file = resolve( typeof process !== 'undefined' ? process.cwd() : '', file );
map = magicString.generateMap({ file, includeContent: true }); if ( this.hasLoaders || this.transformers.length || this.bundleTransformers.length ) {
map = magicString.generateMap( {} );
if ( this.transformers.length || this.bundleTransformers.length ) { map = collapseSourcemaps( file, map, usedModules, bundleSourcemapChain );
map = collapseSourcemaps( map, usedModules, bundleSourcemapChain ); } else {
map = magicString.generateMap({ file, includeContent: true });
} }
map.sources = map.sources.map( unixizePath ); map.sources = map.sources.map( unixizePath );

3
src/Module.js

@ -17,9 +17,10 @@ import { emptyBlockStatement } from './ast/create.js';
import extractNames from './ast/extractNames.js'; import extractNames from './ast/extractNames.js';
export default class Module { export default class Module {
constructor ({ id, code, originalCode, ast, sourceMapChain, bundle }) { constructor ({ id, code, originalCode, originalSourceMap, ast, sourceMapChain, bundle }) {
this.code = code; this.code = code;
this.originalCode = originalCode; this.originalCode = originalCode;
this.originalSourceMap = originalSourceMap;
this.sourceMapChain = sourceMapChain; this.sourceMapChain = sourceMapChain;
this.bundle = bundle; this.bundle = bundle;

1
src/rollup.js

@ -28,6 +28,7 @@ const ALLOWED_KEYS = [
'plugins', 'plugins',
'preferConst', 'preferConst',
'sourceMap', 'sourceMap',
'sourceMapFile',
'targets', 'targets',
'treeshake', 'treeshake',
'useStrict' 'useStrict'

75
src/utils/collapseSourcemaps.js

@ -1,13 +1,15 @@
import { encode, decode } from 'sourcemap-codec'; import { encode, decode } from 'sourcemap-codec';
import { dirname, relative, resolve } from './path.js';
class Source { class Source {
constructor ( index ) { constructor ( filename, content ) {
this.isOriginal = true; this.isOriginal = true;
this.index = index; this.filename = filename;
this.content = content;
} }
traceSegment ( line, column, name ) { traceSegment ( line, column, name ) {
return { line, column, name, index: this.index }; return { line, column, name, source: this };
} }
} }
@ -21,7 +23,7 @@ class Link {
} }
traceMappings () { traceMappings () {
let names = []; let sources = [], sourcesContent = [], names = [];
const mappings = this.mappings.map( line => { const mappings = this.mappings.map( line => {
let tracedLine = []; let tracedLine = [];
@ -31,14 +33,28 @@ class Link {
const traced = source.traceSegment( segment[2], segment[3], this.names[ segment[4] ] ); const traced = source.traceSegment( segment[2], segment[3], this.names[ segment[4] ] );
if ( traced ) { if ( traced ) {
let nameIndex = null; let sourceIndex = null, nameIndex = null;
segment = [ segment = [
segment[0], segment[0],
traced.index, null,
traced.line, traced.line,
traced.column traced.column
]; ];
// newer sources are more likely to be used, so search backwards.
sourceIndex = sources.lastIndexOf( traced.source.filename );
if ( sourceIndex === -1 ) {
sourceIndex = sources.length;
sources.push( traced.source.filename );
sourcesContent[ sourceIndex ] = traced.source.content;
} else if ( sourcesContent[ sourceIndex ] == null ) {
sourcesContent[ sourceIndex ] = traced.source.content;
} else if ( traced.source.content != null && sourcesContent[ sourceIndex ] !== traced.source.content ) {
throw new Error( `Multiple conflicting contents for sourcemap source ${source.filename}` );
}
segment[1] = sourceIndex;
if ( traced.name ) { if ( traced.name ) {
nameIndex = names.indexOf( traced.name ); nameIndex = names.indexOf( traced.name );
if ( nameIndex === -1 ) { if ( nameIndex === -1 ) {
@ -56,7 +72,7 @@ class Link {
return tracedLine; return tracedLine;
}); });
return { names, mappings }; return { sources, sourcesContent, names, mappings };
} }
traceSegment ( line, column, name ) { traceSegment ( line, column, name ) {
@ -81,29 +97,58 @@ class Link {
} }
} }
export default function collapseSourcemaps ( map, modules, bundleSourcemapChain ) { export default function collapseSourcemaps ( file, map, modules, bundleSourcemapChain ) {
const sources = modules.map( ( module, i ) => { const moduleSources = modules.map( module => {
let source = new Source( i ); let sourceMapChain = module.sourceMapChain;
let source;
if ( module.originalSourceMap == null ) {
source = new Source( module.id, module.originalCode );
} else {
const sources = module.originalSourceMap.sources;
const sourcesContent = module.originalSourceMap.sourcesContent || [];
if ( sources == null || ( sources.length <= 1 && sources[0] == null ) ) {
source = new Source( module.id, sourcesContent[0] );
sourceMapChain = [ module.originalSourceMap ].concat( sourceMapChain );
} else {
// TODO indiscriminately treating IDs and sources as normal paths is probably bad.
const directory = dirname( module.id ) || '.';
const sourceRoot = module.originalSourceMap.sourceRoot || '.';
const baseSources = sources.map( (source, i) => {
return new Source( resolve( directory, sourceRoot, source ), sourcesContent[i] );
});
source = new Link( module.originalSourceMap, baseSources );
}
}
module.sourceMapChain.forEach( map => { sourceMapChain.forEach( map => {
source = new Link( map, [ source ]); source = new Link( map, [ source ]);
}); });
return source; return source;
}); });
let source = new Link( map, sources ); let source = new Link( map, moduleSources );
bundleSourcemapChain.forEach( map => { bundleSourcemapChain.forEach( map => {
source = new Link( map, [ source ] ); source = new Link( map, [ source ] );
}); });
const { names, mappings } = source.traceMappings(); let { sources, sourcesContent, names, mappings } = source.traceMappings();
if ( file ) {
const directory = dirname( file );
sources = sources.map( source => relative( directory, source ) );
}
// we re-use the `map` object because it has convenient toString/toURL methods // we re-use the `map` object because it has convenient toString/toURL methods
map.sourcesContent = modules.map( module => module.originalCode ); map.sources = sources;
map.mappings = encode( mappings ); map.sourcesContent = sourcesContent;
map.names = names; map.names = names;
map.mappings = encode( mappings );
return map; return map;
} }

4
src/utils/transform.js

@ -1,6 +1,8 @@
export default function transform ( source, id, transformers ) { export default function transform ( source, id, transformers ) {
let sourceMapChain = []; let sourceMapChain = [];
const originalSourceMap = typeof source.map === 'string' ? JSON.parse( source.map ) : source.map;
let originalCode = source.code; let originalCode = source.code;
let ast = source.ast; let ast = source.ast;
@ -30,7 +32,7 @@ export default function transform ( source, id, transformers ) {
}, Promise.resolve( source.code ) ) }, Promise.resolve( source.code ) )
.then( code => ({ code, originalCode, ast, sourceMapChain }) ) .then( code => ({ code, originalCode, originalSourceMap, ast, sourceMapChain }) )
.catch( err => { .catch( err => {
err.id = id; err.id = id;
err.message = `Error loading ${id}: ${err.message}`; err.message = `Error loading ${id}: ${err.message}`;

2
src/utils/transformBundle.js

@ -11,7 +11,7 @@ export default function transformBundle ( code, transformers, sourceMapChain ) {
}; };
} }
const map = typeof result.map === 'string' ? JSON.parse( result.map ) : map; const map = typeof result.map === 'string' ? JSON.parse( result.map ) : result.map;
sourceMapChain.push( map ); sourceMapChain.push( map );
return result.code; return result.code;

63
test/sourcemaps/loaders/_config.js

@ -0,0 +1,63 @@
var babel = require( 'babel-core' );
var fs = require( 'fs' );
var assert = require( 'assert' );
var getLocation = require( '../../utils/getLocation' );
var SourceMapConsumer = require( 'source-map' ).SourceMapConsumer;
module.exports = {
description: 'preserves sourcemap chains when transforming',
options: {
plugins: [
{
load: function ( id ) {
if ( /foo.js$/.test( id ) ) {
id = id.replace( /foo.js$/, 'bar.js' );
} else if ( /bar.js$/.test( id ) ) {
id = id.replace( /bar.js$/, 'foo.js' );
}
var out = babel.transformFileSync( id, {
blacklist: [ 'es6.modules' ],
sourceMap: true,
comments: false // misalign the columns
});
if ( /main.js$/.test( id ) ) {
delete out.map.sources;
} else {
const slash = out.map.sources[0].lastIndexOf( '/' ) + 1;
out.map.sources = out.map.sources.map( source => '../' + source.slice( slash ) );
out.map.sourceRoot = 'fake';
}
return { code: out.code, map: out.map };
}
}
]
},
test: function ( code, map ) {
var smc = new SourceMapConsumer( map );
var generatedLoc = getLocation( code, code.indexOf( '22' ) );
var originalLoc = smc.originalPositionFor( generatedLoc );
assert.equal( originalLoc.source, '../foo.js' );
assert.equal( originalLoc.line, 1 );
assert.equal( originalLoc.column, 32 );
var generatedLoc = getLocation( code, code.indexOf( '20' ) );
var originalLoc = smc.originalPositionFor( generatedLoc );
assert.equal( originalLoc.source, '../bar.js' );
assert.equal( originalLoc.line, 1 );
assert.equal( originalLoc.column, 37 );
generatedLoc = getLocation( code, code.indexOf( 'log' ) );
originalLoc = smc.originalPositionFor( generatedLoc );
assert.equal( originalLoc.source, '../main.js' );
assert.ok( /columns/.test( smc.sourceContentFor( '../main.js' ) ) );
assert.equal( originalLoc.line, 4 );
assert.equal( originalLoc.column, 19 );
}
};

1
test/sourcemaps/loaders/bar.js

@ -0,0 +1 @@
/*misalign*/export const foo = () => 20;

1
test/sourcemaps/loaders/foo.js

@ -0,0 +1 @@
/*the*/export const bar = () => 22;

4
test/sourcemaps/loaders/main.js

@ -0,0 +1,4 @@
import { foo } from './foo';
import { bar } from './bar';
/*columns*/console.log( `the answer is ${foo() + bar()}` );

2
test/test.js

@ -76,7 +76,7 @@ describe( 'rollup', function () {
return rollup.rollup({ entry: 'x', plUgins: [] }).then( function () { return rollup.rollup({ entry: 'x', plUgins: [] }).then( function () {
throw new Error( 'Missing expected error' ); throw new Error( 'Missing expected error' );
}, function ( err ) { }, function ( err ) {
assert.equal( err.message, 'Unexpected key \'plUgins\' found, expected one of: acorn, banner, cache, dest, entry, exports, external, footer, format, globals, indent, intro, moduleId, moduleName, noConflict, onwarn, outro, plugins, preferConst, sourceMap, targets, treeshake, useStrict' ); assert.equal( err.message, 'Unexpected key \'plUgins\' found, expected one of: acorn, banner, cache, dest, entry, exports, external, footer, format, globals, indent, intro, moduleId, moduleName, noConflict, onwarn, outro, plugins, preferConst, sourceMap, sourceMapFile, targets, treeshake, useStrict' );
}); });
}); });
}); });

Loading…
Cancel
Save