all files / static-site-generator-webpack-plugin/ index.js

100% Statements 64/64
100% Branches 22/22
100% Functions 11/11
100% Lines 64/64
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131                               15×   15× 12×     15×           15× 15× 14×       15×     14×                                                               14×   14×              
var evaluate = require('eval');
var path = require('path');
var Promise = require('bluebird');
 
function StaticSiteGeneratorWebpackPlugin(renderSrc, outputPaths, locals, scope) {
  this.renderSrc = renderSrc;
  this.outputPaths = Array.isArray(outputPaths) ? outputPaths : [outputPaths];
  this.locals = locals;
  this.scope = scope;
}
 
StaticSiteGeneratorWebpackPlugin.prototype.apply = function(compiler) {
  var self = this;
 
  compiler.plugin('emit', function(compiler, done) {
    var renderPromises;
 
    var webpackStats = compiler.getStats();
    var webpackStatsJson = webpackStats.toJson();
 
    try {
      var asset = findAsset(self.renderSrc, compiler, webpackStatsJson);
 
      if (asset == null) {
        throw new Error('Source file not found: "' + self.renderSrc + '"');
      }
 
      var assets = getAssetsFromCompiler(compiler, webpackStatsJson);
 
      var source = asset.source();
      var render = evaluate(source, /* filename: */ self.renderSrc, /* scope: */ self.scope, /* includeGlobals: */ true);
 
      if (render.hasOwnProperty('default')) {
        render = render['default'];
      }
 
      if (typeof render !== 'function') {
        throw new Error('Export from "' + self.renderSrc + '" must be a function that returns an HTML string');
      }
 
      renderPromises = self.outputPaths.map(function(outputPath) {
        var outputFileName = outputPath.replace(/^(\/|\\)/, ''); // Remove leading slashes for webpack-dev-server
 
        if (!/\.(html?)$/i.test(outputFileName)) {
            outputFileName = path.join(outputFileName, 'index.html');
        }
 
        var locals = {
          path: outputPath,
          assets: assets,
          webpackStats: webpackStats
        };
 
        for (var prop in self.locals) {
          if (self.locals.hasOwnProperty(prop)) {
            locals[prop] = self.locals[prop];
          }
        }
 
        return Promise
          .fromNode(render.bind(null, locals))
          .then(function(output) {
            compiler.assets[outputFileName] = createAssetFromContents(output);
          })
          .catch(function(err) {
            compiler.errors.push(err.stack);
          });
      });
 
      Promise.all(renderPromises).nodeify(done);
    } catch (err) {
      compiler.errors.push(err.stack);
      done();
    }
  });
};
 
var findAsset = function(src, compiler, webpackStatsJson) {
  var asset = compiler.assets[src];
 
  if (asset) {
    return asset;
  }
 
  var chunkValue = webpackStatsJson.assetsByChunkName[src];
 
  if (!chunkValue) {
    return null;
  }
  // Webpack outputs an array for each chunk when using sourcemaps
  if (chunkValue instanceof Array) {
    // Is the main bundle always the first element?
    chunkValue = chunkValue[0];
  }
  return compiler.assets[chunkValue];
};
 
// Shamelessly stolen from html-webpack-plugin - Thanks @ampedandwired :)
var getAssetsFromCompiler = function(compiler, webpackStatsJson) {
  var assets = {};
  for (var chunk in webpackStatsJson.assetsByChunkName) {
    var chunkValue = webpackStatsJson.assetsByChunkName[chunk];
 
    // Webpack outputs an array for each chunk when using sourcemaps
    if (chunkValue instanceof Array) {
      // Is the main bundle always the first element?
      chunkValue = chunkValue[0];
    }
 
    if (compiler.options.output.publicPath) {
      chunkValue = compiler.options.output.publicPath + chunkValue;
    }
    assets[chunk] = chunkValue;
  }
 
  return assets;
};
 
var createAssetFromContents = function(contents) {
  return {
    source: function() {
      return contents;
    },
    size: function() {
      return contents.length;
    }
  };
};
 
module.exports = StaticSiteGeneratorWebpackPlugin;