Skip to content

Generate a default favicon.ico in public folder, don't generate one on compile #2625

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 43 commits into from
Apr 28, 2025

Conversation

FranjoMindek
Copy link
Contributor

@FranjoMindek FranjoMindek commented Apr 4, 2025

New projects start with favicon.ico inside of public directory.
If there is no favicon.ico we still exclude the favicon <link> tag from the <head> of index.html.

Fixes #1979

Question for reviewers: Do we, and where do we notify users of new behavior in docs?

TODO: golden tests

Comment on lines 184 to 191
faviconFd = C.mkTmplFd . C.asTmplFile $ [relfile|public/favicon.ico|]
extPublicFileDrafts = map C.mkPublicFileDraft $ AS.externalPublicFiles spec
templateData =
object
[ "title" .= (AS.App.title (snd $ getApp spec) :: String),
"head" .= (maybe "" (intercalate "\n") (AS.App.head $ snd $ getApp spec) :: String)
"head"
.= (maybe "" (intercalate "\n") (AS.App.head $ snd $ getApp spec) :: String),
"isFaviconPresent" .= checkIfFileDraftExists faviconFd extPublicFileDrafts
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something feels off here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, old approach, but let's improve it.

This code wants to know something about user-defined file paths. Instead of directly checking what it wants to know, it first transofrms file paths into file drafts, and then does the (slightly incorrect) check there.

We should extract the knowledge we need as close to the source data as possible, not later down the road after further procesing. In fact, this function doesn't even need the favicon file draft. It's creating one just to check something about the data needed to construct it.

Think about what to do here and expand when you figure it out:

Here's how I'd do it, compare it with your approach:

"isFaviconPresent" .= didUserProvideFavicon

-- ...

didUserProvideFavicon = didUserProvidePublicFile faviconPathInPublicDir $ AS.externalPublicFiles spec
faviconPathInPublicDir = [relfile|public/favicon.ico|]

-- This used to be `checkIfFileDraftExists`
didUserProvidePublicFile :: ...

@FranjoMindek FranjoMindek requested a review from Copilot April 7, 2025 12:46
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 4 out of 7 changed files in this pull request and generated no comments.

Files not reviewed (3)
  • waspc/data/Generator/templates/react-app/index.html: Language not supported
  • waspc/src/Wasp/Generator/WebAppGenerator.hs: Language not supported
  • waspc/waspc.cabal: Language not supported

@FranjoMindek
Copy link
Contributor Author

Copilot reviewed 4 out of 7 changed files in this pull request and generated no comments.

Files not reviewed (3)

  • waspc/data/Generator/templates/react-app/index.html: Language not supported
  • waspc/src/Wasp/Generator/WebAppGenerator.hs: Language not supported
  • waspc/waspc.cabal: Language not supported

Bro can't do Haskell

@sodic
Copy link
Contributor

sodic commented Apr 8, 2025

Bro can't do Haskell

Not over yet... Btw, is this ready for review? I see it's still a draft.

@FranjoMindek FranjoMindek marked this pull request as ready for review April 8, 2025 09:27
@FranjoMindek
Copy link
Contributor Author

It's ready for review

@infomiho
Copy link
Contributor

infomiho commented Apr 9, 2025

Question for reviewers: Do we, and where do we notify users of new behavior in docs?

If it's a breaking change, we put it in the migration docs 👍 e.g. https://wasp.sh/docs/migration-guides/migrate-from-0-15-to-0-16

@infomiho
Copy link
Contributor

infomiho commented Apr 9, 2025

@FranjoMindek did I get the logic correctly:

  1. include the default favicon.ico
  2. users can delete that and our code no longer generated the <link> tag in the HTML file
  3. if users decide to use e.g. favicon.svg they need to include their own <link>?

I'll review this PR more after you confirm I understood 👍

@FranjoMindek
Copy link
Contributor Author

@FranjoMindek did I get the logic correctly:

  1. include the default favicon.ico
  2. users can delete that and our code no longer generated the <link> tag in the HTML file
  3. if users decide to use e.g. favicon.svg they need to include their own <link>?

I'll review this PR more after you confirm I understood 👍

Yes.
I'll create the discussion we talked about in #wasp-dev discord channel.

@cprecioso cprecioso mentioned this pull request Apr 10, 2025
4 tasks
Copy link
Contributor

@sodic sodic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work noticing something's off with the code!

I left some comments that explain it.

Comment on lines 194 to 198
checkIfFileDraftExists :: FileDraft -> [FileDraft] -> Bool
checkIfFileDraftExists draftToCheck drafts = dstPathToCheck `elem` dstPaths
where
dstPaths = map FD.getDstPath drafts
dstPathToCheck = FD.getDstPath draftToCheck
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function claims to check whether a file draft exists (and implies to be comparing file drafts), but it only compares their paths. We should either:

  • Change its signature to Path -> [Path] -> Bool, which just turns it into a wrapper around elem.
  • Improve its name.
  • Remove it.

Also, it seems to be comparing destination paths instead of source paths, which coincidentally works but is semantically incorrect. Thefore, I vote for removing replacing the function with a more appropriate one (more on this in another comment).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also old code I extracted out since it was used on two places (and possibly more in future).
Didn't want to do any bigger changes with File System since that part of Haskell and Wasp is still a bit unclear to me. And whole logic on how it works was a bit confusing e.g. why are destination paths compared to compare file drafts. I'll try to understand it a bit more first then and see how to improve it.

++ ifUserDidntProvideFile genManifestFd
where
publicFiles = AS.externalPublicFiles spec
extPublicFileDrafts = map C.mkPublicFileDraft publicFiles
genFaviconFd = C.mkTmplFd (C.asTmplFile [relfile|public/favicon.ico|])
genManifestFd = C.mkTmplFdWithData tmplFile tmplData
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Old code, but this function's name is wrong - gen implies it's a generator monad but it's just a file draft.

Comment on lines 184 to 191
faviconFd = C.mkTmplFd . C.asTmplFile $ [relfile|public/favicon.ico|]
extPublicFileDrafts = map C.mkPublicFileDraft $ AS.externalPublicFiles spec
templateData =
object
[ "title" .= (AS.App.title (snd $ getApp spec) :: String),
"head" .= (maybe "" (intercalate "\n") (AS.App.head $ snd $ getApp spec) :: String)
"head"
.= (maybe "" (intercalate "\n") (AS.App.head $ snd $ getApp spec) :: String),
"isFaviconPresent" .= checkIfFileDraftExists faviconFd extPublicFileDrafts
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, old approach, but let's improve it.

This code wants to know something about user-defined file paths. Instead of directly checking what it wants to know, it first transofrms file paths into file drafts, and then does the (slightly incorrect) check there.

We should extract the knowledge we need as close to the source data as possible, not later down the road after further procesing. In fact, this function doesn't even need the favicon file draft. It's creating one just to check something about the data needed to construct it.

Think about what to do here and expand when you figure it out:

Here's how I'd do it, compare it with your approach:

"isFaviconPresent" .= didUserProvideFavicon

-- ...

didUserProvideFavicon = didUserProvidePublicFile faviconPathInPublicDir $ AS.externalPublicFiles spec
faviconPathInPublicDir = [relfile|public/favicon.ico|]

-- This used to be `checkIfFileDraftExists`
didUserProvidePublicFile :: ...

@FranjoMindek
Copy link
Contributor Author

According to pool on discord, we will refactor the current solution so that the link tags are provided in the wasp configs head property.

Copy link
Contributor

@infomiho infomiho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments, mostly about the prose


### 🔧 Small improvements

- Show a friendlier error when there are no routes defined in the wasp file ([#2643](https://github.com/wasp-lang/wasp/pull/2643))
- Show a friendlier error when there are no routes defined in the wasp file ([#2643](https://github.com/wasp-lang/wasp/pull/2643)).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Auto format?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I've seen older versions had them so I manually re-added them for all missing ones

}

route RootRoute { path: "/", to: MainPage }
page MainPage {
component: import { MainPage } from "@src/MainPage"
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing newline

@@ -161,13 +161,11 @@ genPublicDir :: AppSpec -> Generator [FileDraft]
genPublicDir spec =
return $
extPublicFileDrafts
++ ifUserDidntProvideFile genFaviconFd
++ ifUserDidntProvideFile genManifestFd
++ ifUserDidntProvideFile manifestFd
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to do the same thing for manifest.json as we did for favicon.ico? 🤷

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With time possibly yes, that would be an another issue though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm more for user doing configuration in userland, but I know Matija and Martin probably want to also keep it magical. The question is where to draw the line.

### 2. Add a default `favicon.ico` to the public folder

This step is necessary only if you have no `favicon.ico` in your `public` folder.
In that case add a default `favicon.ico` to your `public` folder.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In that case add a default `favicon.ico` to your `public` folder.
You should add a `favicon.ico` to your `public` folder. If you want to keep the default, download it here: [link].

I'd add the link to download the default for people that don't really care / don't have a special favicon in mind. This is a great place to link to a favicon generator for people that want to have their logo as favicon.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any go-to recommendation for favicon generators?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, this is a soft recommendation, what ever feels okay for you as a dev, people with less experience will appreciate your tip.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FranjoMindek and others added 16 commits April 15, 2025 17:12
Co-authored-by: Mihovil Ilakovac <[email protected]>
Co-authored-by: Mihovil Ilakovac <[email protected]>
@FranjoMindek FranjoMindek requested a review from infomiho April 17, 2025 09:06
@FranjoMindek FranjoMindek self-assigned this Apr 18, 2025
# Conflicts:
#	waspc/ChangeLog.md
#	web/docs/migration-guides/migrate-from-0-16-to-0-17.md
#	web/docs/tutorial/02-project-structure.md
Copy link
Contributor

@infomiho infomiho left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make sure the CI is passing.

I really like this change, it makes things easier to understand without reading any docs on how to customize stuff, you see the file, you change it and it just works.

@FranjoMindek FranjoMindek merged commit 75db3d3 into main Apr 28, 2025
6 checks passed
@FranjoMindek FranjoMindek deleted the franjo/fb/favicon branch April 28, 2025 13:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Place favicon.ico in the public dir by default
3 participants