@edenjs/cli
Version:
Web Application Framework built on Express.js and Redis
192 lines (158 loc) • 4.7 kB
text/typescript
// Require local dependencies
import fs from 'fs-extra';
import loader from '../../../lib/loader';
/**
* Create SASS Task class
*
* @task scss
* @parallel
*/
export default class ScssTask {
/**
* Construct SASS Task class
*
* @param {Loader} runner
*/
constructor(cli) {
// Set private variables
this.cli = cli;
// Bind public methods
this.run = this.run.bind(this);
this.watch = this.watch.bind(this);
}
/**
* run in background
*
* @param {*} files
*/
async run(files) {
// create opts
const opts = {
files,
scss : Array.from(new Set(this.cli.get('config.frontend.scss.include') || [])),
bases : this.cli.get('bases', []),
appRoot : global.appRoot,
variables : await loader.find(this.cli.get('bundles').map((b) => b.path), '/public/scss/variables.scss'),
bootstrap : await loader.find(this.cli.get('bundles').map((b) => b.path), '/public/scss/bootstrap.scss'),
sourceMaps : this.cli.get('config.environment') === 'dev',
compiler : require.resolve('node-sass'),
};
// try/catch
try {
// run models in background
await this.thread(opts);
} catch (e) {
console.log(e);
}
// reload js
if (this.cli.get('config.environment') === 'dev') {
// emit hot
this.cli.emit('hot', 'scss', await fs.readFile(`${global.appRoot}/www/public/css/app.min.css`, 'utf8'));
}
// return loaded
return `${files.length.toLocaleString()} scss entries compiled!`;
}
/**
* Run sass task
*
* @returns {Promise}
*/
async thread(data) {
// require dependencies
const fs = require('fs-extra');
const os = require('os');
const Path = require('path');
const glob = require('@edenjs/glob');
const gulp = require('gulp');
const gulpSass = require('gulp-sass');
const gulpRename = require('gulp-rename');
const vinylSource = require('vinyl-source-stream');
const vinylBuffer = require('vinyl-buffer');
const gulpSourcemaps = require('gulp-sourcemaps');
// add compiler
gulpSass.compiler = require(data.compiler);
// create custom importer
const customImporter = (url) => {
// return null for normal importer
if (url[0] !== '~') return null;
// file path minus tilda
const filePath = url.substr(1).split('.')[0];
// location null
let location = null;
// loop for bases
[data.appRoot, ...data.bases].forEach((base) => {
// find
['.scss', '.css'].forEach((type) => {
// get location
const check = `${base}/node_modules/${filePath}${type}`;
// return location
if (!location && fs.existsSync(check)) location = check;
});
});
// return location if not null
if (location) {
return { file : location };
}
// return null
return null;
};
// Grab gulp source for sass. Create local variables array for sass files
const sassFiles = data.variables.reverse();
// Load sass
const configSass = data.scss;
// Add config sass files
sassFiles.push(...configSass.map(p => Path.join(data.appRoot, p)));
// Push local bootstrap files
sassFiles.push(...data.bootstrap);
// Create body for main file
let body = '';
// global all saas files to import
for (const file of await glob(sassFiles)) {
// import
body += (Path.extname(file) === '.css' ? await fs.readFile(file, 'utf8') : `@import "${file}";`) + os.EOL;
}
// Create job
let job = vinylSource('master.scss');
// Push main body file to job
job.end(body);
// Buffer for compatibility
job = job.pipe(vinylBuffer());
// Init gulpSourcemaps
if (data.sourceMaps) {
job = job.pipe(gulpSourcemaps.init());
}
// pipe
job = job.pipe(gulpSass.sync({
importer : customImporter,
}));
// pipe to rename
job = job.pipe(gulpRename('app.min.css'));
// Write gulpSourcemaps
if (data.sourceMaps) {
job = job.pipe(gulpSourcemaps.write('.'));
}
// create job
job = job.pipe(gulp.dest(`${data.appRoot}/www/public/css`));
// Wait for job to end
await new Promise((resolve, reject) => {
// resolve
job.once('end', () => {
// resolve
resolve();
});
job.once('error', (err) => {
console.log(err);
reject(err);
});
});
}
/**
* Watch task
*
* @return {string[]}
*/
watch() {
// Return files
return '/public/scss/**/*.scss';
}
}