createAppBundleMappings: function(bundleSetConfig, optimizerContext, callback) {
        ok(bundleSetConfig, '"bundleSetConfig" is required');
        ok(typeof callback === 'function', 'callback function is required');

        var dependencyRegistry = this.dependencies;
        var bundleMappings = new BundleMappings(this.config);

        var asyncTasks = [];

        bundleSetConfig.forEachBundleConfig(function(bundleConfig) {
            var bundleName = bundleConfig.name;

            ok(bundleName, 'Illegal state. Bundle name is required');

            asyncTasks.push(function(callback) {
                bundleBuilder.buildBundle(
                    bundleMappings,
                    dependencyRegistry,
                    bundleConfig,
                    optimizerContext,
                    callback);
            });
        });

        return series(asyncTasks, function(err) {
            if (err) {
                return callback(err);
            }

            return callback(null, bundleMappings);
        });
    },
        function (dir, helpers, done) {

            var main = require(nodePath.join(dir, 'test.js'));
            var testName = nodePath.basename(dir);
            var pageName = 'resource-transforms-' + testName;

            var lassoConfig = main.getLassoConfig && main.getLassoConfig();
            if (!lassoConfig) {
                lassoConfig = {
                    bundlingEnabled: false,
                    fingerprintsEnabled: false
                };
            }

            if (!lassoConfig.outputDir) {
                lassoConfig.outputDir = nodePath.join(buildDir, pageName);
            }

            if (!lassoConfig.projectRoot) {
                lassoConfig.projectRoot = dir;
            }

            rmdirRecursive(lassoConfig.outputDir);

            var myLasso = lasso.create(lassoConfig, dir);

            var inputs = main.getInputs();

            var asyncTasks = inputs.map((input, i) => {
                return (callback) => {
                    var path = input.path;
                    var options = input.options;

                    myLasso.lassoResource(path, options, function(err, result) {
                        if (err) {
                            callback(err);
                        }

                        process.nextTick(() => {
                            try {
                                input.check(result);
                            } catch(e) {
                                return callback(`The inputs at index ${i} failed: ${e.stack}`);
                            }

                            callback();
                        });
                    });
                };
            });

            series(asyncTasks, function(err) {
                if (err) {
                    return done(err);
                }
                done();
            });
        });
Example #3
0
                return function(callback) {
                    var plugin = use.plugin;
                    var pluginName;

                    if (typeof plugin === 'string') {
                        pluginName = plugin;
                        plugin = builtins[plugin] || require(plugin);
                    }

                    if (!pluginName) {
                        pluginName = plugin.name;
                    }

                    var options = use.options || {};

                    var patterns = use.paths;
                    if (typeof patterns === 'string') {
                        patterns = [patterns];
                    }

                    var paths = {};

                    series(patterns.map(function(pattern) {
                            return function(callback) {
                                glob(pattern, { cwd: basedir}, function (err, files) {
                                    if (err) {
                                        return callback(err);
                                    }
                                    for (var i=0, len=files.length; i<len; i++) {
                                        var path = files[i];
                                        path = nodePath.join(basedir, path);
                                        paths[path] = true;
                                    }

                                    callback();
                                });
                            };
                        }),
                        function(err) {
                            if (err) {
                                return initDataHolder.reject(err);
                            }

                            Object.keys(paths).forEach(function(path) {
                                var pluginsForPath = pluginsByPath[path] ||
                                    (pluginsByPath[path] = []);

                                pluginsForPath.push({
                                    plugin: plugin,
                                    options: options
                                });
                            });

                            callback();
                        });
                };
function globNormalizer(dependency, context, callback) {
    if (typeof dependency === 'string' && globRegExp.test(dependency)) {

        var pattern = dependency;
        var typeSeparator = dependency.indexOf(':');
        var type = null;
        var basedir = context.dirname;
        var matches = [];

        if (typeSeparator) {
            type = dependency.substring(0, typeSeparator).trim();
            pattern = dependency.substring(typeSeparator+1);

        }

        pattern = pattern.trim();
        var patterns = pattern.split(/\s+/);
        var asyncTasks = patterns.map(function(pattern) {
            return function(callback) {
                glob(pattern,
                    {
                        cwd: basedir
                    },
                    function (err, files) {
                        if (err) {
                            return callback(err);
                        }

                        matches = matches.concat(files);
                        callback();
                    });
            };
        });

        series(asyncTasks, function(err) {
            if (err) {
                return callback(err);
            }


            matches = matches.map(function(match) {
                match = nodePath.join(basedir, match);
                return type ? type + ':' + match : match;
            });

            callback(null, matches);
        });

    } else {
        callback();
    }
}
Example #5
0
    writeBundles: function(iteratorFunc, onBundleWrittenCallback, lassoContext, callback) {
        ok(lassoContext, 'lassoContext is required');
        ok(callback, 'callback is required');

        var _this = this;

        var work = [];

        iteratorFunc(function(bundle) {
            if (bundle.hasContent()) {
                work.push(function(callback) {
                    _this.writeBundle(bundle, onBundleWrittenCallback, lassoContext, callback);
                });
            }
        });

        series(work, callback);
    }
    function resolveInspectedRequires(inspected, fromDir, fromFile, isBuiltin, options, optimizerContext, callback) {
        ok(inspected, '"inspected" is required');
        equal(typeof fromDir, 'string', '"fromDir" should be a string');
        equal(typeof callback, 'function', '"callback" should be a string');

        var allRequires = [];

        var asyncTasks = [];

        function handleRequire(require) {
            asyncTasks.push(function(callback) {
                resolveRequire(require.path, fromDir, fromFile, options, optimizerContext, function(err, resolved) {
                    if (err) {
                        return callback(err);
                    }

                    if (isBuiltin && resolved.builtin !== true) {
                        resolved = extend({}, resolved);
                        resolved.builtin = true;
                    }

                    require.resolved = resolved;
                    allRequires.push(require);
                    callback();
                });
            });
        }

        inspected.requires.forEach(handleRequire);
        inspected.asyncBlocks.forEach(function(asyncBlock) {
            asyncBlock.requires.forEach(handleRequire);
        });

        series(asyncTasks, function(err) {
            if (err) {
                return callback(err);
            }

            inspected.allRequires = allRequires;
            callback(null, inspected);
        });
    }
Example #7
0
    dependencies.normalize(function(err, dependencies) {
        var asyncTasks = dependencies.map(function(rootDependency) {
            return function(callback) {
                rootDependency.init(lassoContext, function(err) {
                    logger.debug('Root init');

                    if (err) {
                        return callback(err);
                    }

                    var recurseInto = rootDependency._recurseInto || bundleConfig.getRecurseInto();

                    if (!recurseInto) {
                        if (rootDependency.getDir()) {
                            recurseInto = 'dirtree';
                        } else {
                            recurseInto = 'all';
                        }

                    }

                    if (!recurseHandlers[recurseInto]) {
                        throw new Error('Invalid recursion option: ' + recurseInto);
                    }

                    var recurseHandler = recurseHandlers[recurseInto](rootDependency, lassoContext);

                    function shouldIncludeDependency(dependency) {
                        if (dependency === rootDependency ||
                                (lassoContext.parentDependency && lassoContext.parentDependency === rootDependency)) {
                            // Always include the root dependency or any child dependencies if the top-level
                            // dependency was a package
                            return true;
                        }

                        return recurseHandler.shouldIncludeDependency(dependency);
                    }

                    function shouldRecurseIntoPackageDependency(dependency) {
                        if (dependency === rootDependency) {
                            // Always recurse into top-level package dependencies
                            return true;
                        }

                        return recurseHandler.shouldRecurseIntoPackageDependency(dependency);
                    }

                    dependencyWalker.walk({
                            lassoContext: lassoContext,
                            dependency: rootDependency,
                            flags: flags,
                            shouldSkipDependency: function(dependency) {
                                if (bundleMappings.getBundleForDependency(dependency)) {
                                    // The dependency has already been added to another bundle
                                    return true;
                                }

                                if (dependency.isPackageDependency()) {
                                    return !shouldRecurseIntoPackageDependency(dependency);
                                } else if (!dependency.read) {
                                    // ignore non-readable dependencies during bundling phase
                                    return true;
                                }

                                return false;
                            },
                            on: {
                                dependency: function(dependency, context) {

                                    logger.debug(module.id, 'on dependency: ' + dependency.type);

                                    if (dependency.isPackageDependency()) {
                                        if (tree) {
                                            tree.add(dependency, context.parentDependency);
                                        }

                                        // We are only interested in non-package dependencies
                                        return;
                                    }

                                    if (shouldIncludeDependency(dependency)) {
                                        bundleMappings.addDependencyToBundle(
                                            dependency,
                                            targetBundleName,
                                            context.slot,
                                            bundleConfig,
                                            lassoContext);

                                        if (tree) {
                                            tree.add(dependency, context.parentDependency);
                                        }

                                    }
                                }
                            }
                        }, callback);
                });
            };
        });

        series(asyncTasks, function(err) {
            if (err) {
                return callback(err);
            }

            if (tree) {
                logger.debug('Bundle "' + targetBundleName + '":\n' + tree.toString());
            }

            callback();
        });
    });
    getOptimizerManifestFromOptions(options, pageOptimizer.dependencies, function(err, optimizerManifest) {
        if (!optimizerManifest) {
            callback(new Error('Invalid options. "dependencies", "packagePath" or "optimizerManifest" expected. Options: ' + require('util').inspect(options)));
        }

        options.optimizerManifest = optimizerManifest;

        var pluginContext = {
            context: optimizerContext,
            config: config,
            options: options,
            pageOptimizer: pageOptimizer
        };

        pageOptimizer.emit('beforeOptimizePage', pluginContext);

        var optimizedPage = new OptimizedPage();
        var slotTracker = new SlotTracker();

        var writer = optimizerContext.writer;

        function registerBundle(bundle, async) {
            var url = bundle.getUrl(optimizerContext);

            if (url) {
                optimizedPage.addUrl(url, bundle.getSlot(), bundle.getContentType(), async);
            }

            if (!bundle.isExternalResource && bundle.outputFile) {
                optimizedPage.addFile(bundle.outputFile, bundle.getContentType(), async);
            }
        }

        function onBundleWritten(bundle) {
            if (logInfoEnabled) {
                logger.info('Bundle ' + bundle + ' written.');
            }
            registerBundle(bundle, false);
        }

        function onAsyncBundleWritten(bundle) {
            if (logInfoEnabled) {
                logger.info('Bundle ' + bundle + ' (async) written.');
            }
            registerBundle(bundle, true);
        }

        function buildHtmlSlots(pageBundles) {
            pageBundles.forEachBundle(function(bundle) {
                var html,
                    url;

                if (bundle.isInline()) {
                    slotTracker.addInlineCode(bundle.getSlot(), bundle.getContentType(), bundle.getCode(), bundle.getInlinePos(), bundle.isMergeInline());
                } else {
                    url = bundle.getUrl(optimizerContext);

                    if (bundle.isJavaScript()) {
                        html = pageOptimizer.getJavaScriptDependencyHtml(url);
                    } else if (bundle.isStyleSheet()) {
                        html = pageOptimizer.getCSSDependencyHtml(url);
                    } else if (!bundle.hasContent()) {
                        // ignore this bundle because contentType is "none"
                        return;
                    } else {
                        throw new Error('Invalid bundle content type: ' + bundle.getContentType());
                    }
                    slotTracker.addContent(bundle.getSlot(), bundle.getContentType(), html);
                }
            });

            optimizedPage.setHtmlBySlot(slotTracker.getHtmlBySlot());
        }

        var pageBundles;

        var prevStartTime = startTime;

        var asyncTasks = [
            function buildPageBundles(callback) {
                pageOptimizer.buildPageBundles(options, optimizerContext, function(err, _pageBundles) {
                    if (err) {
                        return callback(err);
                    }

                    pageBundles = _pageBundles;
                    callback();
                });
            },
            function writeAsyncBundles(callback) {
                if (perfLogInfoEnabled) {
                    perfLogger.info('Page bundles built in ' + (Date.now() - prevStartTime) + 'ms');
                }
                prevStartTime = Date.now();

                optimizerContext.setPhase('write-async-page-bundles');

                // First write out all of the async bundles
                writer.writeBundles(pageBundles.forEachAsyncBundleIter(), onAsyncBundleWritten, optimizerContext, callback);
            },
            function writeSyncBundles(callback) {
                if (perfLogInfoEnabled) {
                    perfLogger.info('Async page bundles written in ' + (Date.now() - prevStartTime) + 'ms');
                }
                prevStartTime = Date.now();

                optimizerContext.setPhase('write-page-bundles');


                // Now write out all of the non-async bundles
                writer.writeBundles(pageBundles.forEachBundleIter(), onBundleWritten, optimizerContext, callback);
            }
        ];

        series(asyncTasks, function(err) {
            if (err) {
                return callback(err);
            }

            if (perfLogInfoEnabled) {
                perfLogger.info('Page bundles written in ' + (Date.now() - prevStartTime) + 'ms');
            }
            // All of the bundles have now been persisted, now we can
            // generate all of the HTML for the page
            buildHtmlSlots(pageBundles);

            perfLogger.info('Optimized page "' + pageName + '" in ' + (Date.now() - startTime) + 'ms');

            if (optimizerContext.cache) {
                optimizerContext.cache.flushAll();
            }

            callback(null, optimizedPage);
        });
    });
Example #9
0
        function (dir, done) {

            var main = require(nodePath.join(dir, 'test.js'));
            var testName = nodePath.basename(dir);
            var pageName = 'bundling-' + testName;

            var lassoConfig = main.getLassoConfig && main.getLassoConfig();
            if (!lassoConfig) {
                lassoConfig = {
                    bundlingEnabled: false,
                    fingerprintsEnabled: false
                };
            }

            if (!lassoConfig.outputDir) {
                lassoConfig.outputDir = nodePath.join(buildDir, pageName);
            }


            rmdirRecursive(lassoConfig.outputDir);

            var myLasso = lasso.create(lassoConfig, dir);

            var inputs;

            if (main.getInputs) {
                inputs = main.getInputs();
            } else {
                let lassoOptions = main.getLassoOptions(dir) || {};
                let check = main.check;

                inputs = [
                    {
                        lassoOptions,
                        check
                    }
                ];
            }


            var asyncTasks = inputs.map((input) => {
                return (callback) => {
                    var writerTracker = WriterTracker.create(myLasso.writer);

                    var lassoOptions = input.lassoOptions;
                    var check = input.check;

                    if (!lassoOptions.pageName) {
                        lassoOptions.pageName = pageName;
                    }

                    if (!lassoOptions.from) {
                        lassoOptions.from = dir;
                    }

                    myLasso.lassoPage(lassoOptions)
                        .then((lassoPageResult) => {
                            check(lassoPageResult, writerTracker);
                            lasso.flushAllCaches(callback);
                        })
                        .catch(callback);
                };
            });

            series(asyncTasks, (err) => {
                if (err) {
                    return done(err);
                }

                done();
            });


        });
Example #10
0
    writeBundle: function(bundle, onBundleWrittenCallback, lassoContext, callback) {
        ok(callback, 'callback is required');

        if (!bundle.hasContent()) {
            return callback();
        }

        ok(lassoContext, 'lassoContext is required');
        var _this = this;

        function done(err) {
            if (err) {
                err = createError('Error while writing bundle "' + bundle + '" Error: ' + err, err);
                return callback(err);
            }

            bundle.setWritten(true);

            if (onBundleWrittenCallback) {
                onBundleWrittenCallback(bundle);
            }

            _this.emit('bundleWritten', {
                bundle: bundle
            });

            logger.info('Bundle ' + bundle + ' written.');

            return callback(null, bundle);
        }

        if (bundle.isWritten() || bundle.url) {
            if (logger.isInfoEnabled()) {
                logger.info('Bundle (' + bundle.getKey() + ') already written. Skipping writing...');
            }

            return done();
        } else if ((bundle.inPlaceDeployment === true) && !bundle.isInline()) {
            var inPlaceUrl = this.getInPlaceUrlForBundle(bundle, lassoContext);
            if (inPlaceUrl) {
                if (logger.isInfoEnabled()) {
                    logger.info('In-place deployment enabled for (' + bundle.getKey() + '). Skipping writing...');
                }
                bundle.setUrl(inPlaceUrl);
                return done();
            }
        }

        lassoContext = Object.create(lassoContext);
        lassoContext.bundle = bundle;
        lassoContext.dependencies = bundle.dependencies;

        var bundleReader = reader.createBundleReader(bundle, lassoContext);

        logger.info('Writing bundle ' + bundle + '...');

        var asyncTasks = [
            function checkBundleUpToDate(callback) {
                if (bundle.isInline()) {
                    return callback();
                }

                return _this.checkBundleUpToDate(bundle, lassoContext, function(err) {
                    if (err) {
                        return callback(err);
                    }

                    // We make the assumption that the bundle was populated with its URL
                    // and marked as written if it was indeed up-to-date
                    return callback();
                });
            },

            function writeBundle(callback) {
                if (bundle.isWritten()) {
                    // If the bundle is written then there is nothing to do
                    return callback();
                }

                var completed = false;

                function handleError(e) {
                    if (!completed) {
                        completed = true;
                        return callback(e);
                    }
                }

                if (bundle.isInline()) {
                    bundleReader.readBundleFully(function(err, code) {
                        if (err) {
                            return handleError(err);
                        }

                        logger.info('Code for inline bundle ' + bundle.getLabel() + ' generated.');
                        bundle.setCode(code);
                        return callback();
                    });
                } else {
                    _this.impl.writeBundle(bundleReader, lassoContext, function(err) {
                        if (err) {
                            return handleError(err);
                        }

                        return callback();
                    });
                }
            }
        ];

        series(asyncTasks, done);
    },
Example #11
0
    getLassoManifestFromOptions(options, theLasso.dependencies, function(err, lassoManifest) {
        if (!lassoManifest) {
            callback(new Error('Invalid options. "dependencies", "packagePath" or "lassoManifest" expected. Options: ' + require('util').inspect(options)));
        }

        logger.debug('getLassoManifestFromOptions()');

        options.lassoManifest = lassoManifest;

        var pluginContext = {
            context: lassoContext,
            config: config,
            options: options,
            lasso: theLasso
        };

        // TODO: Deprecate this
        theLasso.emit('beforeOptimizePage', pluginContext);
        theLasso.emit('beforeLassoPage', pluginContext);

        var lassoPageResult = new LassoPageResult();
        var slotTracker = new SlotTracker();

        var writer = lassoContext.writer;

        // Inline code fingerprinting is useful for building a Single Page App
        // that is using a Content Security Policy (CSP) that prevents
        // untrusted script blocks. By keeping track of inline code
        // fingerprints, a build tool could provide these as part of the CSP
        // so that inline code blocks created at build time will be trusted.
        var fingerprintInlineCode = config.fingerprintInlineCode;
        var inlineCodeFingerprints;

        if (fingerprintInlineCode) {
            inlineCodeFingerprints = [];
        }

        function onBundleWritten(bundle) {
            if (logInfoEnabled) {
                logger.info('Bundle ' + bundle + ' written.');
            }
            lassoPageResult.registerBundle(bundle, false, lassoContext);
        }

        function onAsyncBundleWritten(bundle) {
            if (logInfoEnabled) {
                logger.info('Bundle ' + bundle + ' (async) written.');
            }
            lassoPageResult.registerBundle(bundle, true, lassoContext);
        }

        function buildHtmlSlots(pageBundles) {
            pageBundles.forEachBundle(function(bundle) {
                var html,
                    url;

                if (bundle.isInline()) {
                    if (fingerprintInlineCode) {
                        var fingerprint = config.fingerprintInlineCode(bundle.getCode());
                        if (fingerprint) {
                            inlineCodeFingerprints.push(fingerprint);
                        }
                    }

                    slotTracker.addInlineCode(bundle.getSlot(), bundle.getContentType(), bundle.getCode(), bundle.getInlinePos(), bundle.isMergeInline());
                } else {
                    url = bundle.getUrl(lassoContext);

                    if (bundle.isJavaScript()) {
                        html = theLasso.getJavaScriptDependencyHtml(url);
                    } else if (bundle.isStyleSheet()) {
                        html = theLasso.getCSSDependencyHtml(url);
                    } else if (!bundle.hasContent()) {
                        // ignore this bundle because contentType is "none"
                        return;
                    } else {
                        throw new Error('Invalid bundle content type: ' + bundle.getContentType());
                    }
                    slotTracker.addContent(bundle.getSlot(), bundle.getContentType(), html);
                }
            });

            lassoPageResult.setHtmlBySlot(slotTracker.getHtmlBySlot());
            lassoPageResult.setInlineCodeFingerprints(inlineCodeFingerprints);
        }

        var pageBundles;

        var prevStartTime = startTime;

        var asyncTasks = [
            function buildPageBundles(callback) {

                logger.debug('buildPageBundles BEGIN');

                theLasso.buildPageBundles(options, lassoContext, function(err, _pageBundles) {
                    if (err) {
                        return callback(err);
                    }

                    logger.debug('buildPageBundles COMPLETE');

                    pageBundles = _pageBundles;
                    callback();
                });
            },
            function writeAsyncBundles(callback) {
                if (perfLogInfoEnabled) {
                    perfLogger.info('Page bundles built in ' + (Date.now() - prevStartTime) + 'ms');
                }
                prevStartTime = Date.now();

                lassoContext.setPhase('write-async-page-bundles');

                // First write out all of the async bundles
                writer.writeBundles(pageBundles.forEachAsyncBundleIter(), onAsyncBundleWritten, lassoContext, callback);
            },
            function writeSyncBundles(callback) {
                if (perfLogInfoEnabled) {
                    perfLogger.info('Async page bundles written in ' + (Date.now() - prevStartTime) + 'ms');
                }
                prevStartTime = Date.now();

                lassoContext.setPhase('write-page-bundles');


                // Now write out all of the non-async bundles
                writer.writeBundles(pageBundles.forEachBundleIter(), onBundleWritten, lassoContext, callback);
            }
        ];

        series(asyncTasks, function(err) {
            if (err) {
                return callback(err);
            }

            if (perfLogInfoEnabled) {
                perfLogger.info('Page bundles written in ' + (Date.now() - prevStartTime) + 'ms');
            }
            // All of the bundles have now been persisted, now we can
            // generate all of the HTML for the page
            buildHtmlSlots(pageBundles);

            perfLogger.info('Built page "' + pageName + '" in ' + (Date.now() - startTime) + 'ms');

            if (lassoContext.cache) {
                lassoContext.cache.flushAll();
            }

            callback(null, lassoPageResult);
        });
    });
Example #12
0
    require('../lib/github').fetchRepos(org, function(err, repos) {
        if (err) {
            logger.error('Error fetching GitHub repositories.', err);
            process.exit(1);
            return;
        }

        var dir = args.dir;
        var i;
        var repo;

        logger.info('Found the following ' + org + ' repositories on GitHub:');
        for (i = 0; i < repos.length; i++) {
            repo = repos[i];
            logger.info(repo.name);
        }

        logger.info('Cloning or updating raptorjs repositories to ' + dir + '...');

        series([
            function(callback) {
                // update git repos
                if (args['skip-git-update']) {
                    callback();
                } else {
                    git.updateRepos(repos, args.dir, logger, function(err) {
                        if (err) {
                            logger.error('Error cloning one or more repos.');
                        } else {
                            logger.info('All raptorjs repositories cloned or updated successfully.');
                        }
                        callback(err);
                    });
                }
            },

            function(callback) {
                // remove unneeded modules from node_modules
                removeUnneeded(repos, args.dir, logger, callback);
            },

            function(callback) {
                // run npm link
                if (args['skip-link']) {
                    callback();
                } else {
                    // STEP 4: Use "npm link" to link all of the modules for development
                    npm.linkModules(repos, args.dir, logger, function(err) {
                        if (err) {
                            logger.error('Error linking modules.', err);
                        } else {
                            logger.info('All raptorjs modules linked successfully.');
                        }

                        callback(err);
                    });
                }
            }
        ], function(err) {
            if (err) {
                logger.error('Errors during setup.', err);
            } else {
                logger.success('Setup completed successfully.');
            }
        });
    });