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

100% Statements 62/62
100% Branches 22/22
100% Functions 9/9
100% Lines 62/62
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   10× 10× 10× 10×     10×   10× 10× 10×   10× 10×   10× 10×   10×                 16×   16× 13×     16×           16× 16× 15×       16×     15×                       10×   10×                                          
var RawSource = require('webpack-sources/lib/RawSource');
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('this-compilation', function(compilation) {
    compilation.plugin('optimize-assets', function(_, done) {
      var renderPromises;
 
      var webpackStats = compilation.getStats();
      var webpackStatsJson = webpackStats.toJson();
 
      try {
        var asset = findAsset(self.renderSrc, compilation, webpackStatsJson);
 
        if (asset == null) {
          throw new Error('Source file not found: "' + self.renderSrc + '"');
        }
 
        var assets = getAssetsFromCompilation(compilation, 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) {
              compilation.assets[outputFileName] = new RawSource(output);
            })
            .catch(function(err) {
              compilation.errors.push(err.stack);
            });
        });
 
        Promise.all(renderPromises).nodeify(done);
      } catch (err) {
        compilation.errors.push(err.stack);
        done();
      }
    });
  });
};
 
var findAsset = function(src, compilation, webpackStatsJson) {
  var asset = compilation.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 compilation.assets[chunkValue];
};
 
// Shamelessly stolen from html-webpack-plugin - Thanks @ampedandwired :)
var getAssetsFromCompilation = function(compilation, 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 (compilation.options.output.publicPath) {
      chunkValue = compilation.options.output.publicPath + chunkValue;
    }
    assets[chunk] = chunkValue;
  }
 
  return assets;
};
 
module.exports = StaticSiteGeneratorWebpackPlugin;