systemjs / builder

SystemJS build tool
MIT License
465 stars 122 forks source link

Suggestion: create bundles based on bundles section of config #793

Open benstevens48 opened 7 years ago

benstevens48 commented 7 years ago

I'm loading some modules dynamically so am using the bundles section of the config. I've decided that rather than write something complicated to populate this by tracing trees etc, I'd like to fill this in manually. It would then be quite useful if the builder had the option of creating output bundles containing exactly the modules in the bundles section of the config. This could be a method like bundle() or bundles() or something with no arguments. I guess you might want one argument which would be the base path for the output bundles.

As an extension, it would be useful if the bundles section supported wildcards/globbing. Ideally this would also support non-js files such as html during build by using the appropriate loader specified in the config.

aluanhaddad commented 7 years ago

Do you mean static builds?

benstevens48 commented 7 years ago

Basically I mean something that would automatically do the following: loop through keys in the bundles section of the systemjs config wich looks like { bundlePath: [module1, module2, ...], ... } and then for each key call builder.bundle([module1,module2,...], baseOutputPath + '/' + bundlePath) where baseOutputPath would be the single argument.

aluanhaddad commented 7 years ago

When you load the configuration file via the builder, the bundle configuration is available but it sounds like you want a package configuration rather bundle configuration.

benstevens48 commented 7 years ago

Perhaps some code would make what I'm trying to do clearer. Basically I'd like to be able to do the following more convienently.

const gulp = require('gulp');
const streamToPromise = require('stream-to-promise');
const concat = require('gulp-concat');
const Builder = require('systemjs-builder');
const glob = require('glob-promise');

let bundleModule = async function(builder, modules, outName){
    let exactModuleNames = [];
    for(let mod of modules){
        let fileNames = await glob(mod, {cwd: 'build/static'});
        exactModuleNames = exactModuleNames.concat(fileNames);
    }
    exactModuleNames = exactModuleNames.filter(name => {
        return ['.js', '.html'].some(ext => name.endsWith(ext)) && !['.standalone.js'].some(ext => name.endsWith(ext));
    });
    await builder.bundle(exactModuleNames, 'build/static/' + outName);
};

let clientBundle = async function(){
    let prdConfig = {};
    let SystemJS = {config:(options) => {prdConfig = options}}
    let systemJsPrdFile = await fs.readFile('./build/static/app/systemjs-prd.config.js');
    eval(systemJsPrdFile.toString());
    if(!prdConfig.bundles){
        return;
    }
    var builder = new Builder('build/static', 'build/static/app/systemjs.config.js');
    let bundles = prdConfig.bundles;
    for(let key of Object.keys(bundles)){
        await bundleModule(builder, bundles[key], key);
    }
};

let writeSystemJsConfig = function(dev){
    let conactFile = dev ? 'build/static/app/systemjs-dev.config.js' : 'build/static/app/systemjs-prd.config.js';
    return streamToPromise(gulp.src(['build/static/app/systemjs.config.js', conactFile]).pipe(concat('systemjs.config.js')).pipe(gulp.dest('build/static/app')));
};

let clientSystemJsDev = function(){
    return writeSystemJsConfig(true);
};

let clientSystemJs = function() {
    return clientBundle().then(() => writeSystemJsConfig(false));
};

Note that for production builds I call clientSystemJs and for dev builds (no bundling) I call clientSystemJsDev. I have most SystemJS config in one file called systemjs.config.js with specific production and dev config in systemjs-prd.config.js and systemjs-dev.config.js respectively.

There are a few things that could be made easier here. One is being able to read the config without using eval. Another is if builder.bundle(exactModuleNames, 'build/static/' + outName); could take an array of globs instead of exact module names. In addition, if the bundles part of config supported the full glob syntax rather than just a single wildcard character, this would be useful. Then it might be useful to have a built-in builder function that could replace almost the whole of my clientBundle and bundleModule functions by using the bundles section of the config to create bundles.