Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSM: Update rollup examples config to merge and convert files #16920

Closed
wants to merge 10 commits into from
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"google-closure-compiler": "20190729.0.0",
"http-server": "^0.11.1",
"qunit": "^2.9.2",
"glob": "^7.1.4",
"rollup": "^1.19.4",
"typescript": "^3.5.3",
"rollup-plugin-buble": "^0.19.8"
Expand Down
202 changes: 161 additions & 41 deletions rollup-examples.config.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,159 @@
var path = require( 'path' );
var fs = require( 'fs' );
var glob = require('glob');

// Creates a rollup config object for the given file to
// be converted to umd
function createOutput( file ) {
var libsDir = path.resolve( 'examples/jsm/libs/' );
var sourceDir = path.resolve( 'examples/jsm/' );
var outputDir = path.resolve( 'examples/js/' );

var inputPath = path.resolve( file );
var outputPath = inputPath.replace( /[\\\/]examples[\\\/]jsm[\\\/]/, '/examples/js/' );
// How to merge output files.
// "input": Which jsm file to process.
// "output": The name and location to output the resultant UMD file.
// "paths": Which files should be merged into the file. Any other files
// not in the list will be considered external.
var mergedFiles = [{

// Every import is marked as external so the output is 1-to-1. We
// assume that that global object should be the THREE object so we
// replicate the existing behavior.
return {
input: 'postprocessing/EffectComposer.js',
output: 'postprocessing/EffectComposer.js',
paths: [
'postprocessing/Pass.js',
]

input: inputPath,
treeshake: false,
external: p => p !== inputPath,
}];

// A map of processed files to the output file that they have been rolled up
// in so references can be corrected.
var fileToOutput = {};

// Plugin to convert the dfeault "three_module_js" variable name to THREE.
var threeGlobalPlugin = {

generateBundle: function ( options, bundle ) {

for ( var key in bundle ) {

bundle[ key ].code = bundle[ key ].code.replace( /three_module_js/g, 'THREE' );

}

}

};

createOutputFileMap();

// Generate the configs for every merged output and individual file not
// covered in a merged file.
var configs = [];

mergedFiles.forEach( mergedFileInfo => {

configs.push( createMergedFileConfig( mergedFileInfo ) );

} );

glob.sync( path.join( sourceDir, '**/*.js' ) )
.forEach( p => {

p = path.normalize( p );

if ( ! isLibrary( p ) && ! ( p in fileToOutput ) ) {

configs.push( createSingleFileConfig( p ) );

}

} );

export default configs;

function isLibrary( depPath ) {

return depPath.indexOf( libsDir ) === 0;

}

// Resolve which global variable to reference for a given depdency. If a dependency is
// a library we assume it comes from "window" otherwise it is expected to be on "THREE".
function resolveGlobalObject( depPath ) {

if ( isLibrary( depPath ) ) {

return 'window';

} else {

return 'THREE';

}

}

function resolveDependencyPath( depPath, inputPath ) {

if ( /three\.module\.js$/.test( depPath ) ) {

plugins: [ {
// If importing three.js
return 'three';

generateBundle: function ( options, bundle ) {
} else if ( depPath in fileToOutput ) {

for ( var key in bundle ) {
// If the file is included in a merged file
return path.relative( inputPath, fileToOutput[ depPath ] ) ;

bundle[ key ].code = bundle[ key ].code.replace( /three_module_js/g, 'THREE' );
} else {

}
return path.relative( inputPath, depPath );

}
}

} ],
}

// Generate the map the stores the name of each file to the file it is merged into.
function createOutputFileMap() {

mergedFiles.forEach( mergedFileInfo => {

const paths = mergedFileInfo.paths;
const output = mergedFileInfo.output;
paths.forEach( depPath => {

glob.sync( path.join( sourceDir, depPath ) ).forEach( fullPath => {

fullPath = path.normalize( fullPath );

fileToOutput[ fullPath ] = path.join( outputDir, output );

} );

} );

} );

}

function createMergedFileConfig( mergedFileInfo ) {

const inputPath = path.join( sourceDir, mergedFileInfo.input );
const outputPath = path.join( outputDir, mergedFileInfo.output );
const internalFiles = [ mergedFileInfo.input, ...mergedFileInfo.paths ].map( p => path.join( sourceDir, p ) );

return {

input: inputPath,
treeshake: false,
external: p => ! internalFiles.includes( p ),

plugins: [ threeGlobalPlugin ],

output: {

format: 'umd',
name: 'THREE',
file: outputPath,
indent: false,

globals: () => 'THREE',
paths: p => /three\.module\.js$/.test( p ) ? 'three' : p,
globals: p => resolveGlobalObject( p ),
paths: p => resolveDependencyPath( p, inputPath ),
extend: true,

banner:
Expand All @@ -53,33 +168,38 @@ function createOutput( file ) {

}

// Walk the file structure starting at the given directory and fire
// the callback for every js file.
function walk( dir, cb ) {
function createSingleFileConfig( inputPath ) {

var files = fs.readdirSync( dir );
files.forEach( f => {
var relativePath = path.relative( sourceDir, inputPath );
var outputPath = path.join( outputDir, relativePath );

var p = path.join( dir, f );
var stats = fs.statSync( p );
return {

if ( stats.isDirectory() ) {
input: inputPath,
treeshake: false,
external: p => p !== inputPath,

walk( p, cb );
plugins: [ threeGlobalPlugin ],

} else if ( f.endsWith( '.js' ) ) {
output: {

cb( p );
format: 'umd',
name: 'THREE',
file: outputPath,
indent: false,

}
globals: p => resolveGlobalObject( p ),
paths: p => resolveDependencyPath( p, inputPath ),
extend: true,

} );
banner:
'/**\n' +
` * Generated from '${ path.relative( '.', inputPath ).replace( /\\/g, '/' ) }'\n` +
' */\n',
esModule: false

}
}

// Gather up all the files
var files = [];
walk( 'examples/jsm/', p => files.push( p ) );
};

// Create a rollup config for each module.js file
export default files.map( p => createOutput( p ) );
}