diff --git a/hakyll.cabal b/hakyll.cabal
--- a/hakyll.cabal
+++ b/hakyll.cabal
@@ -1,5 +1,5 @@
 Name:    hakyll
-Version: 3.4.0.0
+Version: 3.4.1.0
 
 Synopsis: A static website compiler library
 Description:
@@ -60,6 +60,7 @@
 
 Library
   Ghc-Options:    -Wall
+  Ghc-Prof-Options: -auto-all -caf-all
   Hs-Source-Dirs: src
 
   Build-Depends:
@@ -73,7 +74,7 @@
     cryptohash   >= 0.7    && < 0.8,
     directory    >= 1.0    && < 1.2,
     filepath     >= 1.0    && < 1.4,
-    hamlet       >= 1.0    && < 1.1,
+    hamlet       >= 1.0    && < 1.2,
     mtl          >= 1      && < 2.2,
     old-locale   >= 1.0    && < 1.1,
     old-time     >= 1.0    && < 1.2,
@@ -84,7 +85,8 @@
     regex-tdfa   >= 1.1    && < 1.2,
     tagsoup      >= 0.12.6 && < 0.13,
     text         >= 0.11   && < 1.12,
-    time         >= 1.1    && < 1.5
+    time         >= 1.1    && < 1.5,
+    lrucache     >= 1.1.1  && < 1.2
 
   Exposed-Modules:
     Hakyll
@@ -180,7 +182,7 @@
     cryptohash   >= 0.7    && < 0.8,
     directory    >= 1.0    && < 1.2,
     filepath     >= 1.0    && < 1.4,
-    hamlet       >= 1.0    && < 1.1,
+    hamlet       >= 1.0    && < 1.2,
     mtl          >= 1      && < 2.2,
     old-locale   >= 1.0    && < 1.1,
     old-time     >= 1.0    && < 1.2,
@@ -192,6 +194,7 @@
     tagsoup      >= 0.12.6 && < 0.13,
     text         >= 0.11   && < 1.12,
     time         >= 1.1    && < 1.5,
+    lrucache     >= 1.1.1  && < 1.2,
     unix         >= 2.4    && < 2.6
 
   Other-modules:
diff --git a/src/Hakyll/Core/Resource/Provider.hs b/src/Hakyll/Core/Resource/Provider.hs
--- a/src/Hakyll/Core/Resource/Provider.hs
+++ b/src/Hakyll/Core/Resource/Provider.hs
@@ -12,6 +12,7 @@
 --
 module Hakyll.Core.Resource.Provider
     ( ResourceProvider (..)
+    , resourceList
     , makeResourceProvider
     , resourceExists
     , resourceDigest
@@ -22,6 +23,7 @@
 import Control.Concurrent (MVar, readMVar, modifyMVar_, newMVar)
 import Data.Map (Map)
 import qualified Data.Map as M
+import qualified Data.Set as S
 
 import Data.Time (UTCTime)
 import qualified Crypto.Hash.MD5 as MD5
@@ -34,8 +36,8 @@
 -- | A value responsible for retrieving and listing resources
 --
 data ResourceProvider = ResourceProvider
-    { -- | A list of all resources this provider is able to provide
-      resourceList             :: [Resource]
+    { -- | A set of all resources this provider is able to provide
+      resourceSet              :: S.Set Resource
     , -- | Retrieve a certain resource as string
       resourceString           :: Resource -> IO String
     , -- | Retrieve a certain resource as lazy bytestring
@@ -53,12 +55,17 @@
                      -> (Resource -> IO LB.ByteString)  -- ^ ByteString reader
                      -> (Resource -> IO UTCTime)        -- ^ Time checker
                      -> IO ResourceProvider             -- ^ Resulting provider
-makeResourceProvider l s b t = ResourceProvider l s b t <$> newMVar M.empty
+makeResourceProvider l s b t =
+    ResourceProvider (S.fromList l) s b t <$> newMVar M.empty
 
+-- | Get the list of all resources
+resourceList :: ResourceProvider -> [Resource]
+resourceList = S.toList . resourceSet
+
 -- | Check if a given identifier has a resource
 --
 resourceExists :: ResourceProvider -> Resource -> Bool
-resourceExists provider = flip elem $ resourceList provider
+resourceExists provider = flip S.member $ resourceSet provider
 
 -- | Retrieve a digest for a given resource
 --
diff --git a/src/Hakyll/Core/Store.hs b/src/Hakyll/Core/Store.hs
--- a/src/Hakyll/Core/Store.hs
+++ b/src/Hakyll/Core/Store.hs
@@ -10,18 +10,16 @@
     ) where
 
 import Control.Applicative ((<$>))
-import Control.Concurrent.MVar (MVar, newMVar, readMVar, modifyMVar_)
 import System.FilePath ((</>))
 import System.Directory (doesFileExist)
 import Data.Maybe (fromMaybe)
-import Data.Map (Map)
-import qualified Data.Map as M
 
 import Data.Binary (Binary, encodeFile, decodeFile)
 import Data.Typeable (Typeable, TypeRep, cast, typeOf)
 
 import Hakyll.Core.Identifier
 import Hakyll.Core.Util.File
+import qualified Data.Cache.LRU.IO as LRU
 
 -- | Items we can store
 --
@@ -40,36 +38,42 @@
     { -- | All items are stored on the filesystem
       storeDirectory :: FilePath
     , -- | And some items are also kept in-memory
-      storeMap       :: Maybe (MVar (Map FilePath Storable))
+      storeLRU       :: Maybe (LRU.AtomicLRU FilePath Storable)
     }
 
+-- | The size of the in-memory cache to use in items.
+storeLRUSize :: Maybe Integer
+storeLRUSize = Just 500
+
 -- | Initialize the store
 --
 makeStore :: Bool      -- ^ Use in-memory caching
           -> FilePath  -- ^ Directory to use for hard disk storage
           -> IO Store  -- ^ Store
 makeStore inMemory directory = do
-    mvar <- if inMemory then Just <$> newMVar M.empty else return Nothing
+    lru <- if inMemory
+            then Just <$> LRU.newAtomicLRU storeLRUSize
+            else return Nothing
     return Store
         { storeDirectory = directory
-        , storeMap       = mvar
+        , storeLRU       = lru
         }
 
 -- | Auxiliary: add an item to the map
 --
 cacheInsert :: (Binary a, Typeable a) => Store -> FilePath -> a -> IO ()
-cacheInsert (Store _ Nothing)   _    _     = return ()
-cacheInsert (Store _ (Just mv)) path value =
-    modifyMVar_ mv $ return . M.insert path (Storable value)
+cacheInsert (Store _ Nothing)    _    _     = return ()
+cacheInsert (Store _ (Just lru)) path value =
+    LRU.insert path (Storable value) lru
 
 -- | Auxiliary: get an item from the cache
 --
 cacheLookup :: forall a. (Binary a, Typeable a)
             => Store -> FilePath -> IO (StoreGet a)
 cacheLookup (Store _ Nothing) _      = return NotFound
-cacheLookup (Store _ (Just mv)) path = do
-    map' <- readMVar mv
-    case M.lookup path map' of
+cacheLookup (Store _ (Just lru)) path = do
+    res <- LRU.lookup path lru
+    case res of
         Nothing           -> return NotFound
         Just (Storable s) -> return $ case cast s of
             Nothing -> WrongType (typeOf s) $ typeOf (undefined :: a)
diff --git a/src/Hakyll/Web/CompressCss.hs b/src/Hakyll/Web/CompressCss.hs
--- a/src/Hakyll/Web/CompressCss.hs
+++ b/src/Hakyll/Web/CompressCss.hs
@@ -31,12 +31,12 @@
 compressSeparators :: String -> String
 compressSeparators = replaceAll "; *}" (const "}")
                    . replaceAll " *([{};:]) *" (take 1 . dropWhile isSpace)
-                   . replaceAll ";;*" (const ";")
+                   . replaceAll ";+" (const ";")
 
 -- | Compresses all whitespace.
 --
 compressWhitespace :: String -> String
-compressWhitespace = replaceAll "[ \t\n][ \t\n]*" (const " ")
+compressWhitespace = replaceAll "[ \t\n\r]+" (const " ")
 
 -- | Function that strips CSS comments away.
 --
diff --git a/src/Hakyll/Web/Page/Read.hs b/src/Hakyll/Web/Page/Read.hs
--- a/src/Hakyll/Web/Page/Read.hs
+++ b/src/Hakyll/Web/Page/Read.hs
@@ -4,10 +4,10 @@
     ( readPage
     ) where
 
-import Control.Applicative ((<$>), (<*>), (<*))
+import Control.Applicative ((<$>), (<*>), (<*), (<|>))
 import qualified Data.Map as M
 
-import Text.Parsec.Char (alphaNum, anyChar, char, newline, oneOf, string)
+import Text.Parsec.Char (alphaNum, anyChar, char, oneOf, string)
 import Text.Parsec.Combinator (choice, many1, manyTill, option, skipMany1)
 import Text.Parsec.Prim (many, parse, skipMany, (<?>))
 import Text.Parsec.String (Parser)
@@ -18,6 +18,11 @@
 -- | Space or tab, no newline
 inlineSpace :: Parser Char
 inlineSpace = oneOf ['\t', ' '] <?> "space"
+
+-- | Parse Windows newlines as well (i.e. "\n" or "\r\n")
+newline :: Parser String
+newline = string "\n"   -- Unix
+      <|> string "\r\n" -- DOS
 
 -- | Parse a single metadata field
 --
diff --git a/tests/Hakyll/Web/Template/Tests.hs b/tests/Hakyll/Web/Template/Tests.hs
--- a/tests/Hakyll/Web/Template/Tests.hs
+++ b/tests/Hakyll/Web/Template/Tests.hs
@@ -17,17 +17,18 @@
 tests = fromAssertions "applyTemplate"
     -- Hakyll templates
     [ applyTemplateAssertion readTemplate applyTemplate
-        "bar" "$foo$" [("foo", "bar")]
+        ("bar" @=?) "$foo$" [("foo", "bar")]
 
     , applyTemplateAssertion readTemplate applyTemplate
-        "$ barqux" "$$ $foo$$bar$" [("foo", "bar"), ("bar", "qux")]
+        ("$ barqux" @=?) "$$ $foo$$bar$" [("foo", "bar"), ("bar", "qux")]
 
     , applyTemplateAssertion readTemplate applyTemplate
-        "$foo$" "$foo$" []
+        ("$foo$" @=?) "$foo$" []
 
     -- Hamlet templates
     , applyTemplateAssertion readHamletTemplate applyTemplate
-        "<head><title>notice</title></head><body>A paragraph</body>"
+        (("<head><title>notice</title></head><body>A paragraph</body>" @=?) .
+            filter (/= '\n'))
         "<head>\n\
         \    <title>#{title}\n\
         \<body>\n\
@@ -39,16 +40,16 @@
           missing "bar" = "qux"
           missing x     = reverse x
       in applyTemplateAssertion readTemplate (applyTemplateWith missing)
-        "bar foo ver" "$foo$ $bar$ $rev$" [("bar", "foo")]
+        ("bar foo ver" @=?) "$foo$ $bar$ $rev$" [("bar", "foo")]
     ]
 
 -- | Utility function to create quick template tests
 --
 applyTemplateAssertion :: (String -> Template)
                        -> (Template -> Page String -> Page String)
-                       -> String
+                       -> (String -> Assertion)
                        -> String
                        -> [(String, String)]
                        -> Assertion
-applyTemplateAssertion parser apply expected template page =
-    expected @=? pageBody (apply (parser template) (fromMap $ M.fromList page))
+applyTemplateAssertion parser apply correct template page =
+    correct $ pageBody (apply (parser template) (fromMap $ M.fromList page))
