Skip to content
Browse files

init: stack new yesod blog yesodweb/sqlite && cd yesod-blog

  • Loading branch information...
3v0k4 committed Jun 13, 2019
0 parents commit 7a5782d47e082a8cfcb4e07bac71d88709179c0c
@@ -0,0 +1,4 @@
((haskell-mode . ((haskell-indent-spaces . 4)
(haskell-process-use-ghci . t)))
(hamlet-mode . ((hamlet/basic-offset . 4)
(haskell-process-use-ghci . t))))
@@ -0,0 +1,22 @@
@@ -0,0 +1,43 @@
## Haskell Setup

1. If you haven't already, [install Stack](
* On POSIX systems, this is usually `curl -sSL | sh`
2. Install the `yesod` command line tool: `stack install yesod-bin --install-ghc`
3. Build libraries: `stack build`

If you have trouble, refer to the [Yesod Quickstart guide]( for additional detail.

## Development

Start a development server with:

stack exec -- yesod devel

As your code changes, your site will be automatically recompiled and redeployed to localhost.

## Tests

stack test --flag yesod-blog:library-only --flag yesod-blog:dev

(Because `yesod devel` passes the `library-only` and `dev` flags, matching those flags means you don't need to recompile between tests and development, and it disables optimization to speed up your test compile times).

## Documentation

* Read the [Yesod Book]( online for free
* Check [Stackage]( for documentation on the packages in your LTS Haskell version, or [search it using Hoogle]( Tip: Your LTS version is in your `stack.yaml` file.
* For local documentation, use:
* `stack haddock --open` to generate Haddock documentation for your dependencies, and open that documentation in a browser
* `stack hoogle <function, module or type signature>` to generate a Hoogle database and search for your query
* The [Yesod cookbook]( has sample code for various needs

## Getting Help

* Ask questions on [Stack Overflow, using the Yesod or Haskell tags](
* Ask the [Yesod Google Group](!forum/yesodweb)
* There are several chatrooms you can ask for help:
* For IRC, try Freenode#yesod and Freenode#haskell
* [Functional Programming Slack](, in the #haskell, #haskell-beginners, or #yesod channels.
@@ -0,0 +1,105 @@
-- | Running your app inside GHCi.
-- This option provides significantly faster code reload compared to
-- @yesod devel@. However, you do not get automatic code reload
-- (which may be a benefit, depending on your perspective). To use this:
-- 1. Start up GHCi
-- $ stack ghci yesod-blog:lib --no-load --work-dir .stack-work-devel
-- 2. Load this module
-- > :l app/DevelMain.hs
-- 3. Run @update@
-- > DevelMain.update
-- 4. Your app should now be running, you can connect at http://localhost:3000
-- 5. Make changes to your code
-- 6. After saving your changes, reload by running:
-- > :r
-- > DevelMain.update
-- You can also call @DevelMain.shutdown@ to stop the app
-- There is more information about this approach,
-- on the wiki:
-- WARNING: GHCi does not notice changes made to your template files.
-- If you change a template, you'll need to either exit GHCi and reload,
-- or manually @touch@ another Haskell module.

module DevelMain where

import Prelude
import Application (getApplicationRepl, shutdownApp)

import Control.Monad ((>=>))
import Control.Concurrent
import Data.IORef
import Foreign.Store
import Network.Wai.Handler.Warp
import GHC.Word

-- | Start or restart the server.
-- newStore is from foreign-store.
-- A Store holds onto some data across ghci reloads
update :: IO ()
update = do
mtidStore <- lookupStore tidStoreNum
case mtidStore of
-- no server running
Nothing -> do
done <- storeAction doneStore newEmptyMVar
tid <- start done
_ <- storeAction (Store tidStoreNum) (newIORef tid)
return ()
-- server is already running
Just tidStore -> restartAppInNewThread tidStore
doneStore :: Store (MVar ())
doneStore = Store 0

-- shut the server down with killThread and wait for the done signal
restartAppInNewThread :: Store (IORef ThreadId) -> IO ()
restartAppInNewThread tidStore = modifyStoredIORef tidStore $ \tid -> do
killThread tid
withStore doneStore takeMVar
readStore doneStore >>= start

-- | Start the server in a separate thread.
start :: MVar () -- ^ Written to when the thread is killed.
-> IO ThreadId
start done = do
(port, site, app) <- getApplicationRepl
(runSettings (setPort port defaultSettings) app)
-- Note that this implies concurrency
-- between shutdownApp and the next app that is starting.
-- Normally this should be fine
(\_ -> putMVar done () >> shutdownApp site)

-- | kill the server
shutdown :: IO ()
shutdown = do
mtidStore <- lookupStore tidStoreNum
case mtidStore of
-- no server running
Nothing -> putStrLn "no Yesod app running"
Just tidStore -> do
withStore tidStore $ readIORef >=> killThread
putStrLn "Yesod app is shutdown"

tidStoreNum :: Word32
tidStoreNum = 1

modifyStoredIORef :: Store (IORef a) -> (a -> IO a) -> IO ()
modifyStoredIORef store f = withStore store $ \ref -> do
v <- readIORef ref
f v >>= writeIORef ref
@@ -0,0 +1,6 @@
{-# LANGUAGE PackageImports #-}
import "yesod-blog" Application (develMain)
import Prelude (IO)

main :: IO ()
main = develMain
@@ -0,0 +1,5 @@
import Prelude (IO)
import Application (appMain)

main :: IO ()
main = appMain
BIN +1.31 KB config/favicon.ico
Binary file not shown.
@@ -0,0 +1,70 @@
# After you've edited this file, remove the following line to allow
# `yesod keter` to build your bundle.
user-edited: false

# A Keter app is composed of 1 or more stanzas. The main stanza will define our
# web application. See the Keter documentation for more information on
# available stanzas.

# Your Yesod application.
- type: webapp

# Name of your executable. You are unlikely to need to change this.
# Note that all file paths are relative to the keter.yml file.
# The path given is for Stack projects. If you're still using cabal, change
# to
# exec: ../dist/build/yesod-blog/yesod-blog
exec: ../dist/bin/yesod-blog

# Command line options passed to your application.
args: []

# You can specify one or more hostnames for your application to respond
# to. The primary hostname will be used for generating your application
# root.

# Enable to force Keter to redirect to https
# Can be added to any stanza
requires-secure: false

# Static files.
- type: static-files
root: ../static

# Uncomment to turn on directory listings.
# directory-listing: true

# Redirect plain domain name to www.
- type: redirect

- host:
# secure: false
# port: 80

# Uncomment to switch to a non-permanent redirect.
# status: 303

# Use the following to automatically copy your bundle upon creation via `yesod
# keter`. Uses `scp` internally, so you can set it to a remote destination
# copy-to: user@host:/opt/keter/incoming/

# You can pass arguments to `scp` used above. This example limits bandwidth to
# 1024 Kbit/s and uses port 2222 instead of the default 22
# copy-to-args:
# - "-l 1024"
# - "-P 2222"

# If you would like to have Keter automatically create a PostgreSQL database
# and set appropriate environment variables for it to be discovered, uncomment
# the following line.
# plugins:
# postgres: true
@@ -0,0 +1,18 @@
-- By default this file is used by `persistFileWith` in Model.hs (which is imported by Foundation.hs)
-- Syntax for this file here:

ident Text
password Text Maybe
UniqueUser ident
deriving Typeable
email Text
userId UserId Maybe
verkey Text Maybe
UniqueEmail email
Comment json -- Adding "json" causes ToJSON and FromJSON instances to be derived.
message Text
userId UserId Maybe
deriving Eq
deriving Show
@@ -0,0 +1 @@
User-agent: *
@@ -0,0 +1,14 @@
-- By default this file is used by `parseRoutesFile` in Foundation.hs
-- Syntax for this file here:

/static StaticR Static appStatic
/auth AuthR Auth getAuth

/favicon.ico FaviconR GET
/robots.txt RobotsR GET


/comments CommentR POST

/profile ProfileR GET
@@ -0,0 +1,37 @@
# Values formatted like "_env:YESOD_ENV_VAR_NAME:default_value" can be overridden by the specified environment variable.
# See

static-dir: "_env:YESOD_STATIC_DIR:static"
host: "_env:YESOD_HOST:*4" # any IPv4 host
port: "_env:YESOD_PORT:3000" # NB: The port `yesod devel` uses is distinct from this value. Set the `yesod devel` port from the command line.
ip-from-header: "_env:YESOD_IP_FROM_HEADER:false"

# Default behavior: determine the application root from the request headers.
# Uncomment to set an explicit approot
#approot: "_env:YESOD_APPROOT:http://localhost:3000"

# By default, `yesod devel` runs in development, and built executables use
# production settings (see below). To override this, use the following:
# development: false

# Optional values with the following production defaults.
# In development, they default to the inverse.
# detailed-logging: false
# should-log-all: false
# reload-templates: false
# mutable-static: false
# skip-combining: false
# auth-dummy-login : false

# NB: If you need a numeric value (e.g. 123) to parse as a String, wrap it in single quotes (e.g. "_env:YESOD_PGPASS:'123'")
# See

# See config/test-settings.yml for an override during tests
database: "_env:YESOD_SQLITE_DATABASE:yesod-blog.sqlite3"
poolsize: "_env:YESOD_SQLITE_POOLSIZE:10"

copyright: Insert copyright statement here
#analytics: UA-YOURCODE
@@ -0,0 +1,11 @@
# NOTE: By design, this setting prevents the SQLITE_DATABASE environment variable
# from affecting test runs, so that we don't accidentally affect the
# production database during testing. If you're not concerned about that and
# would like to have environment variable overrides, you could instead use
# something like:
# database: "_env:SQLITE_DATABASE:yesod-blog_test.sqlite3"
database: yesod-blog_test.sqlite3

auth-dummy-login: true

0 comments on commit 7a5782d

Please sign in to comment.
You can’t perform that action at this time.