UNPKG

web-themer

Version:

Customizable theme generator for web applications.

157 lines (133 loc) 6.15 kB
'use strict'; const fs = require('fs'); const os = require('os'); const path = require('path'); const process = require('process'); const chalk = require('chalk'); const nodeDir = require('node-dir'); const sass = require('node-sass'); const _ = require('lodash'); const utils = require('../utils'); const fsx = utils.fsx; module.exports = class ThemeBuilder { constructor(themeRootDir, outputDir, options) { this.currentDir = process.cwd(); this.themeRootDir = themeRootDir; this.outputDir = outputDir; this.options = options || {}; this.options.flattenOutput = this.options.flattenOutput || false; this.options.recreateOutputDir = this.options.recreateOutputDir == undefined ? true : this.options.recreateOutputDir;; this.options.run = options.run || { sassBuild: true, cssAssets: true, otherAssets: true }; this.options.themesToBuild = [].concat(this.options.themesToBuild || []); if (this.options.themesToBuild.length > 0) { if (this.options.themesToBuild.some(theme => typeof theme !== 'string')) { throw `Specify a valid theme name in the --theme option`; } } if (this.options.flattenOutput && this.options.themesToBuild.length !== 1) { throw `To flatten the theme output, specify a single theme to process.`; } } build() { this.prepareOutputDirectory(); //Get all directories under the themes root folder that do not start with a '_'. let themes = nodeDir.files(this.themeRootDir, 'dir', null, { sync: true, shortName: true, recursive: false }).filter(t => !_.startsWith(t, '_')); let rootSassContent = fs.readFileSync(path.resolve(this.themeRootDir, 'index.scss'), 'utf8'); let themesToBuild = [].concat(this.options.themesToBuild); for (let i = 0; i < themes.length; i++) { let theme = themes[i]; //If only specific themes need to be built, check if this theme is in the list if (themesToBuild.length > 0 && !themesToBuild.some(thm => thm === theme)) { continue; } //Get the output root and CSS directories. Create them, if they do not exist. let outputDir = this.options.flattenOutput ? this.outputDir : path.resolve(this.outputDir, theme); let cssDir = path.resolve(outputDir, 'css'); fsx.mkdir.sync(cssDir); if (this.options.run.sassBuild) { //Get the name of the output CSS file let cssFile = path.resolve(cssDir, 'styles.css'); //Get the SASS to compile by replacing any occurence of <%theme%> with the theme name //in the root SASS file content. let sassContent = rootSassContent.replace(/<%theme%>/g, theme); //Compile the SASS and write to the output CSS file try { let result = sass.renderSync({ data: sassContent, outFile: cssFile, includePaths: [utils.makeRelativePath(this.currentDir, this.themeRootDir)] }); fs.writeFileSync(cssFile, result.css, 'utf8'); } catch (ex) { const message = ex.message ? ex.message.toString() : ex.toString(); console.log(chalk.red(message)) } } //Copy assets mentioned in the assets.json in the root directory this.copyAssets(this.themeRootDir, outputDir, cssDir, theme); //Copy assets mentioned in the assets.json in the theme directory let themeDir = path.resolve(this.themeRootDir, theme); this.copyAssets(themeDir, outputDir, cssDir, theme); } } /** * If the output directory exists, delete it and recreate it. */ prepareOutputDirectory() { if (fs.existsSync(this.outputDir) && this.options.recreateOutputDir) { // fsx.rmdir.sync(this.outputDir, { force: true }); let dirToEmpty = path.resolve(this.outputDir, '**/*'); console.log(`Emptying ${dirToEmpty}`); fsx.rmdir.sync(dirToEmpty, { force: true }); } if (!fs.existsSync(this.outputDir)) { fsx.mkdir.sync(this.outputDir); } } copyAssets(assetsDir, outputDir, cssDir, themeName) { let assetsFile = path.resolve(assetsDir, 'assets.json'); if (!fs.existsSync(assetsFile)) { return; } let assets = require(assetsFile); if (assets instanceof Array) { if (this.options.run.cssAssets) { this.copySpecificAssets(assets, assetsDir, cssDir, themeName); } } else { if (assets.css && assets.css instanceof Array) { if (this.options.run.cssAssets) { this.copySpecificAssets(assets.css, assetsDir, cssDir, themeName); } } if (assets.others && assets.others instanceof Array) { if (this.options.run.otherAssets) { this.copySpecificAssets(assets.others, assetsDir, outputDir, themeName); } } } } copySpecificAssets(assets, srcDir, outputDir, themeName) { for (let i = 0; i < (assets || []).length; i++) { let asset = assets[i]; let srcGlob = path.resolve(srcDir, asset.src.replace('<%theme%>', themeName)); let destDir = path.resolve(outputDir, asset.dest); if (!fs.existsSync(destDir)) { fsx.mkdir.sync(destDir); } fsx.copy(srcGlob, destDir, function(err, files) { if (err) { throw err; } }); } } }