mirror of
https://github.com/srid/ema.git
synced 2024-11-29 09:25:14 +03:00
FileSystem -> unionmount
This commit is contained in:
parent
32b51222d6
commit
cabae54a23
@ -5,6 +5,7 @@
|
||||
- Websocket API: Add `ema.switchRoute` to switch to other routes in live server.
|
||||
- Helpers
|
||||
- `Ema.Helpers.PathTree` moved to separate package *pathtree*.
|
||||
- `Ema.Helpers.FileSystem` moved to separate package *unionmount*.
|
||||
|
||||
## 0.4.0.0 -- 2022-01-19
|
||||
|
||||
|
@ -17,13 +17,13 @@ When switching to a new route or when receiving the new HTML, Ema uses [morphdom
|
||||
|
||||
### Haskell reload
|
||||
|
||||
Finally, hot reload on _code_ changes are supported via [ghcid](https://github.com/ndmitchell/ghcid). The [template repo](https://github.com/srid/ema-template)'s `bin/run` script uses ghcid underneath. Any HTML DSL (like blaze-html -- as used by the [Blaze helper](guide/helpers/blaze.md)) or CSS DSL automatically gets supported for hot-reload. If you choose to use a file-based HTML template language, you can enable hot-reload on template change using the [FileSystem helper](guide/helpers/filesystem.md).
|
||||
Finally, hot reload on _code_ changes are supported via [ghcid](https://github.com/ndmitchell/ghcid). The [template repo](https://github.com/srid/ema-template)'s `bin/run` script uses ghcid underneath. Any HTML DSL (like blaze-html -- as used by the [Blaze helper](guide/helpers/blaze.md)) or CSS DSL automatically gets supported for hot-reload. If you choose to use a file-based HTML template language, you can enable hot-reload on template change using the [`unionmount` library](guide/helpers/filesystem.md).
|
||||
|
||||
Note that if your application makes use of threads, it is important to setup cleanup handlers so that `ghcid` doesn't leave [ghost](https://stackoverflow.com/q/24999636/55246) processes behind. Helpers like [`race_`](https://hackage.haskell.org/package/async-2.2.3/docs/Control-Concurrent-Async.html#v:race_) will do this automatically (incidentally it is used by `runEma` for running the user IO action).
|
||||
|
||||
### Data reload
|
||||
|
||||
For anything outside of the Haskell code, your code becomes responsible for monitoring and updating the model [LVar](concepts/lvar.md). The [filesystem helper](guide/helpers/filesystem.md) already provides utilities to facilitate this for monitoring changes to files and directories.
|
||||
For anything outside of the Haskell code, your code becomes responsible for monitoring and updating the model [LVar](concepts/lvar.md). The [`unionmount` library](guide/helpers/filesystem.md) already provides utilities to facilitate this for monitoring changes to files and directories.
|
||||
|
||||
## Handling errors
|
||||
|
||||
|
@ -6,5 +6,5 @@ order: 5
|
||||
Beyond the model and route types, Ema leaves it up to you as to how to develop your site. The following are not *required* when using Ema; nevertheless they are useful inasmuch as they capture common patterns in writing a good static site:
|
||||
|
||||
* [Blaze](guide/helpers/blaze.md) -- [We recommend--but not mandate--Tailwind for CSS and blaze-html as HTML DSL]{.item-intro}
|
||||
* [Working with files](guide/helpers/filesystem.md) -- [Ema provides a helper to support hot-reload on files]{.item-intro}
|
||||
* [Working with files](guide/helpers/filesystem.md) -- [Use `unionmount` to support hot-reload on files]{.item-intro}
|
||||
* [Converting Markdown](guide/helpers/markdown.md) -- [Pointers on how to work with Markdown files]{.item-intro}
|
@ -17,44 +17,27 @@ runEma render $ \model -> do
|
||||
|
||||
For monitoring local files on disk you would typically use something like [fsnotify](https://hackage.haskell.org/package/fsnotify) in place of `observeFileSystem`. What is the point of doing this? To support [hot reload](concepts/hot-reload.md) on _data_ change. Imagine that your static site is generated based on Markdown files as well as HTML templates on disk. If either the Markdown file, or a HTML template file is modified, we want the web browser to hot reload the updated HTML *instantly*. This is enabled by storing both these kinds of files in the application [model](guide/model.md) and using [LVar](concepts/lvar.md) to update it *over time*.
|
||||
|
||||
For filesystem changes, Ema provides a helper based on `fsnotify` in the `Ema.Helper.FileSystem` module. You can use it as follows
|
||||
Much of this is provided by the `System.UnionMount` module from [unionmount](https://hackage.haskell.org/package/unionmount) package. You should use it:
|
||||
|
||||
```haskell
|
||||
import qualified Ema.Helper.FileSystem as FileSystem
|
||||
|
||||
type Model = Map FilePath Text
|
||||
import qualified System.UnionMount as UnionMount
|
||||
|
||||
Ema.runEma render $ \model -> do
|
||||
LVar.set model =<< do
|
||||
mdFiles <- FileSystem.filesMatching "." ["**/*.md"]
|
||||
forM mdFiles readFileText
|
||||
<&> Map.fromList
|
||||
FileSystem.onChange "." $ \fp -> \case
|
||||
FileSystem.Update ->
|
||||
when (takeExtension fp == ".md") $ do
|
||||
log $ "Update: " <> fp
|
||||
s <- readFileText fp
|
||||
LVar.modify model $ Map.insert fp s
|
||||
FileSystem.Delete ->
|
||||
whenJust (takeExtension fp == ".md") $ do
|
||||
log $ "Delete: " <> fp
|
||||
LVar.modify model $ Map.delete fp
|
||||
let pats = [((), "**/*.md")]
|
||||
ignorePats = [".*"]
|
||||
void . UnionMount.mountOnLVar "." pats ignorePats model model0 $ \() fp action -> do
|
||||
case action of
|
||||
UnionMount.Refresh _ () -> do
|
||||
when (takeExtension fp == ".md") $ do
|
||||
log $ "Update: " <> fp
|
||||
s <- readFileText fp
|
||||
pure $ Map.insert fp s
|
||||
UnionMount.Delete ->
|
||||
whenJust (takeExtension fp == ".md") $ do
|
||||
log $ "Delete: " <> fp
|
||||
pure $ Map.delete fp
|
||||
```
|
||||
|
||||
In most cases, however, you probably want to use the higher level function `mountOnLVar`. It "mounts" the files you specify onto the [model LVar](concepts/lvar.md) such that any changes to them are *automatically* reflected in your [model](guide/model.md) value.
|
||||
|
||||
```haskell
|
||||
Ema.runEma render $ \model -> do
|
||||
FileSystem.mountOnLVar "." ["**/*.md"] [] model def $ \() fp -> \case
|
||||
FileSystem.Update () -> do
|
||||
s <- readFileText fp
|
||||
pure $ Map.insert fp s
|
||||
FileSystem.Delete ->
|
||||
pure $ Map.delete fp
|
||||
```
|
||||
`mountOnLVar` "mounts" the files you specify onto the [model LVar](concepts/lvar.md) such that any changes to them are *automatically* reflected in your [model](guide/model.md) value.
|
||||
|
||||
[Full example here](https://github.com/srid/ema-template/blob/master/src/Main.hs).
|
||||
|
||||
This functionality is mostly provided by the [unionmount] library.
|
||||
|
||||
[unionmount]: https://hackage.haskell.org/package/unionmount
|
@ -26,7 +26,7 @@ runEma render $ \_act model ->
|
||||
liftIO $ threadDelay $ 1 * 1000000
|
||||
```
|
||||
|
||||
In this contrived example ([full code here](https://github.com/srid/ema/blob/master/src/Ema/Example/Ex02_Clock.hs)), we are using `UTCTime` as the model. We set the initial value using `LVar.set`, and then continually update the current time every second. Every time the model gets updated, the web browser will [hot reload](concepts/hot-reload.md) to display the up to date value. For the `BlogPosts` model, you would typically use [fsnotify](https://hackage.haskell.org/package/fsnotify) to monitor changes to the underlying Markdown files, but note that Ema provides [a helper](guide/helpers/filesystem.md) for that.
|
||||
In this contrived example ([full code here](https://github.com/srid/ema/blob/master/src/Ema/Example/Ex02_Clock.hs)), we are using `UTCTime` as the model. We set the initial value using `LVar.set`, and then continually update the current time every second. Every time the model gets updated, the web browser will [hot reload](concepts/hot-reload.md) to display the up to date value. For the `BlogPosts` model, you would typically use [fsnotify](https://hackage.haskell.org/package/fsnotify) to monitor changes to the underlying Markdown files, or even better use [the unionmount library](guide/helpers/filesystem.md).
|
||||
|
||||
## Advanced tips
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
cabal-version: 2.4
|
||||
name: ema
|
||||
version: 0.5.1.0
|
||||
version: 0.5.2.0
|
||||
license: AGPL-3.0-only
|
||||
copyright: 2021 Sridhar Ratnakumar
|
||||
maintainer: srid@srid.ca
|
||||
@ -139,7 +139,6 @@ library
|
||||
if (flag(with-helpers) || flag(with-examples))
|
||||
exposed-modules:
|
||||
Ema.Helper.Blaze
|
||||
Ema.Helper.FileSystem
|
||||
Ema.Helper.Markdown
|
||||
|
||||
other-modules:
|
||||
|
@ -1,7 +0,0 @@
|
||||
-- | TODO: Deprecate this module!
|
||||
module Ema.Helper.FileSystem
|
||||
( module X,
|
||||
)
|
||||
where
|
||||
|
||||
import System.UnionMount as X
|
Loading…
Reference in New Issue
Block a user