From 1f7d36c70726e483c163385dda32f4e90eb76d96 Mon Sep 17 00:00:00 2001
From: Jahred Hope <jahredhope@gmail.com>
Date: Fri, 4 Jan 2019 09:32:07 +1100
Subject: [PATCH] fix: Add render errors to compilation

---
 src/RenderError.js                            | 11 +++++++
 src/index.js                                  |  7 ++--
 tests/test-cases/errors/errors.test.js        | 21 ++++++++++++
 tests/test-cases/errors/src/client.js         |  4 +++
 tests/test-cases/errors/src/render.js         |  3 ++
 .../errors/webpack.default.config.js          | 32 +++++++++++++++++++
 .../errors/webpack.errors.config.js           | 17 ++++++++++
 7 files changed, 92 insertions(+), 3 deletions(-)
 create mode 100644 src/RenderError.js
 create mode 100644 tests/test-cases/errors/errors.test.js
 create mode 100644 tests/test-cases/errors/src/client.js
 create mode 100644 tests/test-cases/errors/src/render.js
 create mode 100644 tests/test-cases/errors/webpack.default.config.js
 create mode 100644 tests/test-cases/errors/webpack.errors.config.js

diff --git a/src/RenderError.js b/src/RenderError.js
new file mode 100644
index 0000000..923a58f
--- /dev/null
+++ b/src/RenderError.js
@@ -0,0 +1,11 @@
+module.exports = class RenderError extends Error {
+  constructor(error) {
+    super(
+      `html-render-webpack-plugin: An error occured during render: \n${error}`
+    );
+
+    this.name = "RenderError";
+
+    Error.captureStackTrace(this, this.constructor);
+  }
+};
diff --git a/src/index.js b/src/index.js
index b2a6c73..330c020 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,8 +1,9 @@
-const renderHtml = require("./renderHtml");
 const chalk = require("chalk");
-
 const validateOptions = require("schema-utils");
+
 const schema = require("./schemas/HtmlRenderWebpackPlugin.json");
+const RenderError = require("./RenderError");
+const renderHtml = require("./renderHtml");
 
 const MultiStats = require("webpack/lib/MultiStats");
 
@@ -84,7 +85,7 @@ module.exports = class HtmlRenderPlugin {
       });
     } catch (error) {
       this.logError("An error occured rendering HTML", error);
-      throw error;
+      currentCompilation.errors.push(new RenderError(error));
     }
   }
   applyRenderPlugin(compiler) {
diff --git a/tests/test-cases/errors/errors.test.js b/tests/test-cases/errors/errors.test.js
new file mode 100644
index 0000000..afc14bc
--- /dev/null
+++ b/tests/test-cases/errors/errors.test.js
@@ -0,0 +1,21 @@
+const MemoryFS = require("memory-fs");
+const webpack = require("webpack");
+
+describe("Render HTML from in-config Plugin", () => {
+  it("should render a HTML file", async done => {
+    const compiler = webpack(require("./webpack.errors.config"));
+
+    const memoryFs = new MemoryFS();
+    compiler.outputFileSystem = memoryFs;
+
+    compiler.run((error, result) => {
+      // Render errors do not show up as build errors
+      expect(error).toBe(null);
+      // Errors show up in compilation
+      expect(result.toJson({ all: false, errors: true }).errors).toEqual(
+        expect.arrayContaining([expect.stringContaining("Example error")])
+      );
+      done();
+    });
+  });
+});
diff --git a/tests/test-cases/errors/src/client.js b/tests/test-cases/errors/src/client.js
new file mode 100644
index 0000000..30921d2
--- /dev/null
+++ b/tests/test-cases/errors/src/client.js
@@ -0,0 +1,4 @@
+module.exports = async () => {
+  const bar = "foo";
+  return bar;
+};
diff --git a/tests/test-cases/errors/src/render.js b/tests/test-cases/errors/src/render.js
new file mode 100644
index 0000000..b5b1876
--- /dev/null
+++ b/tests/test-cases/errors/src/render.js
@@ -0,0 +1,3 @@
+export default function exampleRender() {
+  throw new Error("Example error");
+}
diff --git a/tests/test-cases/errors/webpack.default.config.js b/tests/test-cases/errors/webpack.default.config.js
new file mode 100644
index 0000000..6227553
--- /dev/null
+++ b/tests/test-cases/errors/webpack.default.config.js
@@ -0,0 +1,32 @@
+const path = require("path");
+
+const srcPath = path.resolve(__dirname, "./src");
+const paths = {
+  renderEntry: path.resolve(srcPath, "render.js"),
+  clientEntry: path.resolve(srcPath, "client.js")
+};
+
+module.exports = [
+  {
+    name: "client",
+    target: "web",
+    mode: "production",
+    entry: paths.clientEntry,
+    output: {
+      filename: "client-[name]-[contenthash].js"
+    }
+  },
+  {
+    dependencies: ["client"],
+    name: "render",
+    target: "node",
+    mode: "production",
+    entry: paths.renderEntry,
+    output: {
+      libraryExport: "default",
+      library: "static",
+      libraryTarget: "umd2",
+      filename: "render-[name]-[contenthash].js"
+    }
+  }
+];
diff --git a/tests/test-cases/errors/webpack.errors.config.js b/tests/test-cases/errors/webpack.errors.config.js
new file mode 100644
index 0000000..3bb15fc
--- /dev/null
+++ b/tests/test-cases/errors/webpack.errors.config.js
@@ -0,0 +1,17 @@
+const path = require("path");
+const merge = require("webpack-merge");
+const defaultConfig = require("./webpack.default.config");
+const HtmlRenderPlugin = require("../../../src");
+
+const renderDirectory = path.join(process.cwd(), "dist", "render");
+
+const htmlRenderPlugin = new HtmlRenderPlugin({ renderDirectory });
+
+module.exports = [
+  merge(defaultConfig[0], {
+    plugins: [htmlRenderPlugin]
+  }),
+  merge(defaultConfig[1], {
+    plugins: [htmlRenderPlugin.render()]
+  })
+];