From 2acb37749a132604b5d3dec6ebb0acfcbcfdd8e1 Mon Sep 17 00:00:00 2001 From: Onyeka Obi Date: Tue, 31 Mar 2026 10:16:13 -0700 Subject: [PATCH 1/2] Report a clear error when lamdera/codecs is missing from elm.json The early dependency check only verified lamdera/core was present, so projects missing lamdera/codecs (e.g. elm-pages) hit an opaque Map.! crash during JS codegen. Now Checks.hs also validates that lamdera/codecs is reachable, and the graph lookup in JavaScript.hs uses Map.findWithDefault to produce a descriptive message naming the exact missing global. Fixes #59. --- builder/src/Reporting/Exit.hs | 8 ++++++++ compiler/src/Generate/JavaScript.hs | 15 ++++++++++++--- extra/Lamdera/Checks.hs | 10 +++++++--- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/builder/src/Reporting/Exit.hs b/builder/src/Reporting/Exit.hs index ebcafcb0..b87df0b4 100644 --- a/builder/src/Reporting/Exit.hs +++ b/builder/src/Reporting/Exit.hs @@ -962,6 +962,7 @@ data Outline | OutlineNoAppCore | OutlineNoAppJson | OutlineLamderaMissingDeps + | OutlineLamderaMissingCodecs | OutlineLamderaReplacementPackageVersionTooLow Pkg.Name V.Version V.Version | OutlineLamderaReplacementPackageVersionTooHigh Pkg.Name V.Version V.Version @@ -1064,6 +1065,13 @@ toOutlineReport problem = , D.reflow "Note: if you're trying to run a normal Elm app, use the elm binary instead." ] + OutlineLamderaMissingCodecs -> + Help.report "MISSING DEPENDENCY" (Just "elm.json") + "A Lamdera application must have \"lamdera/codecs\" as a dependency." + [ D.reflow "Wire code generation relies on this package. You can install it with:" + , D.indent 4 $ D.green $ "lamdera install lamdera/codecs" + ] + OutlineLamderaReplacementPackageVersionTooLow name replacedVersion elmJsonVersion -> Help.report "UNSUPPORTED VERSION" (Just "elm.json") ("This version of the Lamdera compiler supports the following range for \"" <> Pkg.toChars name <> "\":") diff --git a/compiler/src/Generate/JavaScript.hs b/compiler/src/Generate/JavaScript.hs index 1f25fa39..152596c6 100644 --- a/compiler/src/Generate/JavaScript.hs +++ b/compiler/src/Generate/JavaScript.hs @@ -12,7 +12,6 @@ import Prelude hiding (cycle, print) import qualified Data.ByteString.Builder as B import Data.Monoid ((<>)) import qualified Data.List as List -import Data.Map ((!)) import qualified Data.Map as Map import qualified Data.Name as Name import qualified Data.Set as Set @@ -23,6 +22,7 @@ import qualified AST.Optimized as Opt import qualified Data.Index as Index import qualified Elm.Kernel as K import qualified Elm.ModuleName as ModuleName +import qualified Elm.Package as Pkg import qualified Generate.JavaScript.Builder as JS import qualified Generate.JavaScript.Expression as Expr import qualified Generate.JavaScript.Functions as Functions @@ -194,10 +194,10 @@ addGlobalHelp mode graph global state = let addDeps deps someState = Set.foldl' (addGlobal mode graph) someState deps - + argLookup = makeArgLookup graph in - case graph ! global of + case Map.findWithDefault (error $ globalNotFound global) global graph of -- @LAMDERA Opt.Define (Opt.Function args body) deps | length args > 1 -> @@ -716,3 +716,12 @@ toMainEsmExports mode mains = in "export const Elm = " <> exports <> ";" + +globalNotFound :: Opt.Global -> String +globalNotFound (Opt.Global (ModuleName.Canonical pkg modul) name) = + "Global not found in dependency graph: " + ++ Pkg.toChars pkg ++ ":" ++ Name.toChars modul ++ "." ++ Name.toChars name + ++ "\n This likely means a required package is missing from elm.json." + ++ "\n If you are using the Lamdera compiler, make sure lamdera/codecs is installed:" + ++ "\n lamdera install lamdera/codecs" + diff --git a/extra/Lamdera/Checks.hs b/extra/Lamdera/Checks.hs index f9cb6c7d..a0be0527 100644 --- a/extra/Lamdera/Checks.hs +++ b/extra/Lamdera/Checks.hs @@ -42,10 +42,14 @@ runChecks root shouldCheckLamdera direct indirect default_ = do return $ Left err Right () -> + let allDeps = Map.union direct indirect in if Map.member Pkg.lamderaCore direct - then do - onlyWhen shouldCheckLamdera (Lamdera.Checks.runChecks_ root) - default_ + then + if not (Map.member Pkg.lamderaCodecs allDeps) + then return $ Left Exit.OutlineLamderaMissingCodecs + else do + onlyWhen shouldCheckLamdera (Lamdera.Checks.runChecks_ root) + default_ else if shouldCheckLamdera then return $ Left Exit.OutlineLamderaMissingDeps From dee7c2f841f86b014b235001685cffd8810e647c Mon Sep 17 00:00:00 2001 From: Onyeka Obi Date: Wed, 1 Apr 2026 14:37:40 -0700 Subject: [PATCH 2/2] Gate lamdera/codecs check on shouldCheckLamdera (miniBill review feedback) --- extra/Lamdera/Checks.hs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/extra/Lamdera/Checks.hs b/extra/Lamdera/Checks.hs index a0be0527..e8f3d890 100644 --- a/extra/Lamdera/Checks.hs +++ b/extra/Lamdera/Checks.hs @@ -45,11 +45,14 @@ runChecks root shouldCheckLamdera direct indirect default_ = do let allDeps = Map.union direct indirect in if Map.member Pkg.lamderaCore direct then - if not (Map.member Pkg.lamderaCodecs allDeps) - then return $ Left Exit.OutlineLamderaMissingCodecs - else do - onlyWhen shouldCheckLamdera (Lamdera.Checks.runChecks_ root) - default_ + if shouldCheckLamdera + then + if not (Map.member Pkg.lamderaCodecs allDeps) + then return $ Left Exit.OutlineLamderaMissingCodecs + else do + Lamdera.Checks.runChecks_ root + default_ + else default_ else if shouldCheckLamdera then return $ Left Exit.OutlineLamderaMissingDeps