MVP Bundling is now implemented

This commit gets bundling to the point where it can be used now

TODO:
- Get ESBuild Stdout/stderr to not pop up in psb output
- figure out how to split off map files so I'm not shunting them into
  script tags
This commit is contained in:
Pagwin 2026-02-23 17:14:31 -05:00
parent 8082f95491
commit b3808f4136
No known key found for this signature in database
GPG key ID: 81137023740CA260
4 changed files with 62 additions and 18 deletions

View file

@ -29,7 +29,7 @@ library
hs-source-dirs: src
exposed-modules: Markdown HTML Logger IR Logger.Shake Psb.Main Utilities Utilities.FilePath Utilities.Action Utilities.Javascript Utilities.CSS Templates Types Config Utilities.Bundling
other-modules: Utilities.Parsing
build-depends: base >=4.20 && < 4.21, mustache >=2.4.2, shake >= 0.19.8, deriving-aeson >= 0.2.9, aeson, text >= 2.1.2, time, unordered-containers, yaml, megaparsec >= 9.7.0, transformers >= 0.6.2, css-syntax >= 0.1.0.2
build-depends: base >=4.20 && < 4.21, mustache >=2.4.2, shake >= 0.19.8, deriving-aeson >= 0.2.9, aeson, text >= 2.1.2, time, unordered-containers, yaml, megaparsec >= 9.7.0, transformers >= 0.6.2, bytestring
default-extensions: ApplicativeDo DataKinds NamedFieldPuns DerivingVia LambdaCase TypeApplications DeriveGeneric OverloadedRecordDot NamedFieldPuns DuplicateRecordFields DisambiguateRecordFields FlexibleInstances
test-suite test-markdown-parse

View file

@ -26,7 +26,7 @@ import Text.Megaparsec (errorBundlePretty)
import Text.Mustache (ToMustache (toMustache))
import Types
import Utilities.Action (getPublishedPosts, isDraft', markdownToHtml, markdownToPost, now, psbProgress)
import Utilities.Bundling (bundled)
import Utilities.Bundling (BuildOracleVariant (CSS, Javascript), bundled)
import qualified Utilities.CSS as CSS
import Utilities.FilePath (indexHtmlOutputPath, indexHtmlSourcePaths, isMarkdownPost, urlConvert)
import qualified Utilities.Javascript as JS
@ -78,7 +78,6 @@ buildRules = do
postsRule
rss
bundled
pure ()
-- css_resources
-- js_resources
@ -130,6 +129,8 @@ markdownPost src = do
post <- readMarkdownPost src
let rPost = fromPost post
postHtml <- applyTemplate "post.html" rPost
css_bundle <- Shake.askOracle CSS
js_bundle <- Shake.askOracle Javascript
time <- Utilities.Action.now
-- Shake.putInfo $ T.unpack $ urlConvert target
@ -138,7 +139,9 @@ markdownPost src = do
{ pageTitle = rPostTitle rPost,
pageContent = postHtml,
pageNow = time,
pageUrl = urlConvert target
pageUrl = urlConvert target,
pageBundleCss = map T.pack css_bundle,
pageBundleJs = map T.pack js_bundle
}
applyTemplateAndWrite "default.html" page target
@ -154,13 +157,17 @@ home =
let posts' = map fromPost posts
html <- applyTemplate "home.html" $ HM.singleton "posts" posts'
time <- Utilities.Action.now
css_bundle <- Shake.askOracle CSS
js_bundle <- Shake.askOracle Javascript
-- Shake.putInfo $ T.unpack $ urlConvert target
let page =
Page
{ pageTitle = T.pack "Home",
pageContent = html,
pageNow = time,
pageUrl = urlConvert target
pageUrl = urlConvert target,
pageBundleCss = map T.pack css_bundle,
pageBundleJs = map T.pack js_bundle
}
applyTemplateAndWrite "default.html" page target

View file

@ -12,8 +12,10 @@ data Page = Page
pageContent :: Text,
-- build time
pageNow :: Text,
--
pageUrl :: Text
pageUrl :: Text,
-- from Bundles
pageBundleCss :: [Text],
pageBundleJs :: [Text]
}
deriving (Show, Generic)
deriving (ToJSON) via PrefixedSnake "page" Page

View file

@ -1,13 +1,27 @@
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
module Utilities.Bundling
( bundled,
BuildOracleVariant
( CSS,
Javascript
),
)
where
import Config (buildDir, cssGlobs, jsGlobs, outputDir)
import Development.Shake (Action, RuleResult, Rules, addOracle, cmd_, command_, getDirectoryFiles, need, (%>))
import Data.Aeson
import Data.Aeson (decode)
import Data.Aeson.Key (toText)
import qualified Data.Aeson.KeyMap as KM
import qualified Data.ByteString.Lazy as BL
import Data.Maybe (fromJust)
import Data.String (IsString (fromString))
import Data.Text (Text)
import qualified Data.Text as T
import Development.Shake (Action, RuleResult, Rules, addOracle, addOracleCache, cmd_, command_, getDirectoryFiles, need, newCache, readFile', (%>))
import Development.Shake.Classes
import Development.Shake.FilePath ((</>))
import GHC.Generics (Generic)
@ -32,10 +46,13 @@ resource_dir = outputDir </> "resources"
-- indicate completion/fulfill a need directive without rebuilding even when files
-- are left unchanged, maybe have the need be a $(filename).hash which we compute
-- ourselves based on the unminified input
bundled :: Rules (BuildOracleVariant -> Action BuildOutputs)
bundled = addOracle $ \q -> case q of
CSS -> bundle_css
Javascript -> bundle_scripts
bundled :: Rules ()
bundled = do
-- TODO: Need to adjust this oracle to split out source maps from js and css files
oracle <- addOracleCache $ \q -> case q of
CSS -> bundle_css
Javascript -> bundle_scripts
pure ()
css_dir :: FilePath
css_dir = resource_dir </> "css"
@ -52,21 +69,39 @@ css_esbuild_options =
"--metafile=" ++ css_meta_file
]
newtype Metafile = Metafile
{ outputs :: Object -- keys are the file paths
}
deriving (Show)
instance FromJSON Metafile where
parseJSON = withObject "Metafile" $ \o ->
Metafile <$> o .: "outputs"
outputPaths :: Metafile -> BuildOutputs
outputPaths = map (T.unpack . toText) . KM.keys . outputs
metafile_outputs :: FilePath -> Action BuildOutputs
metafile_outputs metafile_path = do
src <- readFile' metafile_path
let intermediate = fromJust $ decode $ fromString src
pure $ outputPaths intermediate
-- need to take an input of resouces/blah.css
-- and in addition to bundling it
bundle_css :: Action BuildOutputs
bundle_css = do
need cssGlobs
css_files <- getDirectoryFiles "" cssGlobs
cmd_ "esbuild" (generic_esbuild_options ++ css_esbuild_options ++ css_files)
pure $ error "TODO: pull the list of files from the meta file"
cmd_ ("esbuild" :: String) (generic_esbuild_options ++ css_esbuild_options ++ css_files)
metafile_outputs css_meta_file
-- Javascript and typescript
-- potentially:
-- "--target=es2020"
-- , "--format=esm"
js_esbuild_options :: [String]
js_esbuild_options = ["--outdir=" ++ js_dir, "--splitting", "--metafile=" ++ js_meta_file]
js_esbuild_options = ["--outdir=" ++ js_dir, "--splitting", "--format=esm", "--metafile=" ++ js_meta_file]
js_meta_file :: FilePath
js_meta_file = buildDir </> "esbuild-js-meta.json"
@ -77,6 +112,6 @@ js_dir = resource_dir </> "js"
bundle_scripts :: Action BuildOutputs
bundle_scripts = do
need jsGlobs
js_files <- getDirectoryFiles "" cssGlobs
cmd_ "esbuild" (generic_esbuild_options ++ js_esbuild_options ++ js_files)
pure $ error "TODO: pull the list of files from the meta file"
js_files <- getDirectoryFiles "" jsGlobs
cmd_ ("esbuild" :: String) (generic_esbuild_options ++ js_esbuild_options ++ js_files)
metafile_outputs js_meta_file