glint
Version:
Glint is an asset (css, js, whatever-you-need) management that helps you organize and manage your client side files
182 lines (150 loc) • 5.82 kB
JavaScript
/**
* @todo move merging and postprocessing outside PackageWriter - it's not its responsibility
*/
;
module.exports = PackageWriter;
var path = require('path');
var fs = require('fs');
var createHash = require('crypto').createHash;
var fsx = require('fs-extra');
function PackageWriter(packages, processedFiles, config) {
var manifest = {dev: {}, prod: {}};
initDirectoryStructure();
function initDirectoryStructure() {
removeOldDirectories();
createNewDirectories();
}
function removeOldDirectories() {
fsx.removeSync(path.join(config.outputDir, 'sources/css'));
fsx.removeSync(path.join(config.outputDir, 'sources/js'));
fsx.removeSync(path.join(config.outputDir, 'build/css'));
fsx.removeSync(path.join(config.outputDir, 'build/js'));
}
function createNewDirectories() {
fsx.mkdirsSync(path.join(config.outputDir, 'sources/css'));
fsx.mkdirsSync(path.join(config.outputDir, 'sources/js'));
fsx.mkdirsSync(path.join(config.outputDir, 'build/css'));
fsx.mkdirsSync(path.join(config.outputDir, 'build/js'));
}
this.writeManifest = function () {
updateDevPackagesInManifest();
if (config.dev) {
manifest.prod = manifest.dev;
}
var pth = path.join(config.baseDir, config.manifest);
fsx.writeJsonSync(pth, manifest);
};
function updateDevPackagesInManifest() {
packages.forEach(function (pkg) {
var files = splitPackageFiles(pkg);
manifest.dev[pkg.name] = {
css: getPathsForFiles(files.css),
js: getPathsForFiles(files.js)
};
});
}
function getPathsForFiles(files) {
return files.map(function (originalFilePath) {
var outputFile = processedFiles[originalFilePath];
return path.relative(config.outputDir, createDevFilePath(outputFile.name, outputFile.extension));
});
}
this.writeFiles = function () {
Object.keys(processedFiles).forEach(writeFile);
};
this.writeFile = writeFile;
function writeFile(originalFilePath) {
var outputFile = processedFiles[originalFilePath];
var outputPath = createDevFilePath(outputFile.name, outputFile.extension);
fs.writeFileSync(outputPath, outputFile.content, 'utf-8');
}
function createDevFilePath(name, extension) {
return path.join(config.outputDir, 'sources', extension, name);
}
this.writePackages = function (packageNames, fileTypes) {
if (config.dev) {
return;
}
var packagesToWrite = getPackagesToWrite(packageNames);
var fileTypesToWrite = fileTypes || {js: true, css: true};
packagesToWrite.forEach(function (pkg) {
writePackage(pkg, fileTypesToWrite);
});
};
function getPackagesToWrite(packageNames) {
if (packageNames) {
return packages.filter(function (pkg) {
return packageNames.indexOf(pkg.name) !== -1;
});
}
return packages;
}
function writePackage(pkg, extensions) {
var packageFiles = splitPackageFiles(pkg);
var css = mergeFiles(packageFiles.css);
var js = mergeFiles(packageFiles.js, ';');
css = postProcess(css, 'css');
js = postProcess(js, 'js');
manifest.prod[pkg.name] = manifest.prod[pkg.name] || {};
if (extensions.css) {
writePackageFile(pkg.name, css, 'css');
}
if (extensions.js) {
writePackageFile(pkg.name, js, 'js');
}
console.log('[INFO] Package', pkg.name, 'written.');
}
function splitPackageFiles(pkg) {
var css = [];
var js = [];
var files = pkg.files;
for (var i = 0, len = files.length; i < len; i++) {
if (processedFiles[files[i]].extension === 'css') {
css.push(files[i]);
} else {
js.push(files[i]);
}
}
return {
css: css,
js: js
};
}
function mergeFiles(files, separator) {
var output = [];
for (var i = 0, len = files.length; i < len; i++) {
output.push(processedFiles[files[i]].content);
}
return output.join(separator || '\n');
}
function writePackageFile(packageName, content, type) {
var filePath = createProdFilePath(packageName, type, createHashForContent(content));
manifest.prod[packageName][type] = path.relative(config.outputDir, filePath);
fs.writeFileSync(filePath, content, 'utf-8');
}
function createProdFilePath(packageName, extension, hash) {
var fileName = [packageName, hash, extension].join('.');
var filePath = path.join(config.outputDir, 'build', extension, fileName);
return filePath;
}
function postProcess(content, category) {
var processors = config.postprocessors[category];
if (!processors) {
return content;
}
processors.forEach(function processContent(postprocessor) {
if (typeof postprocessor === 'function') {
content = postprocessor(content, {});
} else if (typeof postprocessor === 'object' && postprocessor.fn === 'function') {
var options = postprocessor.options || {};
postprocessor.fn(content, postprocessor, options);
} else {
console.log('[WARNING] Can not use postprocessor: ', postprocessor, '(' + category + ')');
}
});
return content;
}
function createHashForContent(content) {
return createHash('md5').update(content).digest('hex')
}
}