diff --git a/Web/Herringbone/Embed.hs b/Web/Herringbone/Embed.hs
new file mode 100644
--- /dev/null
+++ b/Web/Herringbone/Embed.hs
@@ -0,0 +1,51 @@
+{-# LANGUAGE TemplateHaskell #-}
+module Web.Herringbone.Embed where
+
+import Control.Monad (forM, (>=>), when)
+import Language.Haskell.TH.Syntax (Q, Exp(..), Lit(..), runIO)
+import Data.FileEmbed (embedDir)
+import Data.ByteString (ByteString)
+import qualified Data.ByteString.Char8 as B8
+import qualified Filesystem.Path.CurrentOS as F
+import qualified Data.Text as T
+
+import Web.Herringbone
+
+-- | Precompile and embed all assets into your source code. Call this function
+-- in a Template Haskell splice. Any asset compilation failures will result in
+-- a compile error.
+--
+-- For example:
+--
+-- > assets :: [(LogicalPath, ByteString)]
+-- > assets = $(embedAssets
+--      (herringbone
+--          (setSourceDir "assets" . setDestDir ".compiled_assets"))
+--      )
+embedAssets :: IO Herringbone -> Q Exp
+embedAssets iohb = do
+    hb <- runIO iohb
+    errs <- runIO (precompile hb)
+    when (not . null $ errs) $
+        fail ("the following assets failed to compile:\n" ++
+            unlines (map show errs))
+
+    SigE expr' _ <- embedDir (F.encodeString $ hbDestDir hb)
+    let expr = transformFiles expr'
+
+    type_ <- [t| [(LogicalPath, ByteString)] |]
+    return $ SigE expr type_
+    where
+    transformFiles (ListE tups) =
+        let f (TupE [LitE (StringL path), contents]) =
+                TupE [logicalPathExp path, contents]
+            f _ = error "unexpected Exp in precompileEmbed"
+        in ListE $ map f tups
+    transformFiles _ = error "unexpected Exp in precompileEmbed"
+    logicalPathExp = logicalPathToExp . stringToLogicalPath
+    stringToLogicalPath = unsafeMakeLogicalPath . T.splitOn "/" . T.pack
+    logicalPathToExp logicalPath =
+        AppE
+            (VarE 'unsafeMakeLogicalPath)
+            (ListE (map (LitE . StringL . T.unpack)
+                        (fromLogicalPath logicalPath)))
diff --git a/Web/Herringbone/Precompile.hs b/Web/Herringbone/Precompile.hs
deleted file mode 100644
--- a/Web/Herringbone/Precompile.hs
+++ /dev/null
@@ -1,84 +0,0 @@
-{-# LANGUAGE TemplateHaskell #-}
-module Web.Herringbone.Precompile where
-
-import Language.Haskell.TH.Syntax (Q, Exp(..), Lit(..), runIO)
-import Data.FileEmbed (embedDir)
-import Data.ByteString (ByteString)
-import qualified Data.ByteString.Char8 as B8
-import qualified Filesystem.Path.CurrentOS as F
-import qualified Data.Text as T
-import Control.Monad (forM, (>=>))
-
-import Web.Herringbone
-import Web.Herringbone.Internal.GetBuildMapping (getBuildMapping)
-import Web.Herringbone.Internal.Types (BuildSpec(..), LogicalPath(..))
-
--- | Precompiles all assets.
-precompile :: Herringbone -> IO [(LogicalPath, AssetError)]
-precompile hb = do
-    mapping <- getBuildMapping hb
-    results <- forM mapping $ \(BuildSpec _ destPath _) -> do
-        let Just path = toLogicalPath $ destPath
-        asset <- findAsset hb path
-        case asset of
-            Right _ -> return []
-            Left err -> return [(path, err)]
-    return $ concat results
-
-    where
-    toLogicalPath =
-        toMaybe F.toText >=>
-        return . T.splitOn "/" >=>
-        makeLogicalPath 
-    toMaybe f x = case f x of
-        Right y -> Just y
-        Left _  -> Nothing
-
--- | Precompile and embed all assets into your source code. Call this function
--- in a Template Haskell splice.
---
--- Returns: (Errors, Files) where:
---
--- > type Errors = [(LogicalPath, AssetError)]
--- > type Files = [(LogicalPath, ByteString)] 
---
--- The second component is a mapping of filenames to file contents.
-embedAssets :: IO Herringbone -> Q Exp
-embedAssets iohb = do
-    hb <- runIO iohb
-    errs <- runIO (precompile hb)
-    let errsExp = ListE $ map (\(path, err) ->
-                        TupE [logicalPathToExp path, errToExp err]) errs
-    SigE filesExp' _ <- embedDir (F.encodeString $ hbDestDir hb)
-    let filesExp = transformFiles filesExp'
-    let expr = TupE [errsExp, filesExp]
-
-    type_ <- [t| ([(LogicalPath, AssetError)], [(LogicalPath, ByteString)]) |]
-    return $ SigE expr type_
-    where
-    logicalPathToExp logicalPath =
-        AppE
-            (ConE 'LogicalPath)
-            (ListE (map (LitE . StringL . T.unpack)
-                        (fromLogicalPath logicalPath)))
-    errToExp e = case e of
-        AssetNotFound ->
-            ConE 'AssetNotFound
-        AssetCompileError err ->
-            AppE (ConE 'AssetCompileError) $ compileErrToExp err
-        AmbiguousSources srcs ->
-            AppE (ConE 'AmbiguousSources) $ sourcesToExp srcs
-    compileErrToExp err = LitE (StringL (B8.unpack err))
-    sourcesToExp srcs = ListE $ map filePathToExp srcs
-    -- Just use a literal because we have an IsString instance
-    filePathToExp path = LitE (StringL (F.encodeString path))
-
-    transformFiles (ListE tups) = 
-        let f (TupE [LitE (StringL path), contents]) =
-                TupE [logicalPathExp path, contents]
-            f _ = error "unexpected Exp in precompileEmbed"
-        in ListE $ map f tups
-    transformFiles _ = error "unexpected Exp in precompileEmbed"
-
-    logicalPathExp = logicalPathToExp . stringToLogicalPath
-    stringToLogicalPath = unsafeMakeLogicalPath . T.splitOn "/" . T.pack
diff --git a/herringbone-embed.cabal b/herringbone-embed.cabal
--- a/herringbone-embed.cabal
+++ b/herringbone-embed.cabal
@@ -1,5 +1,5 @@
 name:                herringbone-embed
-version:             0.1.0
+version:             0.1.1
 synopsis:            Embed preprocessed web assets in your executable with Template Haskell.
 description:         Embed preprocessed web assets in your executable with Template Haskell.
 license:             MIT
@@ -11,7 +11,7 @@
 cabal-version:       >=1.10
 
 library
-  exposed-modules:     Web.Herringbone.Precompile
+  exposed-modules:     Web.Herringbone.Embed
   build-depends:       base >=4.6 && <5,
                        herringbone,
                        system-filepath,
