Skip to content
This repository has been archived by the owner on Aug 4, 2021. It is now read-only.

Optimise wrappers (redux) #20

Merged
merged 4 commits into from
Dec 27, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
40 changes: 21 additions & 19 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ function getName ( id ) {
export default function commonjs ( options = {} ) {
const filter = createFilter( options.include, options.exclude );
let bundleUsesGlobal = false;
let bundleRequiresWrappers = false;

const sourceMap = options.sourceMap !== false;

Expand Down Expand Up @@ -70,8 +71,7 @@ export default function commonjs ( options = {} ) {

let scope = attachScopes( ast, 'scope' );
let namedExports = {};
let usesModuleOrExports;
let usesGlobal;
let uses = { module: false, exports: false, global: false };

walk( ast, {
enter ( node, parent ) {
Expand Down Expand Up @@ -108,8 +108,7 @@ export default function commonjs ( options = {} ) {
}

if ( node.type === 'Identifier' ) {
if ( ( node.name === 'module' || node.name === 'exports' ) && isReference( node, parent ) && !scope.contains( node.name ) ) usesModuleOrExports = true;
if ( node.name === 'global' && isReference( node, parent ) && !scope.contains( 'global' ) ) usesGlobal = true;
if ( ( node.name in uses && !uses[ node.name ] ) && isReference( node, parent ) && !scope.contains( node.name ) ) uses[ node.name ] = true;
return;
}

Expand Down Expand Up @@ -139,25 +138,20 @@ export default function commonjs ( options = {} ) {

const sources = Object.keys( required );

if ( !sources.length && !usesModuleOrExports && !usesGlobal ) return null; // not a CommonJS module
if ( !sources.length && !uses.module && !uses.exports && !uses.global ) return null; // not a CommonJS module

bundleRequiresWrappers = true;

const name = getName( id );

const importBlock = sources.length ?
sources.map( source => `import ${required[ source ].name} from '${source}';` ).join( '\n' ) :
'';

const intro = `

var ${name} = (function (module${usesGlobal ? ', global' : ''}) {
var exports = module.exports;
`;

let outro = `
return module.exports;
})({exports:{}}${usesGlobal ? ', __commonjs_global' : ''});
const args = `module${uses.exports || uses.global ? ', exports' : ''}${uses.global ? ', global' : ''}`;

export default (${name} && typeof ${name} === 'object' && 'default' in ${name} ? ${name}['default'] : ${name});\n`;
const intro = `\n\nvar ${name} = __commonjs(function (${args}) {\n`;
let outro = `\n});\n\nexport default (${name} && typeof ${name} === 'object' && 'default' in ${name} ? ${name}['default'] : ${name});\n`;

outro += Object.keys( namedExports )
.filter( key => !blacklistedExports[ key ] )
Expand All @@ -172,15 +166,23 @@ export default (${name} && typeof ${name} === 'object' && 'default' in ${name} ?
code = magicString.toString();
const map = sourceMap ? magicString.generateMap() : null;

if ( usesGlobal ) bundleUsesGlobal = true;
if ( uses.global ) bundleUsesGlobal = true;

return { code, map };
},

intro () {
return bundleUsesGlobal ?
`var __commonjs_global = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this;` :
'';
var intros = [];

if ( bundleUsesGlobal ) {
intros.push( `var __commonjs_global = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this;` );
}

if ( bundleRequiresWrappers ) {
intros.push( `function __commonjs(fn, module) { return module = { exports: {} }, fn(module, module.exports${bundleUsesGlobal ? ', __commonjs_global' : ''}), module.exports; }\n` );
}

return intros.join( '\n' );
}
};
}
108 changes: 26 additions & 82 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,58 +6,44 @@ var commonjs = require( '..' );

process.chdir( __dirname );

function executeBundle ( bundle ) {
var generated = bundle.generate({
format: 'cjs'
});

var fn = new Function ( 'module', 'assert', generated.code );
var module = {};

fn( module, assert );

return module;
}

describe( 'rollup-plugin-commonjs', function () {
it( 'converts a basic CommonJS module', function () {
return rollup.rollup({
entry: 'samples/basic/main.js',
plugins: [ commonjs() ]
}).then( function ( bundle ) {
var generated = bundle.generate({
format: 'cjs'
});

var fn = new Function ( 'module', generated.code );
var module = {};

fn( module );

assert.equal( module.exports, 42 );
})
assert.equal( executeBundle( bundle ).exports, 42 );
});
});

it( 'converts a CommonJS module that mutates exports instead of replacing', function () {
return rollup.rollup({
entry: 'samples/exports/main.js',
plugins: [ commonjs() ]
}).then( function ( bundle ) {
var generated = bundle.generate({
format: 'cjs'
});

var fn = new Function ( 'module', generated.code );
var module = {};

fn( module );

assert.equal( module.exports, 'BARBAZ' );
})
assert.equal( executeBundle( bundle ).exports, 'BARBAZ' );
});
});

it( 'converts inline require calls', function () {
return rollup.rollup({
entry: 'samples/inline/main.js',
plugins: [ commonjs() ]
}).then( function ( bundle ) {
var generated = bundle.generate({
format: 'cjs'
});

var fn = new Function ( 'module', generated.code );
var module = {};

fn( module );

assert.equal( module.exports(), 2 );
assert.equal( executeBundle( bundle ).exports(), 2 );
});
});

Expand All @@ -74,12 +60,12 @@ describe( 'rollup-plugin-commonjs', function () {

var smc = new SourceMapConsumer( generated.map );

var loc = smc.originalPositionFor({ line: 3, column: 17 }); // 42
var loc = smc.originalPositionFor({ line: 5, column: 17 }); // 42
assert.equal( loc.source, 'samples/sourcemap/foo.js' );
assert.equal( loc.line, 1 );
assert.equal( loc.column, 15 );

loc = smc.originalPositionFor({ line: 8, column: 8 });
loc = smc.originalPositionFor({ line: 9, column: 8 }); // log
assert.equal( loc.source, 'samples/sourcemap/main.js' );
assert.equal( loc.line, 2 );
assert.equal( loc.column, 8 );
Expand All @@ -90,28 +76,14 @@ describe( 'rollup-plugin-commonjs', function () {
return rollup.rollup({
entry: 'samples/index/main.js',
plugins: [ commonjs() ]
}).then( function ( bundle ) {
var generated = bundle.generate({
format: 'cjs'
});

var fn = new Function ( 'module', 'assert', generated.code );
fn( {}, assert );
});
}).then( executeBundle );
});

it( 'handles reassignments to imports', function () {
return rollup.rollup({
entry: 'samples/reassignment/main.js',
plugins: [ commonjs() ]
}).then( function ( bundle ) {
var generated = bundle.generate({
format: 'cjs'
});

var fn = new Function ( 'module', 'assert', generated.code );
fn( {}, assert );
});
}).then( executeBundle );
});

it( 'handles imports with a trailing slash', function () {
Expand All @@ -120,56 +92,28 @@ describe( 'rollup-plugin-commonjs', function () {
return rollup.rollup({
entry: 'samples/trailing-slash/main.js',
plugins: [ commonjs() ]
}).then( function ( bundle ) {
var generated = bundle.generate({
format: 'cjs'
});

var fn = new Function ( 'module', 'assert', generated.code );
fn( {}, assert );
});
}).then( executeBundle );
});

it( 'handles imports with a non-extension dot', function () {
return rollup.rollup({
entry: 'samples/dot/main.js',
plugins: [ commonjs() ]
}).then( function ( bundle ) {
var generated = bundle.generate({
format: 'cjs'
});

var fn = new Function ( 'module', 'assert', generated.code );
fn( {}, assert );
});
}).then( executeBundle );
});

it( 'handles shadowed require', function () {
return rollup.rollup({
entry: 'samples/shadowing/main.js',
plugins: [ commonjs() ]
}).then( function ( bundle ) {
var generated = bundle.generate({
format: 'cjs'
});

var fn = new Function ( 'module', 'assert', generated.code );
fn( {}, assert );
});
}).then( executeBundle );
});

it( 'identifies named exports', function () {
return rollup.rollup({
entry: 'samples/named-exports/main.js',
plugins: [ commonjs() ]
}).then( function ( bundle ) {
var generated = bundle.generate({
format: 'cjs'
});

var fn = new Function ( 'module', 'assert', generated.code );
fn( {}, assert );
});
}).then( executeBundle );
});

it( 'handles references to `global`', function () {
Expand Down