diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+0.3.0.3
+-------
+<https://github.com/mstksg/ghcjs-websockets/releases/tag/v0.3.0.3>
+
+*   Added CPP an cabal file flags necessary to enable building on (normal)
+    GHC, for hackage and usage with hybrid projects.
+
 0.3.0.2
 -------
 <https://github.com/mstksg/ghcjs-websockets/releases/tag/v0.3.0.2>
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
 *ghcjs-websockets* aims to provide a clean, idiomatic, efficient, low-level,
 out-of-your-way, bare bones, concurrency-aware interface with minimal
 abstractions over the [Javascript Websockets API][jsapi], inspired by common
-Haskell idioms found in libraries like [io-stream][] and the server-side
+Haskell idioms found in libraries like [io-streams][] and the server-side
 [websockets][] library, targeting compilation to Javascript with `ghcjs`.
 
 The interface abstracts websockets as simple IO/file handles, with additional
@@ -25,7 +25,7 @@
 Documenation is [online on github pages][documentation].
 
 [jsapi]: http://www.w3.org/TR/websockets/
-[io-stream]: http://hackage.haskell.org/package/io-streams
+[io-streams]: http://hackage.haskell.org/package/io-streams
 [websockets]: http://hackage.haskell.org/package/websockets
 [binary]: http://hackage.haskell.org/package/binary
 [documentation]: http://mstksg.github.io/ghcjs-websockets/JavaScript-WebSockets.html
@@ -137,6 +137,14 @@
 These will normally be deleted; however, you can use
 `closeConnectionLeftovers` or `withUrlLeftovers` to grab a list of the raw
 `SocketMsg`s remaining after closing.
+
+### Issues and Roadmap
+
+As of now, there are still some exceptions that might be thrown by the
+Javascript websockets API that are not explicitly handled by the library.  For
+the most part, things are usable and asynchronous exceptions (in Haskell)
+should all be handled well at this point.  There are also some small aspects
+of the websockets API that aren't yet accessible through the library.
 
 ### Copyright
 
diff --git a/ghcjs-websockets.cabal b/ghcjs-websockets.cabal
--- a/ghcjs-websockets.cabal
+++ b/ghcjs-websockets.cabal
@@ -1,5 +1,5 @@
 name:                ghcjs-websockets
-version:             0.3.0.2
+version:             0.3.0.3
 synopsis:            GHCJS interface for the Javascript Websocket API
 description:
                      Documentation online at
@@ -90,19 +90,26 @@
   type:     git
   location: https://github.com/mstksg/ghcjs-websockets
 
+flag ghcjs
+  description: Tell cabal we are using ghcjs (work around until hackage supports impl(ghcjs))
+  default: True
+
 library
   exposed-modules:     JavaScript.WebSockets
                      , JavaScript.WebSockets.Internal
   -- ghcjs-options: -O2
   other-modules:       JavaScript.Blob
                      , JavaScript.WebSockets.FFI
+                     , JavaScript.NoGHCJS
   -- other-extensions:
   ghc-options:         -Wall
   build-depends:       base              >= 4.7      && < 5
                      , base64-bytestring >= 1
                      , binary            >= 0.7
                      , bytestring        >= 0.10
-                     , ghcjs-base        >= 0.1
                      , text              >= 1
+  -- if impl(ghcjs)
+  if flag(ghcjs)
+    build-depends:     ghcjs-base        >= 0.1
   hs-source-dirs:      src
   default-language:    Haskell2010
diff --git a/src/JavaScript/Blob.hs b/src/JavaScript/Blob.hs
--- a/src/JavaScript/Blob.hs
+++ b/src/JavaScript/Blob.hs
@@ -11,24 +11,37 @@
 
 import Control.Exception (mask_)
 import Data.ByteString   (ByteString)
+
+#ifdef ghcjs_HOST_OS
 import GHCJS.Foreign     (bufferByteString)
 import GHCJS.Types       (JSRef)
-
+#else
+import JavaScript.NoGHCJS
+#endif
 
 data Blob_
 type Blob = JSRef Blob_
 
+#ifdef ghcjs_HOST_OS
 foreign import javascript interruptible  "var reader = new FileReader();\
                                           reader.addEventListener('loadend', function() {\
                                             $c(reader.result);\
                                           });\
                                           reader.readAsArrayBuffer($1);"
-    ffi_readBlob :: Blob -> IO (JSRef a)
+  ffi_readBlob :: Blob -> IO (JSRef a)
 
-foreign import javascript unsafe "$1 instanceof Blob" ffi_blobCheck :: JSRef a -> IO Bool
+foreign import javascript unsafe "$1 instanceof Blob"
+  ffi_blobCheck :: JSRef a -> IO Bool
+#else
+ffi_readBlob :: Blob -> IO (JSRef a)
+ffi_blobCheck :: JSRef a -> IO Bool
 
+ffi_readBlob = error "ffi_readBlob: only available in JavaScript"
+ffi_blobCheck = error "ffi_blobCheck: only available in JavaScript"
+#endif
+
 readBlob :: Blob -> IO ByteString
 readBlob b = bufferByteString 0 0 =<< mask_ (ffi_readBlob b)
 
 isBlob :: JSRef a -> IO Bool
-isBlob ref = ffi_blobCheck ref
+isBlob = ffi_blobCheck
diff --git a/src/JavaScript/NoGHCJS.hs b/src/JavaScript/NoGHCJS.hs
new file mode 100644
--- /dev/null
+++ b/src/JavaScript/NoGHCJS.hs
@@ -0,0 +1,50 @@
+{-# OPTIONS_HADDOCK hide #-}
+
+module JavaScript.NoGHCJS where
+
+data JSArray a
+data JSBool
+data JSObject a
+data JSRef a
+
+type JSString = String
+
+jsTrue :: a
+jsTrue = error "jsTrue: only available in JavaScript"
+
+setProp :: a
+setProp = error "setProp: only available in JavaScript"
+
+newObj :: a
+newObj = error "newObj: only available in JavaScript"
+
+toJSString :: a
+toJSString = error "toJSString: only available in JavaScript"
+
+fromArray :: a
+fromArray = error "fromArray: only available in JavaScript"
+
+getPropMaybe :: a
+getPropMaybe = error "getPropMaybe: only available in JavaScript"
+
+fromJSBool :: a
+fromJSBool = error "fromJSBool: only available in JavaScript"
+
+newArray :: a
+newArray = error "newArray: only available in JavaScript"
+
+jsNull :: a
+jsNull = error "jsNull: only available in JavaScript"
+
+fromJSString :: a
+fromJSString = error "fromJSString: only available in JavaScript"
+
+fromJSRef :: a
+fromJSRef = error "fromJSRef: only available in JavaScript"
+
+isNull :: a
+isNull = error "isNull: only available in JavaScript"
+
+bufferByteString :: Int -> Int -> a
+bufferByteString = error "bufferByteString: only available in JavaScript"
+
diff --git a/src/JavaScript/WebSockets.hs b/src/JavaScript/WebSockets.hs
--- a/src/JavaScript/WebSockets.hs
+++ b/src/JavaScript/WebSockets.hs
@@ -42,7 +42,6 @@
   , connectionCloseReason
   , connectionOrigin
   -- * Sending data
-  -- $sending
   , sendData
   , sendData_
   , sendText
@@ -52,7 +51,6 @@
   , send
   , send_
   -- * Receiving data
-  -- $receiving
   , receive
   , receiveMaybe
   , receiveText
diff --git a/src/JavaScript/WebSockets/FFI.hs b/src/JavaScript/WebSockets/FFI.hs
--- a/src/JavaScript/WebSockets/FFI.hs
+++ b/src/JavaScript/WebSockets/FFI.hs
@@ -23,7 +23,12 @@
   ) where
 
 import Data.Text   (Text)
+
+#ifdef ghcjs_HOST_OS
 import GHCJS.Types (JSRef, JSArray, JSString, JSObject, JSBool)
+#else
+import JavaScript.NoGHCJS
+#endif
 
 data Socket_
 type Socket = JSRef Socket_
@@ -38,6 +43,7 @@
 
 type WSCloseEvent = JSObject ()
 
+#ifdef ghcjs_HOST_OS
 foreign import javascript unsafe "$1.close();"
   ws_closeSocket :: Socket -> IO ()
 
@@ -99,3 +105,26 @@
 
 foreign import javascript unsafe "$1.readyState"
   ws_readyState :: Socket -> IO Int
+#else
+
+ws_closeSocket :: Socket -> IO ()
+ws_socketSend :: Socket -> JSString -> IO ()
+ws_handleOpen :: Socket -> IO Socket
+ws_newSocket :: JSString -> ConnectionQueue -> ConnectionWaiters -> IO Socket
+ws_awaitConn :: ConnectionQueue -> ConnectionWaiters -> WaiterKilled -> IO (JSRef ())
+ws_clearWaiters :: ConnectionWaiters -> IO ()
+ws_clearQueue :: ConnectionQueue -> IO ()
+ws_handleClose :: Socket -> IO WSCloseEvent
+ws_readyState :: Socket -> IO Int
+
+ws_closeSocket = error "ws_closeSocket: only available in JavaScript"
+ws_socketSend = error "ws_socketSend: only available in JavaScript"
+ws_handleOpen = error "ws_handleOpen: only available in JavaScript"
+ws_newSocket = error "ws_newSocket: only available in JavaScript"
+ws_awaitConn = error "ws_awaitConn: only available in JavaScript"
+ws_clearWaiters = error "ws_clearWaiters: only available in JavaScript"
+ws_clearQueue = error "ws_clearQueue: only available in JavaScript"
+ws_handleClose = error "ws_handleClose: only available in JavaScript"
+ws_readyState = error "ws_readyState: only available in JavaScript"
+
+#endif
diff --git a/src/JavaScript/WebSockets/Internal.hs b/src/JavaScript/WebSockets/Internal.hs
--- a/src/JavaScript/WebSockets/Internal.hs
+++ b/src/JavaScript/WebSockets/Internal.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE FlexibleInstances #-}
 {-# LANGUAGE IncoherentInstances #-}
@@ -27,6 +28,7 @@
     Connection(..)
   , SocketMsg(..)
   , ConnClosing(..)
+  , Socket
   -- ** Typeclasses
   , WSSendable(..)
   , WSReceivable(..)
@@ -61,9 +63,6 @@
 import Data.Text.Encoding        (decodeUtf8', encodeUtf8, decodeUtf8)
 import Data.Traversable          (mapM)
 import Data.Typeable             (Typeable)
-import GHCJS.Foreign
-import GHCJS.Marshal             (fromJSRef)
-import GHCJS.Types               (JSRef, JSString, isNull)
 import JavaScript.Blob           (Blob, isBlob, readBlob)
 import JavaScript.WebSockets.FFI
 import Prelude hiding            (mapM)
@@ -71,6 +70,16 @@
 
 import qualified Data.ByteString.Base64      as B64
 import qualified Data.ByteString.Base64.Lazy as B64L
+
+#ifdef ghcjs_HOST_OS
+import GHCJS.Foreign             (jsTrue, setProp, newObj, toJSString
+                                , fromArray, getPropMaybe, fromJSBool
+                                , newArray, jsNull, fromJSString )
+import GHCJS.Marshal             (fromJSRef)
+import GHCJS.Types               (JSRef, JSString, isNull)
+#else
+import JavaScript.NoGHCJS
+#endif
 
 -- | Encapsulates a (reference to a) Javascript Websocket connection.  Can
 -- be created/accessed with either 'openConnection' or (preferably)
