Skip to content

Commit 581d36a

Browse files
committed
Add option to include WAI middleware for the preview server. Include middleware which adds Refresh headers as an option.
1 parent 61b6e1a commit 581d36a

File tree

4 files changed

+65
-23
lines changed

4 files changed

+65
-23
lines changed

Diff for: lib/Hakyll/Commands.hs

+6-8
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ preview :: Configuration -> Logger -> Rules a -> Int -> IO ()
7777
#ifdef PREVIEW_SERVER
7878
preview conf logger rules port = do
7979
deprecatedMessage
80-
watch conf logger "0.0.0.0" port True rules
80+
watch conf{previewHost = "0.0.0.0", previewPort = port} logger True rules
8181
where
8282
deprecatedMessage = mapM_ putStrLn [ "The preview command has been deprecated."
8383
, "Use the watch command for recompilation and serving."
@@ -90,9 +90,9 @@ preview _ _ _ _ = previewServerDisabled
9090
--------------------------------------------------------------------------------
9191
-- | Watch and recompile for changes
9292

93-
watch :: Configuration -> Logger -> String -> Int -> Bool -> Rules a -> IO ()
93+
watch :: Configuration -> Logger -> Bool -> Rules a -> IO ()
9494
#ifdef WATCH_SERVER
95-
watch conf logger host port runServer rules = do
95+
watch conf logger runServer rules = do
9696
#ifndef mingw32_HOST_OS
9797
_ <- forkIO $ watchUpdates conf update
9898
#else
@@ -108,7 +108,7 @@ watch conf logger host port runServer rules = do
108108
(_, ruleSet) <- run RunModeNormal conf logger rules
109109
return $ rulesPattern ruleSet
110110
loop = threadDelay 100000 >> loop
111-
server' = if runServer then server conf logger host port else loop
111+
server' = if runServer then server conf logger else loop
112112
#else
113113
watch _ _ _ _ _ _ = watchServerDisabled
114114
#endif
@@ -121,11 +121,9 @@ rebuild conf logger rules =
121121

122122
--------------------------------------------------------------------------------
123123
-- | Start a server
124-
server :: Configuration -> Logger -> String -> Int -> IO ()
124+
server :: Configuration -> Logger -> IO ()
125125
#ifdef PREVIEW_SERVER
126-
server conf logger host port = do
127-
let settings = previewSettings conf $ destinationDirectory conf
128-
staticServer logger settings host port
126+
server conf logger = staticServer conf logger
129127
#else
130128
server _ _ _ _ = previewServerDisabled
131129
#endif

Diff for: lib/Hakyll/Core/Configuration.hs

+43-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,23 @@
11
--------------------------------------------------------------------------------
2-
-- | Exports a datastructure for the top-level hakyll configuration
2+
-- | Exports a data structure for the top-level Hakyll configuration.
3+
{-# LANGUAGE OverloadedStrings #-}
34
module Hakyll.Core.Configuration
4-
( Configuration (..)
5+
( -- * Configuration
6+
defaultConfiguration
7+
, Configuration (..)
8+
-- * Utilities
59
, shouldIgnoreFile
610
, shouldWatchIgnore
7-
, defaultConfiguration
11+
-- * Middleware for the preview server
12+
, middlewareRefresh
813
) where
914

1015

1116
--------------------------------------------------------------------------------
1217
import Data.Default (Default (..))
1318
import Data.List (isPrefixOf, isSuffixOf)
19+
import Data.String (fromString)
20+
import Network.Wai (Middleware, mapResponseHeaders)
1421
import qualified Network.Wai.Application.Static as Static
1522
import System.Directory (canonicalizePath)
1623
import System.Exit (ExitCode)
@@ -21,6 +28,14 @@ import System.Process (system)
2128

2229

2330
--------------------------------------------------------------------------------
31+
-- | Specifies the configuration for a Hakyll application.
32+
--
33+
-- Prefer to update record fields from 'defaultConfiguration'
34+
-- instead of constructing a 'Configuration' value directly.
35+
-- For example,
36+
--
37+
-- >>> let config = defaultConfiguration { destinationDirectory = "..." }
38+
--
2439
data Configuration = Configuration
2540
{ -- | Directory in which the output written
2641
destinationDirectory :: FilePath
@@ -96,14 +111,17 @@ data Configuration = Configuration
96111
, -- | Override other settings used by the preview server. Default is
97112
-- 'Static.defaultFileServerSettings'.
98113
previewSettings :: FilePath -> Static.StaticSettings
114+
, -- | WAI middleware which can sit between the preview server
115+
-- and the file serving. Default is to do nothing.
116+
previewMiddleware :: Middleware
99117
}
100118

101119
--------------------------------------------------------------------------------
102120
instance Default Configuration where
103121
def = defaultConfiguration
104122

105123
--------------------------------------------------------------------------------
106-
-- | Default configuration for a hakyll application
124+
-- | Default configuration for a Hakyll application.
107125
defaultConfiguration :: Configuration
108126
defaultConfiguration = Configuration
109127
{ destinationDirectory = "_site"
@@ -119,6 +137,7 @@ defaultConfiguration = Configuration
119137
, previewHost = "127.0.0.1"
120138
, previewPort = 8000
121139
, previewSettings = Static.defaultFileServerSettings
140+
, previewMiddleware = id
122141
}
123142
where
124143
ignoreFile' path
@@ -161,3 +180,23 @@ shouldWatchIgnore conf = do
161180
return (\path ->
162181
let path' = makeRelative fullProviderDir path
163182
in (|| watchIgnore conf path') <$> shouldIgnoreFile conf path)
183+
184+
185+
--------------------------------------------------------------------------------
186+
-- | WAI middleware which tells clients that they should refresh loaded content
187+
-- periodically. Can be used to avoid having to manually reload content.
188+
--
189+
-- For example, the following can be used to have content reloaded
190+
-- every 10 seconds during preview:
191+
--
192+
-- >>> let config = defaultConfiguration { previewMiddleware = middlewareRefresh 10 }
193+
middlewareRefresh
194+
-- | Seconds between refreshes.
195+
:: Int
196+
-- | Middleware which adds the @Refresh@ header to HTTP responses.
197+
-> Middleware
198+
middlewareRefresh seconds app req respond = app req respond'
199+
where
200+
respond' = respond . autoRefresh
201+
autoRefresh = mapResponseHeaders addRefresh
202+
addRefresh rs = ("Refresh", fromString $ show seconds) : rs

Diff for: lib/Hakyll/Main.hs

+3-2
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,11 @@ invokeCommands args conf check logger rules =
110110
Deploy -> Commands.deploy conf
111111
Preview p -> Commands.preview conf logger rules p >> ok
112112
Rebuild -> Commands.rebuild conf logger rules
113-
Server _ _ -> Commands.server conf logger (host args) (port args) >> ok
114-
Watch _ p s -> Commands.watch conf logger (host args) p (not s) rules >> ok
113+
Server _ _ -> Commands.server serverConf{Config.previewPort = port args} logger >> ok
114+
Watch _ p s -> Commands.watch serverConf{Config.previewPort = p} logger (not s) rules >> ok
115115
where
116116
ok = return ExitSuccess
117+
serverConf = conf{Config.previewHost = host args}
117118

118119

119120
--------------------------------------------------------------------------------

Diff for: lib/Hakyll/Preview/Server.hs

+13-9
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,23 @@ import qualified Network.Wai as Wai
1414
import Network.HTTP.Types.Status (Status)
1515

1616
--------------------------------------------------------------------------------
17-
import Hakyll.Core.Logger (Logger)
18-
import qualified Hakyll.Core.Logger as Logger
17+
import Hakyll.Core.Configuration (Configuration(..))
18+
import Hakyll.Core.Logger (Logger)
19+
import qualified Hakyll.Core.Logger as Logger
1920

20-
staticServer :: Logger -- ^ Logger
21-
-> Static.StaticSettings -- ^ Static file server settings
22-
-> String -- ^ Host to bind on
23-
-> Int -- ^ Port to listen on
24-
-> IO () -- ^ Blocks forever
25-
staticServer logger settings host port = do
21+
staticServer :: Configuration -- ^ Hakyll configuration
22+
-> Logger -- ^ Logger
23+
-> IO () -- ^ Blocks forever
24+
staticServer config logger = do
2625
Logger.header logger $ "Listening on http://" ++ host ++ ":" ++ show port
2726
Logger.flush logger -- ensure this line is logged before Warp errors
28-
Warp.runSettings warpSettings $ Static.staticApp settings
27+
Warp.runSettings warpSettings app
2928
where
29+
host = previewHost config
30+
port = previewPort config
31+
settings = previewSettings config $ destinationDirectory config
32+
app = previewMiddleware config $ serverApp
33+
serverApp = Static.staticApp settings
3034
warpSettings = Warp.setLogger noLog
3135
$ Warp.setHost (fromString host)
3236
$ Warp.setPort port Warp.defaultSettings

0 commit comments

Comments
 (0)