feat!: move layout route inside directory #89
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Motivation
Developers dogfooding the beta release of Expo Router at scale have mentioned wanting to try a different format for defining Layout Routes. This new format would involve putting the Layout Route in the layout directory and giving it a magic filename (
_layout.js
). This format would replace the existing format of using a sibling file with the same name as the layout folder (Remix-styled).Implementation
In this PR I've added the ability to define a Layout Route as a file named
_layout
inside the layout folder.Projects will need to migrate app-wide:
Stack
to aLayout
unless specified otherwise in a Layout Route atapp/_layout.js
.Considerations
Naming
The purpose of this change is to make the layout easier to find in larger codebases, for this reason, it makes sense to prefix the file with an underscore (e.g.
_layout
,_document
, etc.) so the file floats to the top of the list. The problem with this is that now projects basically can never have a route named_layout
in their app unless they added a custom rewrite. Using_
in URLs is often considered reserved for API routes, middleware, and other dev tools.Another issue with using a set name like
_layout
is that developers must know about this magic name ahead of time. Previously you could name any file using any name you wanted, there were no magic names, reserved routes, or chances of typos causing confusing issues.Projects also have the ability to create conflicting routes:
foo.js
andfoo/index.js
. Makings projects a bit easier to break. We currently assert in this case, but it's suboptimal.This format also makes Expo Router a little less like Remix and still fairly different from Next.js, meaning it's a bit less optimal for developers switching between projects.
One benefit of this new approach is the ability to control the top-most navigator. By creating an
app/_layout.js
developers can control how all top-level routes are presented. This introduces the ability to break default 404 handling and the sitemap, but it also makes it a bit lighter as you could reuse the root navigator without having to create a second root layout.Alternatively, we could consider using an extension like
.layout.js
which would enable the developer to change the file name if needed. The default would beindex.layout.js
or related.At a glance
Before
After
Jump to File
When pressing ⌘P in VS Code and searching "feed" when the project has a Layout Route named feed and an Index Route (
/feed
).Before
Previously, the layout route would be recommended first.
Selecting this would take you to a file like:
Index Routes are nominally more difficult to find because multiple files can be named
index
. This will often net to be less than_layout
, and developers are more used to theindex
format. The entire React stack (including React Native) have special handling forindex
filenames as well.After
The proposed format makes VS Code recommend the Index Route before the Layout Route.
Selecting this would take you to a file like:
This also means the Layout Route is substantially harder to get to. Devs will need to type the name of the route + _layout like "feed/_layout". There is no special handling for files named
_layout
, meaning tooling will often strip the entire file path and just show_layout.js: error ...
.