Home Manual Reference Source Test Repository

lib/theme/asset.js

import fs from 'fs-extra';
import _ from 'lodash';

import log from '../log';
import browserify from './processor/browserify';
import less from './processor/less';
import sass from './processor/sass';

const processors = {
  browserify,
  less,
  sass,
};

export default class Asset {
  constructor(assetType, assetConfig) {
    /**
     * ID of asset, right now an alias to its type.
     * @type {string}
     */
    this.id = assetType;

    /**
     * What type of asset this is. css/js/font etc.
     * @type {string}
     */
    this.type = assetType;

    /**
     * The asset config object.
     * @type {Object}
     */
    this.config = assetConfig;

    // If this asset has a processor, instantiate the class that handles how to
    // process the asset.
    if (this.config.processor && this.config.processor.name) {
      const processorName = this.config.processor.name;
      const ProcessorClass = processors[processorName];

      if (_.isUndefined(ProcessorClass)) {
        const msg = `Could not load processer '${processorName}'. Aborting.`;
        log.error(msg);
        throw new Error(msg);
      }

      /**
       * Asset processor.
       * @type {Processor}
       */
      this.processor = new ProcessorClass(this);

      /**
       * Asset destination where it should be written to.
       * @type {string}
       */
      this.destination = '';

      /**
       * The processed Asset content.
       * @type {string}
       */
      this.content = '';
    }

    /**
     * Data accessible to templates.
     * @type {Object}
     */
    this.data = Object.create(null);
  }

  async process(pathDestination) {
    if (!this.processor) {
      return;
    }

    try {
      const processedFile = await this.processor.process();

      this.destination = processedFile.destination;
      this.content = processedFile.asset;
    } catch (e) {
      throw e;
    }

    // Expose relative url to file.
    this.data.url = this.destination.replace(pathDestination, '');
  }

  async write() {
    // If there is a processor let it handle writing the file.
    if (this.processor) {
      if (!(this.destination || this.content)) {
        log.warn(`Asset: ${this.id} found no processed file when about ` +
          'to write asset to disk. Processing now.');
        await this.process();
      }

      fs.outputFileSync(this.destination, this.content, 'utf8');
    } else {
      // If there's no processor then just copy the source to the destination.
      try {
        fs.copySync(this.config.source, this.config.destination);
      } catch (e) {
        log.error(`Asset: Could not copy '${this.type}' assets.`);
      }
    }
  }
}