Browse Source

oh man, never run git reset HEAD while you have unmerged paths. chaos

contingency-plan
Rich-Harris 10 years ago
parent
commit
f873e70ff5
  1. 1
      .gitignore
  2. 25
      CHANGELOG.md
  3. 15
      README.md
  4. 7
      bin/runRollup.js
  5. 5
      package.json
  6. 20
      src/Bundle.js
  7. 2
      src/Module.js
  8. 15
      src/Statement.js
  9. 7
      src/finalisers/amd.js
  10. 25
      src/finalisers/es6.js
  11. 29
      src/finalisers/iife.js
  12. 24
      src/finalisers/umd.js
  13. 32
      src/rollup.js
  14. 5
      src/utils/ensureArray.js
  15. 10
      src/utils/load.js
  16. 53
      src/utils/resolvePath.js

1
.gitignore

@ -2,3 +2,4 @@
node_modules
.gobble*
dist
_actual

25
CHANGELOG.md

@ -1,5 +1,30 @@
# rollup changelog
## 0.6.4
* Fix CJS bundling with default export
## 0.6.3
* Fix exports and external module imports with some output formats
* Fix endless cycle bug on Windows ([#3](https://github.com/rollup/rollup/pull/3)) - thanks @Bobris
## 0.6.2
* Permit assignments to properties of imported bindings
## 0.6.1
* Support for basic transformers
## 0.6.0
* BREAKING - `rollup.rollup` and `bundle.write` both take a single options argument
* BREAKING - external modules must be declared upfront with `options.external: [...]`
* Non-relative module paths will be resolved by looking for `jsnext:main` fields in the appropriate `package.json` files. This behaviour can be overridden by passing an alternative `resolveExternal` function
* Fix sourcemap options
* Include CLI files in npm package (duh)
## 0.5.0
* Command line interface

15
README.md

@ -91,14 +91,13 @@ This is not a trivial task. There are almost certainly a great many complex edge
The example below is aspirational. It isn't yet implemented - it exists in the name of [README driven development](http://tom.preston-werner.com/2010/08/23/readme-driven-development.html).
```js
rollup.rollup( 'app.js', {
// Override the default path resolution
resolvePath: function ( importee, importer ) {
// return a string or a falsy value - if falsy,
// import is kept external to the bundle.
// Alternative, return a Promise that fulfils
// with a string or falsy value
}
rollup.rollup({
// The bundle's starting point
entry: 'app.js',
// Any external modules you don't want to include
// in the bundle (includes node built-ins)
external: [ 'path', 'fs', 'some-other-lib' ]
}).then( function ( bundle ) {
// generate code and a sourcemap
const { code, map } = bundle.generate({

7
bin/runRollup.js

@ -33,13 +33,16 @@ function bundle ( options, method ) {
handleError({ code: 'MISSING_INPUT_OPTION' });
}
return rollup.rollup( options.input ).then( function ( bundle ) {
return rollup.rollup({
entry: options.input
}).then( function ( bundle ) {
var generateOptions = {
dest: options.output,
format: options.format
};
if ( options.output ) {
return bundle.write( options.output, generateOptions );
return bundle.write( generateOptions );
}
if ( options.sourcemap && options.sourcemap !== 'inline' ) {

5
package.json

@ -1,6 +1,6 @@
{
"name": "rollup",
"version": "0.5.0",
"version": "0.6.4",
"description": "Next-generation ES6 module bundler",
"main": "dist/rollup.js",
"jsnext:main": "src/rollup.js",
@ -37,7 +37,7 @@
"gobble-babel": "^5.1.0",
"gobble-cli": "^0.4.2",
"gobble-esperanto-bundle": "^0.2.0",
"gobble-rollup": "^0.1.1",
"gobble-rollup": "^0.2.0",
"mocha": "^2.2.4",
"source-map-support": "^0.2.10",
"source-map": "^0.1.40"
@ -52,6 +52,7 @@
"files": [
"src",
"dist",
"bin",
"README.md"
]
}

20
src/Bundle.js

@ -6,7 +6,9 @@ import Module from './Module';
import ExternalModule from './ExternalModule';
import finalisers from './finalisers/index';
import makeLegalIdentifier from './utils/makeLegalIdentifier';
import { defaultResolver } from './utils/resolvePath';
import ensureArray from './utils/ensureArray';
import { defaultResolver, defaultExternalResolver } from './utils/resolvePath';
import { defaultLoader } from './utils/load';
function badExports ( option, keys ) {
throw new Error( `'${option}' was specified for options.exports, but entry module has following exports: ${keys.join(', ')}` );
@ -18,17 +20,26 @@ export default class Bundle {
this.base = dirname( this.entryPath );
this.resolvePath = options.resolvePath || defaultResolver;
this.load = options.load || defaultLoader;
this.resolvePathOptions = {
external: ensureArray( options.external ),
resolveExternal: options.resolveExternal || defaultExternalResolver
};
this.loadOptions = {
transform: ensureArray( options.transform )
};
this.entryModule = null;
this.modulePromises = {};
this.statements = [];
this.externalModules = [];
this.defaultExportName = null;
this.internalNamespaceModules = [];
}
fetchModule ( importee, importer ) {
return Promise.resolve( importer === null ? importee : this.resolvePath( importee, importer ) )
return Promise.resolve( importer === null ? importee : this.resolvePath( importee, importer, this.resolvePathOptions ) )
.then( path => {
if ( !path ) {
// external module
@ -42,7 +53,7 @@ export default class Bundle {
}
if ( !has( this.modulePromises, path ) ) {
this.modulePromises[ path ] = readFile( path, { encoding: 'utf-8' })
this.modulePromises[ path ] = Promise.resolve( this.load( path, this.loadOptions ) )
.then( source => {
const module = new Module({
path,
@ -85,7 +96,6 @@ export default class Bundle {
this.statements = statements;
this.deconflict();
});
}
deconflict () {

2
src/Module.js

@ -19,7 +19,6 @@ export default class Module {
this.bundle = bundle;
this.path = path;
this.relativePath = relative( bundle.base, path ).slice( 0, -3 ); // remove .js
this.magicString = new MagicString( source, {
filename: path
@ -40,6 +39,7 @@ export default class Module {
walk( ast, {
enter: node => {
this.magicString.addSourcemapLocation( node.start );
this.magicString.addSourcemapLocation( node.end );
}
});

15
src/Statement.js

@ -156,17 +156,30 @@ export default class Statement {
checkForWrites ( scope, node ) {
const addNode = ( node, disallowImportReassignments ) => {
let depth = 0; // determine whether we're illegally modifying a binding or namespace
while ( node.type === 'MemberExpression' ) {
node = node.object;
depth += 1;
}
// disallow assignments/updates to imported bindings and namespaces
if ( disallowImportReassignments && has( this.module.imports, node.name ) && !scope.contains( node.name ) ) {
if ( disallowImportReassignments ) {
const importSpecifier = this.module.imports[ node.name ];
if ( importSpecifier && !scope.contains( node.name ) ) {
const minDepth = importSpecifier.name === '*' ?
2 : // cannot do e.g. `namespace.foo = bar`
1; // cannot do e.g. `foo = bar`, but `foo.bar = bar` is fine
if ( depth < minDepth ) {
const err = new Error( `Illegal reassignment to import '${node.name}'` );
err.file = this.module.path;
err.loc = getLocation( this.module.magicString.toString(), node.start );
throw err;
}
}
}
if ( node.type !== 'Identifier' ) {
return;

7
src/finalisers/amd.js

@ -23,13 +23,16 @@ export default function amd ( bundle, magicString, exportMode, options ) {
if ( exportMode === 'default' ) {
exportBlock = `return ${bundle.entryModule.getCanonicalName('default')};`;
} else {
exportBlock = '\n\n' + Object.keys( exports ).map( name => {
exportBlock = Object.keys( exports ).map( name => {
return `exports.${name} = ${exports[name].localName};`;
}).join( '\n' );
}
if ( exportBlock ) {
magicString.append( '\n\n' + exportBlock );
}
return magicString
.append( exportBlock )
.trim()
.indent()
.append( '\n\n});' )

25
src/finalisers/es6.js

@ -1,7 +1,26 @@
import { keys } from '../utils/object';
export default function es6 ( bundle, magicString, exportMode, options ) {
// TODO
const introBlock = '';
const exportBlock = '';
const introBlock = ''; // TODO...
const exports = bundle.entryModule.exports;
const exportBlock = keys( exports ).map( exportedName => {
const specifier = exports[ exportedName ];
const canonicalName = bundle.entryModule.getCanonicalName( specifier.localName );
if ( exportedName === 'default' ) {
return `export default ${canonicalName};`;
}
return exportedName === canonicalName ?
`export { ${exportedName} };` :
`export { ${canonicalName} as ${exportedName} };`;
}).join( '\n' );
if ( exportBlock ) {
magicString.append( '\n\n' + exportBlock );
}
return magicString.trim();
}

29
src/finalisers/iife.js

@ -1,10 +1,33 @@
import { has } from '../utils/object';
import { getName } from '../utils/map-helpers';
export default function iife ( bundle, magicString, exportMode, options ) {
const globalNames = options.globals || {};
let dependencies = bundle.externalModules.map( module => {
return has( globalNames, module.id ) ? globalNames[ module.id ] : module.name;
});
let args = bundle.externalModules.map( getName );
if ( exportMode !== 'none' && !options.moduleName ) {
throw new Error( 'You must supply options.moduleName for IIFE bundles' );
}
const intro = `(function () { 'use strict';\n\n`;
const outro = `\n\n})();`;
if ( exportMode === 'named' ) {
dependencies.unshift( `(window.${options.moduleName} = {})` );
args.unshift( 'exports' );
}
let intro = `(function (${args}) { 'use strict';\n\n`;
let outro = `\n\n})(${dependencies});`;
if ( exportMode === 'default' ) {
intro = `var ${options.moduleName} = ${intro}`;
magicString.append( `\n\nreturn ${bundle.entryModule.getCanonicalName('default')};` );
}
return magicString
.trim()
.indent()
.prepend( intro )
.append( outro );

24
src/finalisers/umd.js

@ -26,23 +26,37 @@ export default function umd ( bundle, magicString, exportMode, options ) {
( has( options, 'moduleId' ) ? `['${options.moduleId}'], ` : `` ) +
( amdDeps.length ? `[${amdDeps.join( ', ' )}], ` : `` );
const cjsExport = exportMode === 'default' ? `module.exports = ` : ``;
const defaultExport = exportMode === 'default' ? `global.${options.moduleName} = ` : '';
const intro =
`(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(${cjsDeps.join( ', ' )}) :
typeof exports === 'object' && typeof module !== 'undefined' ? ${cjsExport}factory(${cjsDeps.join( ', ' )}) :
typeof define === 'function' && define.amd ? define(${amdParams}factory) :
factory(${globalDeps});
${defaultExport}factory(${globalDeps});
}(this, function (${args}) { 'use strict';
`.replace( /^\t\t/gm, '' ).replace( /^\t/gm, indentStr );
const exports = bundle.entryModule.exports;
const exportBlock = '\n\n' + Object.keys( exports ).map( name => {
return `exports.${name} = ${exports[name].localName};`;
let exportBlock;
if ( exportMode === 'default' ) {
const canonicalName = bundle.entryModule.getCanonicalName( 'default' );
exportBlock = `return ${canonicalName};`;
} else {
exportBlock = Object.keys( exports ).map( name => {
const canonicalName = bundle.entryModule.getCanonicalName( exports[ name ].localName );
return `exports.${name} = ${canonicalName};`;
}).join( '\n' );
}
if ( exportBlock ) {
magicString.append( '\n\n' + exportBlock );
}
return magicString
.append( exportBlock )
.trim()
.indent()
.append( '\n\n}));' )

32
src/rollup.js

@ -5,28 +5,25 @@ import Bundle from './Bundle';
let SOURCEMAPPING_URL = 'sourceMa';
SOURCEMAPPING_URL += 'ppingURL';
export function rollup ( entry, options = {} ) {
const bundle = new Bundle({
entry,
resolvePath: options.resolvePath
});
export function rollup ( options ) {
if ( !options || !options.entry ) {
throw new Error( 'You must supply options.entry to rollup' );
}
const bundle = new Bundle( options );
return bundle.build().then( () => {
return {
generate: options => bundle.generate( options ),
write: ( dest, options = {} ) => {
let { code, map } = bundle.generate({
dest,
format: options.format,
globalName: options.globalName,
// sourcemap options
sourceMap: !!options.sourceMap,
sourceMapFile: options.sourceMapFile,
// sourceMapRoot: options.sourceMapRoot
});
write: options => {
if ( !options || !options.dest ) {
throw new Error( 'You must supply options.dest to bundle.write' );
}
const dest = options.dest;
let { code, map } = bundle.generate( options );
let promises = [ writeFile( dest, code ) ];
let promises = [];
if ( options.sourceMap ) {
let url;
@ -41,6 +38,7 @@ export function rollup ( entry, options = {} ) {
code += `\n//# ${SOURCEMAPPING_URL}=${url}`;
}
promises.push( writeFile( dest, code ) );
return Promise.all( promises );
}
};

5
src/utils/ensureArray.js

@ -0,0 +1,5 @@
export default function ensureArray ( thing ) {
if ( Array.isArray( thing ) ) return thing;
if ( thing == undefined ) return [];
return [ thing ];
}

10
src/utils/load.js

@ -0,0 +1,10 @@
import { readFileSync } from 'sander';
export function defaultLoader ( path, options ) {
// TODO support plugins e.g. !css and !json?
const source = readFileSync( path, { encoding: 'utf-8' });
return options.transform.reduce( ( source, transformer ) => {
return transformer( source, path );
}, source );
}

53
src/utils/resolvePath.js

@ -1,11 +1,56 @@
import { dirname, isAbsolute, resolve } from 'path';
import { dirname, isAbsolute, resolve, parse } from 'path';
import { readFileSync } from 'sander';
export function defaultResolver ( importee, importer ) {
export function defaultResolver ( importee, importer, options ) {
// absolute paths are left untouched
if ( isAbsolute( importee ) ) return importee;
// external modules stay external
if ( importee[0] !== '.' ) return false;
// we try to resolve external modules
if ( importee[0] !== '.' ) {
// unless we want to keep it external, that is
if ( ~options.external.indexOf( importee ) ) return null;
return options.resolveExternal( importee, importer, options );
}
return resolve( dirname( importer ), importee ).replace( /\.js$/, '' ) + '.js';
}
export function defaultExternalResolver ( id, importer, options ) {
// for now, only node_modules is supported, and only jsnext:main
let parsed = parse( importer );
let dir = parsed.dir;
while ( dir !== parsed.root ) {
const pkgPath = resolve( dir, 'node_modules', id, 'package.json' );
let pkgJson;
try {
pkgJson = readFileSync( pkgPath ).toString();
} catch ( err ) {
// noop
}
if ( pkgJson ) {
let pkg;
try {
pkg = JSON.parse( pkgJson );
} catch ( err ) {
throw new Error( `Malformed JSON: ${pkgPath}` );
}
const main = pkg[ 'jsnext:main' ];
if ( !main ) {
throw new Error( `Package ${id} does not have a jsnext:main field, and so cannot be included in your rollup. Try adding it as an external module instead (e.g. options.external = ['${id}']). See https://github.com/rollup/rollup/wiki/jsnext:main for more info` );
}
return resolve( dirname( pkgPath ), main ).replace( /\.js$/, '' ) + '.js';
}
dir = dirname( dir );
}
throw new Error( `Could not find package ${id} (required by ${importer})` );
}

Loading…
Cancel
Save