Browse Source

Merge pull request #658 from rollup/incremental-transform

WIP: Add incremental support build by passing previous bundle
ghi-672
Rich Harris 9 years ago
parent
commit
220f306f7e
  1. 22
      src/Bundle.js
  2. 23
      src/Module.js
  3. 5
      src/rollup.js
  4. 7
      src/utils/transform.js
  5. 81
      test/test.js

22
src/Bundle.js

@ -19,6 +19,13 @@ import { dirname, isRelative, isAbsolute, relative, resolve } from './utils/path
export default class Bundle {
constructor ( options ) {
this.cachedModules = new Map();
if ( options.cache ) {
options.cache.modules.forEach( module => {
this.cachedModules.set( module.id, module );
});
}
this.plugins = ensureArray( options.plugins );
this.plugins.forEach( plugin => {
@ -181,7 +188,20 @@ export default class Bundle {
throw new Error( `Error loading ${id}: load hook should return a string, a { code, map } object, or nothing/null` );
})
.then( source => transform( source, id, this.transformers ) )
.then( source => {
if ( typeof source === 'string' ) {
source = {
code: source,
ast: null
};
}
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 => {
const { code, originalCode, ast, sourceMapChain } = 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 ) {

5
src/rollup.js

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

7
src/utils/transform.js

@ -1,13 +1,6 @@
export default function transform ( source, id, transformers ) {
let sourceMapChain = [];
if ( typeof source === 'string' ) {
source = {
code: source,
ast: null
};
}
let originalCode = source.code;
let ast = source.ast;

81
test/test.js

@ -13,6 +13,7 @@ var FUNCTION = path.resolve( __dirname, 'function' );
var FORM = path.resolve( __dirname, 'form' );
var SOURCEMAPS = path.resolve( __dirname, 'sourcemaps' );
var CLI = path.resolve( __dirname, 'cli' );
var INCREMENTAL = path.resolve( __dirname, 'incremental' );
var PROFILES = [
{ format: 'amd' },
@ -430,7 +431,7 @@ describe( 'rollup', function () {
});
done( error );
}
else {
var expected = sander.readFileSync( '_expected.js' ).toString();
try {
@ -445,4 +446,82 @@ describe( 'rollup', function () {
});
});
});
describe.only('incremental', function () {
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: 'entry',
plugins: [ plugin ]
}).then( bundle => {
assert.equal( calls, 2 );
return rollup.rollup({
entry: 'entry',
plugins: [ plugin ],
cache: bundle
});
}).then( bundle => {
assert.equal( calls, 2 );
assert.equal( executeBundle( bundle ), 42 );
});
});
it('transforms modified sources', function () {
let cache;
return rollup.rollup({
entry: 'entry',
plugins: [ plugin ]
}).then( bundle => {
assert.equal( calls, 2 );
assert.equal( executeBundle( bundle ), 42 );
modules.foo = `export default 43`;
cache = bundle;
}).then( () => {
return rollup.rollup({
entry: 'entry',
plugins: [ plugin ],
cache
});
}).then( bundle => {
assert.equal( calls, 3 );
assert.equal( executeBundle( bundle ), 43 );
});
});
});
});

Loading…
Cancel
Save