Browse Source

Merge pull request #698 from rollup/incremental-transform-b

Incremental rebuilds
ghi-672
Rich Harris 9 years ago
parent
commit
c95a78451b
  1. 20
      src/Bundle.js
  2. 23
      src/Module.js
  3. 6
      src/rollup.js
  4. 5
      test/incremental/not-transform-twice/expected.js
  5. 3
      test/incremental/not-transform-twice/foo.js
  6. 3
      test/incremental/not-transform-twice/main.js
  7. 5
      test/incremental/transform-changed/expected.js
  8. 3
      test/incremental/transform-changed/foo-changed.js
  9. 3
      test/incremental/transform-changed/foo.js
  10. 3
      test/incremental/transform-changed/main.js
  11. 115
      test/test.js

20
src/Bundle.js

@ -19,11 +19,11 @@ import { dirname, isRelative, isAbsolute, relative, resolve } from './utils/path
export default class Bundle { export default class Bundle {
constructor ( options ) { constructor ( options ) {
if ( typeof options.bundle === 'object' ) { this.cachedModules = new Map();
this.cachedModules = options.bundle.modules.reduce((modules, module) => { if ( options.cache ) {
modules[module.id] = module; options.cache.modules.forEach( module => {
return modules; this.cachedModules.set( module.id, module );
}, {}); });
} }
this.plugins = ensureArray( options.plugins ); this.plugins = ensureArray( options.plugins );
@ -195,13 +195,11 @@ export default class Bundle {
ast: null ast: null
}; };
} }
if (this.cachedModules && this.cachedModules[id] && this.cachedModules[id].originalCode === source.code) {
const { code, originalCode } = this.cachedModules[id]; if ( this.cachedModules.has( id ) && this.cachedModules.get( id ).originalCode === source.code ) {
return { return this.cachedModules.get( id );
code,
originalCode
};
} }
return transform( source, id, this.transformers ); return transform( source, id, this.transformers );
}) })
.then( source => { .then( source => {

23
src/Module.js

@ -53,7 +53,8 @@ export default class Module {
} }
this.comments = []; this.comments = [];
this.statements = this.parse( ast ); this.ast = ast;
this.statements = this.parse();
this.declarations = blank(); this.declarations = blank();
this.analyse(); this.analyse();
@ -298,13 +299,13 @@ export default class Module {
return this.declarations['*']; return this.declarations['*'];
} }
parse ( ast ) { parse () {
// The ast can be supplied programmatically (but usually won't be) // The ast can be supplied programmatically (but usually won't be)
if ( !ast ) { if ( !this.ast ) {
// Try to extract a list of top-level statements/declarations. If // Try to extract a list of top-level statements/declarations. If
// the parse fails, attach file info and abort // the parse fails, attach file info and abort
try { try {
ast = parse( this.code, { this.ast = parse( this.code, {
ecmaVersion: 6, ecmaVersion: 6,
sourceType: 'module', sourceType: 'module',
onComment: ( block, text, start, end ) => this.comments.push({ block, text, start, end }), onComment: ( block, text, start, end ) => this.comments.push({ block, text, start, end }),
@ -318,7 +319,7 @@ export default class Module {
} }
} }
walk( ast, { walk( this.ast, {
enter: node => { enter: node => {
// eliminate dead branches early // eliminate dead branches early
if ( node.type === 'IfStatement' ) { if ( node.type === 'IfStatement' ) {
@ -354,7 +355,7 @@ export default class Module {
let lastChar = 0; let lastChar = 0;
let commentIndex = 0; let commentIndex = 0;
ast.body.forEach( node => { this.ast.body.forEach( node => {
if ( node.type === 'EmptyStatement' ) return; if ( node.type === 'EmptyStatement' ) return;
if ( if (
@ -637,6 +638,16 @@ export default class Module {
return marked; return marked;
} }
toJSON () {
return {
id: this.id,
code: this.code,
originalCode: this.originalCode,
ast: this.ast,
sourceMapChain: this.sourceMapChain
};
}
trace ( name ) { trace ( name ) {
if ( name in this.declarations ) return this.declarations[ name ]; if ( name in this.declarations ) return this.declarations[ name ];
if ( name in this.imports ) { if ( name in this.imports ) {

6
src/rollup.js

@ -9,6 +9,7 @@ export const VERSION = '<@VERSION@>';
const ALLOWED_KEYS = [ const ALLOWED_KEYS = [
'banner', 'banner',
'cache',
'dest', 'dest',
'entry', 'entry',
'exports', 'exports',
@ -28,8 +29,7 @@ const ALLOWED_KEYS = [
'sourceMap', 'sourceMap',
'targets', 'targets',
'treeshake', 'treeshake',
'useStrict', 'useStrict'
'bundle'
]; ];
export function rollup ( options ) { export function rollup ( options ) {
@ -53,7 +53,7 @@ export function rollup ( options ) {
return { return {
imports: bundle.externalModules.map( module => module.id ), imports: bundle.externalModules.map( module => module.id ),
exports: keys( bundle.entryModule.exports ), exports: keys( bundle.entryModule.exports ),
modules: bundle.orderedModules.map( ( { id, code, originalCode } ) => ( { id, code, originalCode } ) ), modules: bundle.orderedModules.map( module => module.toJSON() ),
generate: options => bundle.render( options ), generate: options => bundle.render( options ),
write: options => { write: options => {

5
test/incremental/not-transform-twice/expected.js

@ -1,5 +0,0 @@
function foo () {
console.log('foo');
};
foo();

3
test/incremental/not-transform-twice/foo.js

@ -1,3 +0,0 @@
export default function () {
console.log('foo');
};

3
test/incremental/not-transform-twice/main.js

@ -1,3 +0,0 @@
import foo from './foo.js';
foo();

5
test/incremental/transform-changed/expected.js

@ -1,5 +0,0 @@
function foo () {
console.log('foo-changed');
};
foo();

3
test/incremental/transform-changed/foo-changed.js

@ -1,3 +0,0 @@
export default function () {
console.log('foo-changed');
};

3
test/incremental/transform-changed/foo.js

@ -1,3 +0,0 @@
export default function () {
console.log('foo');
};

3
test/incremental/transform-changed/main.js

@ -1,3 +0,0 @@
import foo from './foo.js';
foo();

115
test/test.js

@ -431,7 +431,7 @@ describe( 'rollup', function () {
}); });
done( error ); done( error );
} }
else { else {
var expected = sander.readFileSync( '_expected.js' ).toString(); var expected = sander.readFileSync( '_expected.js' ).toString();
try { try {
@ -448,76 +448,79 @@ describe( 'rollup', function () {
}); });
describe.only('incremental', function () { describe.only('incremental', function () {
it('does not transforms in the second time', function () { function executeBundle ( bundle ) {
var calls = 0; const cjs = bundle.generate({ format: 'cjs' });
var counter = { const m = new Function( 'module', 'exports', cjs.code );
transform: function ( code ) {
calls += 1; let module = { exports: {} };
return code; m( module, module.exports );
}
return module.exports;
}
var calls;
var modules;
var plugin = {
resolveId: id => id,
load: id => {
return modules[ id ];
},
transform: function ( code ) {
calls += 1;
return code;
}
};
beforeEach( () => {
calls = 0;
modules = {
entry: `import foo from 'foo'; export default foo;`,
foo: `export default 42`
}; };
});
it('does not transforms in the second time', function () {
return rollup.rollup({ return rollup.rollup({
entry: path.join( INCREMENTAL, 'not-transform-twice', 'main.js' ), entry: 'entry',
plugins: [counter] plugins: [ plugin ]
}).then( function ( bundle ) { }).then( bundle => {
assert.equal( calls, 2 ); assert.equal( calls, 2 );
return rollup.rollup({ return rollup.rollup({
entry: path.join( INCREMENTAL, 'not-transform-twice', 'main.js' ), entry: 'entry',
plugins: [counter], plugins: [ plugin ],
bundle cache: bundle
}); });
}).then( function ( bundle ) { }).then( bundle => {
assert.equal( calls, 2 ); assert.equal( calls, 2 );
var result = bundle.generate({ assert.equal( executeBundle( bundle ), 42 );
format: 'es6'
});
return sander.readFile( path.join( INCREMENTAL, 'not-transform-twice', 'expected.js' ) ).then( function (expected) {
assert.equal( normaliseOutput( expected ), result.code );
});
}); });
}); });
it('transforms modified sources', function () { it('transforms modified sources', function () {
var calls = 0; let cache;
var counter = {
transform: function ( code ) { return rollup.rollup({
calls += 1; entry: 'entry',
return code; plugins: [ plugin ]
} }).then( bundle => {
};
var bundle;
var foo;
var changed;
var expected;
return Promise.all([
rollup.rollup({
entry: path.join( INCREMENTAL, 'transform-changed', 'main.js' ),
plugins: [counter]
}),
sander.readFile( path.join( INCREMENTAL, 'transform-changed', 'foo.js' ) ),
sander.readFile( path.join( INCREMENTAL, 'transform-changed', 'foo-changed.js' ) ),
sander.readFile( path.join( INCREMENTAL, 'transform-changed', 'expected.js' ) )
]).then( function ( [_bundle, _foo, _changed, _expected] ) {
bundle = _bundle;
foo = normaliseOutput( _foo );
changed = normaliseOutput( _changed );
expected = normaliseOutput( _expected );
assert.equal( calls, 2 ); assert.equal( calls, 2 );
assert.equal( executeBundle( bundle ), 42 );
return sander.writeFile( INCREMENTAL, 'transform-changed', 'foo.js', changed ); modules.foo = `export default 43`;
}).then(function () { cache = bundle;
}).then( () => {
return rollup.rollup({ return rollup.rollup({
entry: path.join( INCREMENTAL, 'transform-changed', 'main.js' ), entry: 'entry',
plugins: [counter], plugins: [ plugin ],
bundle cache
}); });
}).then( function ( bundle ) { }).then( bundle => {
assert.equal( calls, 3 ); assert.equal( calls, 3 );
var result = bundle.generate({ assert.equal( executeBundle( bundle ), 43 );
format: 'es6'
});
assert.equal(expected, result.code);
return sander.writeFile( INCREMENTAL, 'transform-changed', 'foo.js', foo );
}); });
}); });
}); });

Loading…
Cancel
Save