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 {
constructor ( options ) {
if ( typeof options.bundle === 'object' ) {
this.cachedModules = options.bundle.modules.reduce((modules, module) => {
modules[module.id] = module;
return modules;
}, {});
this.cachedModules = new Map();
if ( options.cache ) {
options.cache.modules.forEach( module => {
this.cachedModules.set( module.id, module );
});
}
this.plugins = ensureArray( options.plugins );
@ -195,13 +195,11 @@ export default class Bundle {
ast: null
};
}
if (this.cachedModules && this.cachedModules[id] && this.cachedModules[id].originalCode === source.code) {
const { code, originalCode } = this.cachedModules[id];
return {
code,
originalCode
};
if ( this.cachedModules.has( id ) && this.cachedModules.get( id ).originalCode === source.code ) {
return this.cachedModules.get( id );
}
return transform( source, id, this.transformers );
})
.then( source => {

23
src/Module.js

@ -53,7 +53,8 @@ export default class Module {
}
this.comments = [];
this.statements = this.parse( ast );
this.ast = ast;
this.statements = this.parse();
this.declarations = blank();
this.analyse();
@ -298,13 +299,13 @@ export default class Module {
return this.declarations['*'];
}
parse ( ast ) {
parse () {
// 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
// the parse fails, attach file info and abort
try {
ast = parse( this.code, {
this.ast = parse( this.code, {
ecmaVersion: 6,
sourceType: 'module',
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 => {
// eliminate dead branches early
if ( node.type === 'IfStatement' ) {
@ -354,7 +355,7 @@ export default class Module {
let lastChar = 0;
let commentIndex = 0;
ast.body.forEach( node => {
this.ast.body.forEach( node => {
if ( node.type === 'EmptyStatement' ) return;
if (
@ -637,6 +638,16 @@ export default class Module {
return marked;
}
toJSON () {
return {
id: this.id,
code: this.code,
originalCode: this.originalCode,
ast: this.ast,
sourceMapChain: this.sourceMapChain
};
}
trace ( name ) {
if ( name in this.declarations ) return this.declarations[ name ];
if ( name in this.imports ) {

6
src/rollup.js

@ -9,6 +9,7 @@ export const VERSION = '<@VERSION@>';
const ALLOWED_KEYS = [
'banner',
'cache',
'dest',
'entry',
'exports',
@ -28,8 +29,7 @@ const ALLOWED_KEYS = [
'sourceMap',
'targets',
'treeshake',
'useStrict',
'bundle'
'useStrict'
];
export function rollup ( options ) {
@ -53,7 +53,7 @@ export function rollup ( options ) {
return {
imports: bundle.externalModules.map( module => module.id ),
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 ),
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 );
}
else {
var expected = sander.readFileSync( '_expected.js' ).toString();
try {
@ -448,76 +448,79 @@ describe( 'rollup', function () {
});
describe.only('incremental', function () {
it('does not transforms in the second time', function () {
var calls = 0;
var counter = {
transform: function ( code ) {
calls += 1;
return code;
}
function executeBundle ( bundle ) {
const cjs = bundle.generate({ format: 'cjs' });
const m = new Function( 'module', 'exports', cjs.code );
let module = { exports: {} };
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({
entry: path.join( INCREMENTAL, 'not-transform-twice', 'main.js' ),
plugins: [counter]
}).then( function ( bundle ) {
entry: 'entry',
plugins: [ plugin ]
}).then( bundle => {
assert.equal( calls, 2 );
return rollup.rollup({
entry: path.join( INCREMENTAL, 'not-transform-twice', 'main.js' ),
plugins: [counter],
bundle
entry: 'entry',
plugins: [ plugin ],
cache: bundle
});
}).then( function ( bundle ) {
}).then( bundle => {
assert.equal( calls, 2 );
var result = bundle.generate({
format: 'es6'
});
return sander.readFile( path.join( INCREMENTAL, 'not-transform-twice', 'expected.js' ) ).then( function (expected) {
assert.equal( normaliseOutput( expected ), result.code );
});
assert.equal( executeBundle( bundle ), 42 );
});
});
it('transforms modified sources', function () {
var calls = 0;
var counter = {
transform: function ( code ) {
calls += 1;
return code;
}
};
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 );
let cache;
return rollup.rollup({
entry: 'entry',
plugins: [ plugin ]
}).then( bundle => {
assert.equal( calls, 2 );
assert.equal( executeBundle( bundle ), 42 );
return sander.writeFile( INCREMENTAL, 'transform-changed', 'foo.js', changed );
}).then(function () {
modules.foo = `export default 43`;
cache = bundle;
}).then( () => {
return rollup.rollup({
entry: path.join( INCREMENTAL, 'transform-changed', 'main.js' ),
plugins: [counter],
bundle
entry: 'entry',
plugins: [ plugin ],
cache
});
}).then( function ( bundle ) {
}).then( bundle => {
assert.equal( calls, 3 );
var result = bundle.generate({
format: 'es6'
});
assert.equal(expected, result.code);
return sander.writeFile( INCREMENTAL, 'transform-changed', 'foo.js', foo );
assert.equal( executeBundle( bundle ), 43 );
});
});
});

Loading…
Cancel
Save