Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

remix-test

To begin with, I'm following the Remix "Jokes" app tutorial.

Idea: make it store random facts instead of jokes.

Learning notes

  • Remix nuked this README.md file and I had to recreate it. Should have expected that! Adding the contents below instead.
  • The default entry.server.tsx file contains a handleRequest function that takes a request. That's fine, but it also takes a responseStatusCode and responseHeaders. Am I still able to decide what status code to respond with? This signature is a bit weird to me.
  • Since Remix picks up on certain exports from files (like export const meta) but my IDE doesn't know about that, I'm getting a bunch of linter errors on those lines. I'm not sure where the errors are coming from, since from my recollection eslint doesn't complain about unused exports. It has no knowledge of the other files. It's probably IntelliJ then.
  • The default root.tsx contains several interesting elements:
    • <Outlet /> which is like a Svelte <slot />, as far as I remember.
    • <ScrollRestoration />, probably aptly-named. Its presence surprises me because this used to be a feature of react-router that got dropped after the developers noticed scroll restoration working increasingly better out of the box on major browsers.
      • To-do: find out how <ScrollRestoration /> is implemented.
      • Remix documentation on scroll restoration mentions that this component works by restoring the scroll level before rehydration. This should eliminate the jarring effect of having the scroll point being restored after the page loads completely.
        • The "before rehydration" part is true only by virtue of the <ScrollRestoration /> component being used one line before the <Scripts /> component.
  • The yarn build command finished in 0.44 seconds. Nice!
  • I like that the default app doesn't contain images or marketing text selling Remix. It just has some documentation links.
  • While adding some code and missing an import, the app showed me a build error (expectedly). But then after fixing the error, the app didn't go back to a normal state, and the error remained, even though the build didn't show the error any longer.
  • Adding the new routes, I'm thinking that the structure where facts/new shares a namespace with facts/$factId is not great. What if I wanted slugs instead of IDs, and someone created a fact named new? Other solutions aren't as pretty, though: facts/show/$factId + facts/new, or new-fact + facts/$factId.
  • By exporting a links array, you can add <link> elements to <head> sort of like with react-helmet. They then get picked up by a top-level <Links /> component.
  • The tutorial recommends a file structure for styles that's not great. If the CSS I write is encapsulated together with a route, then why shouldn't their files live together? Having a separate styles directory adds quite a bit of indirection and could make a project hard to navigate.
  • I'm skipping all the Prisma stuff, I think it doesn't fit the purposes of a Remix-specific tutorial. Faking my own database with async functions.
  • I wonder why the tutorial recommends using export let. It looks to me as if the things I'm exporting shouldn't ever be reassigned. I'm changing these to export const, hoping that nothing explodes.
  • The useDataLoader pattern with an export const loader coupled with a useDataLoader call ( imported from remix) feels a bit weird to me. I suppose there must be quite a bit going on at build time for this to be worth the indirection. My first impression is that if it shouldn't be necessary? Why can't I go export const loader = someRemixUtility(async () => {}) instead ( removing the useDataLoader call inside the component)? The client and server bundles can still provide different implementations of someRemixUtility.
    • To-do: find out why export const loader can't be used directly and needs to be accessed via useDataLoader. My guess: the purpose is to call the loader during server rendering and then to reuse the same data during rehydration, to initialize a frontend cache with. Remix developers simply decided to for a standard way to access Remix functionality, and this just looks consistent.
  • There's another insidious result of the indirection introduced by the useDataLoader and export const loader pattern, aggravated by the fact that the suggested type LoaderFunction isn't generic: discrepancies between what loader actually returns and what useDataLoader returns aren't going to be caught unless a type is shared between them. But LoaderFunction isn't generic, so there's no enforcement from Remix to make sure that this is the case. I can have a loader that returns number but then access string[] in useDataLoader and unless I actively share the types, TypeScript won't have a chance to complain. In my opinion, LoaderFunction should take a required type argument for the return type, and another ( perhaps optional?) for query parameters.
    • One could argue that this is the responsibility of the developer, and it is, but by not requiring any type arguments, Remix isn't helping.
    • It's also inconsistent because LoaderFunction takes no type arguments but useDataLoader takes a type argument for the returned data.
  • When submitting data, the type mismatch is more accentuated, because POST requests contain FormData, which bears (as far as I know) no information on the shape of the data from the form. In this case, however, it matters less, because the tutorial calls the user to perform backend validation/parsing of this form data, by going form.get("field-name") and then validating the result.
    • I wonder whether building a way to type-check JSX forms and providing e.g. a TS eslint plug-in that uses the full power of the AST to build type-safe forms would be worth it. I suppose exporting a simple component for use, TypedForm<T> would be enough, or perhaps even more magic, somehow simply type-check <form> elements based on their current children. This is probably not possible because one would need to go into other modules. Maybe the TypedForm<T> approach is good as long as one shares T with child controls.

Default Remix README.md

Development

From your terminal:

npm run dev

This starts your app in development mode, rebuilding assets on file changes.

Deployment

First, build your app for production:

npm run build

Then run the app in production mode:

npm start

Now you'll need to pick a host to deploy it to.

DIY

If you're familiar with deploying node applications, the built-in Remix app server is production-ready.

Make sure to deploy the output of remix build

  • build/
  • public/build/

Using a Template

When you ran npx create-remix@latest there were a few choices for hosting. You can run that again to create a new project, then copy over your app/ folder to the new project that's pre-configured for your target server.

cd ..
# create a new project, and pick a pre-configured host
npx create-remix@latest
cd my-new-remix-app
# remove the new project's app (not the old one!)
rm -rf app
# copy your app over
cp -R ../my-old-remix-app/app app

About

A test/exploration app using Remix. No purpose yet: I'll probably make it record random facts.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages