Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Adds support for a client public folder #1229

Merged
merged 21 commits into from
Jun 15, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions waspc/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
### Breaking changes
- Wasp's # action now saves only the fields relevant to the auth process to the database. This prevents users from injecting arbitrary data into the database.

### Public folder support
Wasp now supports a `public` folder in the `client` folder. This folder will be copied to the `public` folder in the build folder. This is useful for adding static assets to your project, like favicons, robots.txt, etc.

## v0.10.6

### Bug fixes
Expand Down
Binary file not shown.
7 changes: 5 additions & 2 deletions waspc/src/Wasp/AppSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,13 @@ resolveRef :: (IsDecl d) => AppSpec -> Ref d -> (String, d)
resolveRef spec ref =
fromMaybe
( error $
"Failed to resolve declaration reference: " ++ refName ref ++ "."
"Failed to resolve declaration reference: "
++ refName ref
++ "."
++ " This should never happen, as Analyzer should ensure all references in AppSpec are valid."
)
$ find ((== refName ref) . fst) $ getDecls spec
$ find ((== refName ref) . fst) $
getDecls spec

doesConfigFileExist :: AppSpec -> Path' (Rel WaspProjectDir) File' -> Bool
doesConfigFileExist spec file =
Expand Down
7 changes: 2 additions & 5 deletions waspc/src/Wasp/Generator/DbGenerator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import Data.Aeson (object, (.=))
import Data.Maybe (fromMaybe, maybeToList)
import Data.Text (Text, pack)
import StrongPath (Abs, Dir, File, Path', Rel, (</>))
import qualified StrongPath as SP
import Wasp.AppSpec (AppSpec, getEntities)
import qualified Wasp.AppSpec as AS
import qualified Wasp.AppSpec.App as AS.App
Expand All @@ -34,6 +33,7 @@ import Wasp.Generator.DbGenerator.Common
)
import qualified Wasp.Generator.DbGenerator.Operations as DbOps
import Wasp.Generator.FileDraft (FileDraft, createCopyDirFileDraft, createTemplateFileDraft)
import Wasp.Generator.FileDraft.CopyDirFileDraft (CopyDirFileDraftDstDirStrategy (RemoveExistingDstDir))
import Wasp.Generator.Monad
( Generator,
GeneratorError (..),
Expand Down Expand Up @@ -82,10 +82,7 @@ genPrismaSchema spec = do
Psl.Ast.Model.Model entityName (AS.Entity.getPslModelBody entity)

genMigrationsDir :: AppSpec -> Generator (Maybe FileDraft)
genMigrationsDir spec =
return $
AS.migrationsDir spec >>= \waspMigrationsDir ->
Just $ createCopyDirFileDraft (SP.castDir genProjectMigrationsDir) (SP.castDir waspMigrationsDir)
genMigrationsDir spec = return $ createCopyDirFileDraft RemoveExistingDstDir genProjectMigrationsDir <$> AS.migrationsDir spec
where
genProjectMigrationsDir = Wasp.Generator.DbGenerator.Common.dbRootDirInProjectRootDir </> Wasp.Generator.DbGenerator.Common.dbMigrationsDirInDbRootDir

Expand Down
5 changes: 1 addition & 4 deletions waspc/src/Wasp/Generator/ExternalCodeGenerator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ module Wasp.Generator.ExternalCodeGenerator
where

import Data.Maybe (mapMaybe)
import StrongPath (File', Path', Rel, (</>))
import qualified StrongPath as SP
import qualified System.FilePath as FP
import qualified Wasp.AppSpec.ExternalCode as EC
Expand Down Expand Up @@ -35,7 +34,5 @@ genFile strategy file
genResourceFile :: C.ExternalCodeGeneratorStrategy -> EC.File -> Generator FileDraft
genResourceFile strategy file = return $ FD.createCopyFileDraft relDstPath absSrcPath
where
relDstPath = C._extCodeDirInProjectRootDir strategy </> dstPathInGenExtCodeDir
relDstPath = C._resolveDstFilePath strategy $ EC.filePathInExtCodeDir file
absSrcPath = EC.fileAbsPath file
dstPathInGenExtCodeDir :: Path' (Rel C.GeneratedExternalCodeDir) File'
dstPathInGenExtCodeDir = C.castRelPathFromSrcToGenExtCodeDir $ EC.filePathInExtCodeDir file
9 changes: 7 additions & 2 deletions waspc/src/Wasp/Generator/ExternalCodeGenerator/Common.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ module Wasp.Generator.ExternalCodeGenerator.Common
where

import Data.Text (Text)
import StrongPath (Dir, File', Path', Rel)
import StrongPath (File', Path', Rel)
import qualified StrongPath as SP
import Wasp.AppSpec.ExternalCode (SourceExternalCodeDir)
import Wasp.Generator.Common (ProjectRootDir)

-- TODO: consider refactoring the usage of GeneratedExternalCodeDir since
-- generated code might end up in multiple places (e.g. ext-src/ but also public/).
-- Name should probably be narrowed down to something that represent only the ext-src/
-- directory. Maybe GeneratedExtSrcDir?

-- | Path to the directory where ext code will be generated.
data GeneratedExternalCodeDir

Expand All @@ -26,5 +31,5 @@ data ExternalCodeGeneratorStrategy = ExternalCodeGeneratorStrategy
-- Also takes text of the file. Returns text where special @wasp imports have been replaced with
-- imports that will work.
_resolveJsFileWaspImports :: Path' (Rel GeneratedExternalCodeDir) File' -> Text -> Text,
_extCodeDirInProjectRootDir :: Path' (Rel ProjectRootDir) (Dir GeneratedExternalCodeDir)
_resolveDstFilePath :: Path' (Rel SourceExternalCodeDir) File' -> Path' (Rel ProjectRootDir) File'
}
2 changes: 1 addition & 1 deletion waspc/src/Wasp/Generator/ExternalCodeGenerator/Js.hs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ genSourceFile strategy file = return $ FD.createTextFileDraft dstPath text'

text = EC.fileText file
text' = C._resolveJsFileWaspImports strategy filePathInGenExtCodeDir text
dstPath = C._extCodeDirInProjectRootDir strategy </> filePathInGenExtCodeDir
dstPath = C._resolveDstFilePath strategy filePathInSrcExtCodeDir

-- | Replaces imports that start with "@wasp/" with imports that start from the src dir of the app.
resolveJsFileWaspImportsForExtCodeDir ::
Expand Down
12 changes: 9 additions & 3 deletions waspc/src/Wasp/Generator/FileDraft.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import StrongPath (Abs, Dir, File, Path', Rel)
import qualified StrongPath as SP
import Wasp.Generator.Common (ProjectRootDir)
import qualified Wasp.Generator.FileDraft.CopyAndModifyTextFileDraft as CMTextFD
import Wasp.Generator.FileDraft.CopyDirFileDraft (CopyDirFileDraftDstDirStrategy)
import qualified Wasp.Generator.FileDraft.CopyDirFileDraft as CopyDirFD
import qualified Wasp.Generator.FileDraft.CopyFileDraft as CopyFD
import qualified Wasp.Generator.FileDraft.TemplateFileDraft as TmplFD
Expand Down Expand Up @@ -98,12 +99,17 @@ createCopyFileDraftIfExists dstPath srcPath =
CopyFD._failIfSrcDoesNotExist = False
}

createCopyDirFileDraft :: Path' (Rel ProjectRootDir) (Dir a) -> Path' Abs (Dir b) -> FileDraft
createCopyDirFileDraft dstPath srcPath =
createCopyDirFileDraft ::
CopyDirFileDraftDstDirStrategy ->
Path' (Rel ProjectRootDir) (Dir a) ->
Path' Abs (Dir b) ->
FileDraft
createCopyDirFileDraft dstDirStrategy dstPath srcPath =
FileDraftCopyDirFd $
CopyDirFD.CopyDirFileDraft
{ CopyDirFD._dstPath = SP.castDir dstPath,
CopyDirFD._srcPath = SP.castDir srcPath
CopyDirFD._srcPath = SP.castDir srcPath,
CopyDirFD._dstDirStrategy = dstDirStrategy
}

createTextFileDraft :: Path' (Rel ProjectRootDir) (File a) -> Text -> FileDraft
Expand Down
19 changes: 17 additions & 2 deletions waspc/src/Wasp/Generator/FileDraft/CopyDirFileDraft.hs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module Wasp.Generator.FileDraft.CopyDirFileDraft
( CopyDirFileDraft (..),
CopyDirFileDraftDstDirStrategy (..),
)
where

Expand Down Expand Up @@ -35,15 +36,29 @@ data CopyDirFileDraft = CopyDirFileDraft
{ -- | Path where the dir will be copied to.
_dstPath :: !(Path' (Rel ProjectRootDir) Dir'),
-- | Absolute path of source dir to copy.
_srcPath :: !(Path' Abs Dir')
_srcPath :: !(Path' Abs Dir'),
-- | What to do with the dst dir if it already exists.
_dstDirStrategy :: !CopyDirFileDraftDstDirStrategy
}
deriving (Show, Eq)

data CopyDirFileDraftDstDirStrategy
= -- | Remove the dst dir if it already exists.
RemoveExistingDstDir
| -- | Write over the dst dir if it already exists, without removing the existing files.
WriteOverExistingDstDir
deriving (Show, Eq)

instance Writeable CopyDirFileDraft where
write projectRootAbsPath draft = do
srcDirExists <- doesDirectoryExist $ SP.fromAbsDir srcPathAbsDir
dstDirExists <- doesDirectoryExist $ SP.fromAbsDir dstPathAbsDir
when dstDirExists $ removeDirectoryRecursive dstPathAbsDir

case _dstDirStrategy draft of
RemoveExistingDstDir ->
when dstDirExists $ removeDirectoryRecursive dstPathAbsDir
WriteOverExistingDstDir -> pure ()

when srcDirExists $ do
createDirectoryIfMissing True (SP.fromAbsDir dstPathAbsDir)
copyDirectoryRecursive srcPathAbsDir dstPathAbsDir
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ where

import StrongPath (Dir, Path', Rel, reldir, (</>))
import qualified StrongPath as SP
import Wasp.Generator.ExternalCodeGenerator.Common (ExternalCodeGeneratorStrategy (..), GeneratedExternalCodeDir)
import Wasp.Generator.ExternalCodeGenerator.Common
( ExternalCodeGeneratorStrategy (..),
GeneratedExternalCodeDir,
castRelPathFromSrcToGenExtCodeDir,
)
import Wasp.Generator.ExternalCodeGenerator.Js (resolveJsFileWaspImportsForExtCodeDir)
import qualified Wasp.Generator.ServerGenerator.Common as C

Expand All @@ -31,8 +35,9 @@ mkExtCodeGeneratorStrategy :: Path' (Rel C.ServerSrcDir) (Dir GeneratedExternalC
mkExtCodeGeneratorStrategy extCodeDirInServerSrcDir =
ExternalCodeGeneratorStrategy
{ _resolveJsFileWaspImports = resolveJsFileWaspImportsForExtCodeDir (SP.castRel extCodeDirInServerSrcDir),
_extCodeDirInProjectRootDir =
_resolveDstFilePath = \filePath ->
C.serverRootDirInProjectRootDir
</> C.serverSrcDirInServerRootDir
</> extCodeDirInServerSrcDir
</> castRelPathFromSrcToGenExtCodeDir filePath
}
35 changes: 22 additions & 13 deletions waspc/src/Wasp/Generator/WebAppGenerator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ import Wasp.Generator.Common
)
import qualified Wasp.Generator.ConfigFile as G.CF
import Wasp.Generator.ExternalCodeGenerator (genExternalCodeDir)
import Wasp.Generator.FileDraft
import Wasp.Generator.FileDraft (FileDraft, createTextFileDraft)
import qualified Wasp.Generator.FileDraft as FD
import Wasp.Generator.Monad (Generator)
import qualified Wasp.Generator.NpmDependencies as N
import Wasp.Generator.WebAppGenerator.AuthG (genAuth)
Expand All @@ -51,6 +52,7 @@ import Wasp.Util ((<++>))

genWebApp :: AppSpec -> Generator [FileDraft]
genWebApp spec = do
extClientCodeFileDrafts <- genExternalCodeDir extClientCodeGeneratorStrategy (AS.externalClientFiles spec)
sequence
[ genFileCopy [relfile|README.md|],
genFileCopy [relfile|tsconfig.json|],
Expand All @@ -65,10 +67,10 @@ genWebApp spec = do
genGitignore,
genIndexHtml spec
]
<++> genPublicDir spec
<++> genSrcDir spec
<++> genExternalCodeDir extClientCodeGeneratorStrategy (AS.externalClientFiles spec)
<++> return extClientCodeFileDrafts
<++> genExternalCodeDir extSharedCodeGeneratorStrategy (AS.externalSharedFiles spec)
<++> genPublicDir spec extClientCodeFileDrafts
<++> genDotEnv spec
<++> genUniversalDir
<++> genEnvValidationScript
Expand Down Expand Up @@ -184,18 +186,25 @@ genGitignore =
(C.asTmplFile [relfile|gitignore|])
(C.asWebAppFile [relfile|.gitignore|])

genPublicDir :: AppSpec -> Generator [FileDraft]
genPublicDir spec = do
return
[ genFaviconFd,
genManifestFd
]
genPublicDir :: AppSpec -> [FileDraft] -> Generator [FileDraft]
genPublicDir spec extCodeFileDrafts =
return $
ifUserDidntProvideFile genFaviconFd
++ ifUserDidntProvideFile genManifestFd
where
genFaviconFd = C.mkTmplFd (C.asTmplFile [relfile|public/favicon.ico|])
genManifestFd =
let tmplData = object ["appName" .= (fst (getApp spec) :: String)]
tmplFile = C.asTmplFile [relfile|public/manifest.json|]
in C.mkTmplFdWithData tmplFile tmplData
genManifestFd = C.mkTmplFdWithData tmplFile tmplData
where
tmplData = object ["appName" .= (fst (getApp spec) :: String)]
tmplFile = C.asTmplFile [relfile|public/manifest.json|]

ifUserDidntProvideFile fileDraft =
if checkIfFileDraftExists fileDraft
then []
else [fileDraft]

checkIfFileDraftExists = (`elem` existingDstPaths) . FD.getDstPath
existingDstPaths = map FD.getDstPath extCodeFileDrafts

genIndexHtml :: AppSpec -> Generator FileDraft
genIndexHtml spec =
Expand Down
7 changes: 7 additions & 0 deletions waspc/src/Wasp/Generator/WebAppGenerator/Common.hs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ module Wasp.Generator.WebAppGenerator.Common
WebAppTemplatesDir,
WebAppTemplatesSrcDir,
toViteImportPath,
staticAssetsDirInWebAppDir,
WebAppStaticAssetsDir,
)
where

Expand All @@ -43,6 +45,8 @@ data WebAppTemplatesDir

data WebAppTemplatesSrcDir

data WebAppStaticAssetsDir

instance GeneratedSrcDir WebAppSrcDir

serverRootDirFromWebAppRootDir :: Path' (Rel WebAppRootDir) (Dir ServerRootDir)
Expand All @@ -65,6 +69,9 @@ webAppRootDirInProjectRootDir = [reldir|web-app|]
webAppSrcDirInWebAppRootDir :: Path' (Rel WebAppRootDir) (Dir WebAppSrcDir)
webAppSrcDirInWebAppRootDir = [reldir|src|]

staticAssetsDirInWebAppDir :: Path' (Rel WebAppRootDir) (Dir WebAppStaticAssetsDir)
staticAssetsDirInWebAppDir = [reldir|public|]

-- | Path to generated web app src/ directory, relative to the root directory of the whole generated project.
webAppSrcDirInProjectRootDir :: Path' (Rel ProjectRootDir) (Dir WebAppSrcDir)
webAppSrcDirInProjectRootDir = webAppRootDirInProjectRootDir </> webAppSrcDirInWebAppRootDir
Expand Down
29 changes: 24 additions & 5 deletions waspc/src/Wasp/Generator/WebAppGenerator/ExternalCodeGenerator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ module Wasp.Generator.WebAppGenerator.ExternalCodeGenerator
)
where

import Data.Maybe (fromJust)
import StrongPath (Dir, Path', Rel, reldir, (</>))
import qualified StrongPath as SP
import Wasp.Generator.ExternalCodeGenerator.Common (ExternalCodeGeneratorStrategy (..), GeneratedExternalCodeDir)
import Wasp.Generator.ExternalCodeGenerator.Common
( ExternalCodeGeneratorStrategy (..),
GeneratedExternalCodeDir,
castRelPathFromSrcToGenExtCodeDir,
)
import Wasp.Generator.ExternalCodeGenerator.Js (resolveJsFileWaspImportsForExtCodeDir)
import qualified Wasp.Generator.WebAppGenerator.Common as C
import Wasp.Util.FilePath (removePathPrefix)

extClientCodeGeneratorStrategy :: ExternalCodeGeneratorStrategy
extClientCodeGeneratorStrategy = mkExtCodeGeneratorStrategy extClientCodeDirInWebAppSrcDir
Expand All @@ -31,8 +37,21 @@ mkExtCodeGeneratorStrategy :: Path' (Rel C.WebAppSrcDir) (Dir GeneratedExternalC
mkExtCodeGeneratorStrategy extCodeDirInWebAppSrcDir =
ExternalCodeGeneratorStrategy
{ _resolveJsFileWaspImports = resolveJsFileWaspImportsForExtCodeDir (SP.castRel extCodeDirInWebAppSrcDir),
_extCodeDirInProjectRootDir =
C.webAppRootDirInProjectRootDir
</> C.webAppSrcDirInWebAppRootDir
</> extCodeDirInWebAppSrcDir
_resolveDstFilePath = resolveDstFilePath
}
where
resolveDstFilePath filePath =
case maybeFilePathInStaticAssetsDir of
Just filePathInStaticAssetsDir ->
C.webAppRootDirInProjectRootDir
</> C.staticAssetsDirInWebAppDir
</> fromJust (SP.parseRelFile filePathInStaticAssetsDir)
Nothing ->
C.webAppRootDirInProjectRootDir
</> C.webAppSrcDirInWebAppRootDir
</> extCodeDirInWebAppSrcDir
</> castRelPathFromSrcToGenExtCodeDir filePath
where
maybeFilePathInStaticAssetsDir = removePathPrefix staticAssetsDir (SP.fromRelFile filePath)

staticAssetsDir = SP.fromRelDir C.staticAssetsDirInWebAppDir
9 changes: 6 additions & 3 deletions waspc/src/Wasp/Project/Analyze.hs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ constructAppSpec ::
constructAppSpec waspDir options decls = do
externalServerCodeFiles <-
ExternalCode.readFiles (CompileOptions.externalServerCodeDirPath options)
externalClientCodeFiles <-
ExternalCode.readFiles (CompileOptions.externalClientCodeDirPath options)

let externalClientCodeDirPath = CompileOptions.externalClientCodeDirPath options
externalClientCodeFiles <- ExternalCode.readFiles externalClientCodeDirPath

externalSharedCodeFiles <-
ExternalCode.readFiles (CompileOptions.externalSharedCodeDirPath options)
maybeMigrationsDir <- findMigrationsDir waspDir
Expand Down Expand Up @@ -86,5 +88,6 @@ findWaspFile waspDir = do
return $ maybeToEither "Couldn't find a single *.wasp file." $ (waspDir </>) <$> find isWaspFile files
where
isWaspFile path =
".wasp" `isSuffixOf` toFilePath path
".wasp"
`isSuffixOf` toFilePath path
&& (length (toFilePath path) > length (".wasp" :: String))
9 changes: 9 additions & 0 deletions waspc/src/Wasp/Project/WebApp.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Wasp.Project.WebApp where

import StrongPath (Dir, Path', Rel, reldir)
import Wasp.AppSpec.ExternalCode (SourceExternalCodeDir)

data StaticAssetsDir

staticAssetsDirInExtClientCodeDir :: Path' (Rel SourceExternalCodeDir) (Dir StaticAssetsDir)
staticAssetsDirInExtClientCodeDir = [reldir|public|]
20 changes: 20 additions & 0 deletions waspc/src/Wasp/Util/FilePath.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Wasp.Util.FilePath
( removePathPrefix,
)
where

import Data.List (isPrefixOf)
import qualified System.FilePath as FP

removePathPrefix :: FilePath -> FilePath -> Maybe FilePath
removePathPrefix pathPrefix path =
if isPathPrefixedWithPrefix
then Just $ drop (length prefixWithTrailingSlash) path
else Nothing
where
isPathPrefixedWithPrefix = prefixWithTrailingSlash `isPrefixOf` path
prefixWithTrailingSlash = ensureTrailingSlash pathPrefix

ensureTrailingSlash :: String -> String
ensureTrailingSlash path | FP.hasTrailingPathSeparator path = path
ensureTrailingSlash path = path ++ [FP.pathSeparator]
Loading