Scaffolding a new app

Scaffolding a new app

Create a brand new Remix project and add tooling for TypeScript, Tailwind and Prettier.

Video resources

Transcript

In this course, we're going to be building a brand new Remix app from scratch, and we're going to base it off of my own work journal, which is here on my website. This is basically a list of things that I do and I learn. I haven't updated it in just a bit, but it's a really cool project to have, and I loved using it when I did. And so when you finish this course, you're going to have work journal of your own. You're going to be able to create new entries, edit entries, we're going to make our own custom designed form, and see all of the features that Remix gives us in order to create, delete and read data. It's going to be authenticated. So we're going to learn all of the most important parts of Remix and, you're going to end up with something like this for yourself by the end.

Creating a Remix app

So let's come over here to my editor and we're going to create a brand new Remix app. And we'll start by going to remix.run, and we'll click Read the Docs. And we'll see this is how we get started. Now, of course these commands could change over time depending on when you watch this, so I always like to look at the docs to see the best way to start.

So we'll go ahead and run

npx create-remix@latest

We're going to call this work-journal, and we're going to go with "Just the basics". We're going to use the defaults for all these options. We'll use "Remix App Server", we'll use TypeScript, and we'll run npm install.

Now Remix is pretty flexible in terms of how you can actually deploy a Remix app, which adapters you use. For this course, I want to focus on the fundamentals, so we're just going to stick with the basics. I'll explain those options as we move through the course and get to a point where we actually deploy it. But for now, we're just going to start with the basics, and let's go ahead and open our work journal in VSCode.

So here is our basic Remix app. We're going to see some files that are already here kind of set up for us to get going. We're going to see an index route, and if we come over to package.json1, we're going to see the way we develop this is by running

npm run dev

So if we do that and grab our Chrome window, then we can go ahead and visit localhost:3000, and we're going to see this index route is being rendered. So, pretty cool, pretty easy to get started.

Now there's a few more things I want to do to kinda get the environment set up the way I like it. And the first is to install Tailwind.

Installing Tailwind CSS

So, I always like to use the Tailwind site because it, I find it's very up to date in terms of its instructions. We can just type in Remix from tailwindcss.com, and we're going to see they recently added build-in Tailwind CSS support in Remix. So, we already have our Remix app. Let's go ahead and add this to our Remix config:

// remix.config.js
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
  future: {
    unstable_tailwind: true,
  },
};

We'll go ahead and install Tailwind:

npm install -D tailwindcss
npx tailwindcss init

We'll grab this and come over to tailwind.config.js and tell Tailwind where our React components live:

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./app/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {},
  },
  plugins: [],
};

And then we'll create an app/tailwind.css file:

/* app/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

And then we'll copy this import and we'll paste this in our app/root.tsx file:

import type { LinksFunction } from "@remix-run/node";
import stylesheet from "~/tailwind.css";

export const links: LinksFunction = () => [
  { rel: "stylesheet", href: stylesheet },
];

So let's come over to app/root.tsx, close this so we can see what's going on. And let's paste this, and go ahead and import this type from @remix-run/node. So this is basically Remix's way of letting us add stylesheet links to the head tag of our app on a per-route basis. You don't need to worry too much about it now, we can just follow the instructions, but it enables a lot of cool features in Remix.

And so with that, we have one more step. Let's go ahead and restart our build process here, npm run dev, come over to our app, and it looks like Tailwind's working because we see these styles have been reset.

So let's come back to our index route, go ahead and delete this, and say "Hello, Build UI!".And we should be able to say text-blue-500 this, wrap this in a div with some padding, and it looks like Tailwind is working great.

// index.tsx
export default function Index() {
  return (
    <div class="p-20">
      <p className="text-blue-500">Hello, Build UI!</p>
    </div>
  );
}

Tailwind CSS IntelliSense extension

And I just want to mention the Tailwind IntelliSense extension. If you don't have it installed, this is what lets me do things like p-dash, and get all these auto-completes. If I go ahead and view my extensions, and we look for Tailwind, we're going to see this official Tailwind CSS IntelliSense extension for VS Code. This is a must-have when working with Tailwind projects. So make sure you have that installed as well.

Prettier

And the next thing I want to do is go ahead and install Prettier, because right now I can just save this and nothing happens. So let's come over and go to prettier.io. We'll go to "Install Prettier", we'll copy this command:

npm install --save-dev --save-exact prettier

Come over, grab Prettier, and we'll create this .prettier.json file, just an empty one so that our editor knows to use Prettier.

echo {}> .prettier.json

Come up here, and now we can save this in, and this all snaps into place.

Tailwind CSS Prettier plugin

And finally, there is a Tailwind Prettier sorting plugin that I use as well. So let's look for "tailwind prettier plugin" in Google. If we just Google this, it'll be the first thing we see, prettier-plugin-tailwind. And if we click on this and come down, we'll see to get started, just install it as a dev dependency. So let's go ahead and grab this and run it:

npm install -D prettier-plugin-tailwindcss

And if you look at this note, you're going to see that this plugin follows Prettier's autoloading convention, so as long as you've got Prettier set up, it'll start working automatically. And what this does is if we were to go ahead and add flex right here and save – sometimes I find you have to reload the window to get this all to pick it up. But now, when we hit save, we're going to see the flex class sorts to the beginning.

So this is neat because we can do font-medium, and then, oh, we need flex-col, and we hit save, and we're going to get these classes sorted in not only an order that makes semantic sense where more important classes come at the beginning – things like display properties like flex, and less important properties come later, like the font color or some padding values – it's also semantically the right sort order because it's based on the order that Tailwind itself generates its utility classes. So this means you're way less likely to run into any sort of conflicts when you use Tailwind. So I definitely recommend adding Prettier and the Prettier sorting plugin.

Scaffolding the index route

But with that, our tools are pretty much set up here. One other thing I like to do is come over to my tailwind.config.js. This is a neat little trick that I picked up. And, you'll notice that Tailwind includes different shades of gray. So if we were to make this, say, a bg-gray-300, this is a certain shade of gray. But there's actually, you know, five or six shades of gray.

We have gray; we have neutral, we can see that looks slightly different; we have slate, that has a bluish tint to it; we have stone, and we have zinc. And whenever I start a new project, I like to just stick with one shade of gray. You should basically always have one shade of gray in your projects. But it's hard to remember, Hey, are we using zinc on this project? Let's make sure you use zinc everywhere we are setting a text or background color.

So what I like to do is come over to my tailwind.config.js, and if we pop over to the Tailwind CSS docs and search for a document called Customizing Colors, and we look for require, we're going to see that we can go ahead and import all of the default pallet from Tailwind.

So let's go ahead and import this. And what we're going to do is we're going to map colors.gray to the shade of our choice. So let's start with colors.zinc, just like that.

const colors = require("tailwindcss/colors");

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./app/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {
      colors: {
        gray: colors.zinc,
      },
    },
  },
  plugins: [],
};

And let's come over to our index, and change this to bg-gray-300:

// index.tsx
export default function Index() {
  return (
    <div class="bg-gray-300 p-20">
      <p className="text-blue-500">Hello, Build UI!</p>
    </div>
  );
}

So now this is actually mapped to zinc, and if we were to come over and change this to slate, and come over and re-save our index file, we're going to see this changes to slate.

const colors = require("tailwindcss/colors");

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./app/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {
      colors: {
        gray: colors.slate,
      },
    },
  },
  plugins: [],
};

So this is a nice way to just keep things consistent on our project, and really to drive this home, let's go ahead, open up our sidebar here. We can close bottom terminal. And I'm going to come to tailwind.css, and let's just set some global styles here.

Let's go ahead and make this kind of a dark-mode app. So I'm going to use html, and let's apply bg-gray-900 as the background. Let's go ahead and remove bg-gray-300, and we'll also drop this text blue, and we'll set a default text of text-gray-300, something like that, or maybe 200.

/* tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

html {
  @apply bg-gray-900 text-gray-200;
}

And so now you can see how this really benefits us. If we wanted to see what our site looks like with slate or with zinc, then we see that change. For this project, let's go ahead and use neutral. This is kind of a fun version that you actually don't see much these days, but it kinda reminds me of Apple. There's no saturation, there's no greens or blues that are kind of part of the gray scale here. So let's go with that for now.

const colors = require("tailwindcss/colors");

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./app/**/*.{js,jsx,ts,tsx}"],
  theme: {
    extend: {
      colors: {
        gray: colors.neutral,
      },
    },
  },
  plugins: [],
};

And I'll also come over to our global styles, I like to add antialiased right here just so we can have that, and the text renders a bit sharper.

/* tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

html {
  @apply bg-gray-900 text-gray-200 antialiased;
}

And now we're basically ready to start going to town right here in our index route. So let's go ahead and just scaffold out our work journal title, let's put some padding on this, and we'll say "Learnings and doings. Updated weekly". And we can make this a bit of margin, text size large, and maybe we'll make this text-gray-400. And just coming back to kind of my work journal right here, we see we basically iterate over list of weeks, and then within those weeks we have a list for Work, Learnings, and Interesting things.

So we might go ahead and add a new div here, and we'll say "Week of February 20th", which is when I'm recording this. Let's go ahead and wrap that in a <super> tag. And then let's add another div right here, and we'll say Work, Learnings, and Interesting things. Something like this. Add some margin top.

And in each one of these, I think they'll probably each have their own wrapping div. And we'll go ahead and add an unordered list, with our first item, second item right here. Let's go ahead and add some padding left to this. Let's make it a list-type-disc. A little bit more padding. Actually, let's make this margin left of eight. And we'll just duplicate this here and here. And let's go ahead and add some space in the y-direction for each one of these sections.

// app/routes/index.tsx
export default function Index() {
  return (
    <div className="mx-auto max-w-7xl p-6">
      <h1 className="text-4xl text-white">Work journal</h1>
      <p className="mt-3 text-xl text-gray-400">
        Doings and learnings. Updated weekly.
      </p>

      <div className="mt-8">
        <ul>
          <li>
            <p>
              Week of Feb 2<sup>nd</sup>, 2023
            </p>

            <div className="mt-4 space-y-4">
              <div>
                <p>Work:</p>
                <ul className="ml-6 list-disc">
                  <li>First thing</li>
                </ul>
              </div>
              <div>
                <p>Learnings:</p>
                <ul className="ml-6 list-disc">
                  <li>First learning</li>
                  <li>Second learning</li>
                </ul>
              </div>
              <div>
                <p>Interesting things:</p>
                <ul className="ml-6 list-disc">
                  <li>Something cool!</li>
                </ul>
              </div>
            </div>
          </li>
        </ul>
      </div>
    </div>
  );
}

So this is kind of the bones of our work journal. Each one of these are entries with different types, and they belong to a week. So this is pretty cool, and you know the tooling in Remix is great. As you can see, you can get going pretty quickly. But now we have a nice starting point to talk about how we're actually going to build the dynamic parts of this web app.

Links