2024-11-03
Run the following command to create a new Remix project using the Blues Stack template:
This command will create a new folder named my-app
and set up the entire project after you answer yes
to a couple of questions.
Note
Create a sample project using the Blues Stack template to get started with Remix. You can change the project name my-app
to any name you prefer.
schema.prisma
: Defines your database schema.Database Configuration
.env
file.DATABASE_URL
in the .env
file with your database credentials: DATABASE_URL="postgresql://<USERNAME>:<PASSWORD>@localhost:5432/<DATABASE_NAME>"
Avertissement
The database connection is not required to serve static HTML and CSS pages using Remix. Database connection is covered in a separate lecture.
Before starting the development server, you need to set up the project dependencies and environment variables.
Run the following command to install dependencies and set up the environment:
Note
Run the setup.
After setting up the project, you need to build it for the first time. This will compile the project and prepare it for development:
Note
Run the build.
Finally, start the development server to run your project locally:
This will start the server, and you can view your project by opening a web browser and going to http://localhost:3000
.
Development URL:
Open your web browser and navigate to:
You should see a Remix application to manage notes running locally.
By following these steps, you will have your development server up and running, allowing you to view and interact with your Remix project in real-time.
Note
Run the development server and open the web site.
Remix allows you to serve static HTML and CSS files directly from the public
directory. This feature is useful for serving standalone pages or assets that do not require dynamic content generation.
Static files such as HTML, CSS, images, and other assets should be placed in the public
directory. This directory is automatically served by Remix, making the files accessible via the root URL.
It’s a good practice to organize your static files into subdirectories within the public
directory. For example:
public/images
for image files.public/css
for additional CSS files.public/js
for JavaScript files.Create an HTML file named simple.html
in the public
directory:
<!-- public/simple.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Static Page</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<h1>Welcome to My Static Page</h1>
</body>
</html>
Create a CSS file named styles.css
in the public/css
directory:
Place an image file named logo.png
in the public/images
directory:
<!-- public/simple.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Static Page</title>
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<h1>Welcome to My Static Page</h1>
<img src="/images/logo.png" alt="Logo">
</body>
</html>
Once the files are in the public
directory, you can access them directly via the browser. For example:
http://localhost:3000/index.html
to view the static HTML page.<head>
section of the HTML file./images/logo.png
in the HTML file.Note
Add and organize static files for your project in the public
directory of your Remix project to serve HTML, CSS, images, and other assets.
What is a Route? - A route in Remix (and web development in general) is a URL path that corresponds to a specific page or resource in your application. - Routes determine what content is displayed when a user navigates to a particular URL. - Routes are defined by creating files in the app/routes
directory.
Example Route
// app/routes/welcome.tsx
export default function Welcome() {
return (
<div className="flex flex-col items-center justify-center h-screen bg-gray-100 text-gray-800">
<h1 className="text-4xl">Hello, World!</h1>
<p className="text-xl mt-2">Welcome to our website. We're glad to have you here!</p>
</div>
);
}
welcome.tsx
within the app/routes
directory of your Remix project.// app/routes/dynamicProducts.tsx
import { useLoaderData } from "remix";
import { json } from "remix";
// Simulate fetching data from a database or API
const fetchProducts = async () => {
return [
{ id: 1, name: "Product 1", price: "$10" },
{ id: 2, name: "Product 2", price: "$20" },
{ id: 3, name: "Product 3", price: "$30" },
];
};
// Loader function to fetch data on the server side
export const loader = async () => {
const products = await fetchProducts();
return json({ products });
};
// React component to display the products
export default function Products() {
const { products } = useLoaderData();
return (
<div className="flex flex-col items-center justify-center h-screen bg-gray-100 text-gray-800">
<h1 className="text-4xl mb-4">Products</h1>
<ul className="space-y-2">
{products.map((product) => (
<li key={product.id} className="text-xl">
{product.name} - {product.price}
</li>
))}
</ul>
</div>
);
}
dynamicProducts.tsx
within the app/routes
directory of your Remix project.<html>
, <head>
, and <body>
tags, around your route components.app/root.tsx
file, which serves as the root layout for your application.root.tsx
root.tsx
file in a Remix project serves as the root layout for your application.<html>
, <head>
, and <body>
tags.Example of a basic root.tsx
file:
// app/root.tsx
import { Links, LiveReload, Meta, Outlet, Scripts, ScrollRestoration } from "remix";
export default function App() {
return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}
<Outlet />
component renders the matched child route component.<Links />
, <Meta />
, <Scripts />
, and <LiveReload />
components are provided by Remix to handle various aspects of the HTML document and live reloading during development.What is a Component? - In Remix, a component is a reusable piece of UI that can be used across different parts of your application. - Components help in breaking down the UI into smaller, manageable pieces, making the code more modular and easier to maintain.
Example Component
// app/components/Navbar.tsx
export default function Navbar() {
return (
<nav className="bg-blue-600 p-4 shadow-md">
<ul className="flex space-x-4">
<li><a href="/" className="text-white hover:text-gray-300">Home</a></li>
<li><a href="/products" className="text-white hover:text-gray-300">Products</a></li>
<li><a href="/dashboard" className="text-white hover:text-gray-300">Dashboard</a></li>
<li><a href="/dashboard/settings" className="text-white hover:text-gray-300">Dashboard Settings</a></li>
</ul>
</nav>
);
}
Navbar.tsx
within the app/components
directory (create it if needed) of your Remix project.To use a component in a route, import it and include it in the JSX of your route component.
// app/routes/products.tsx
import Navbar from "~/components/Navbar";
export default function Products() {
return (
<div className="min-h-screen bg-gray-100">
<Navbar />
<div className="container mx-auto p-4">
<h1 className="text-3xl font-bold mb-4">Products Page</h1>
<p className="text-lg text-gray-700">Details about the products will go here.</p>
</div>
</div>
);
}
Organizing Components - Organize your components in the app/components
directory. - Group related components into subdirectories for better organization. - Example directory structure: app/ ├── components/ │ ├── Navbar.tsx │ └── Footer.tsx ├── routes/ │ ├── index.tsx │ └── products.tsx
What are Nested Routes? - Nested routes allow you to create complex layouts by nesting route components within each other. - They enable you to build hierarchical structures where child routes inherit the layout and context of their parent routes.
Benefits of Nested Routes - Reusability: Share common layouts and components across multiple routes. - Maintainability: Simplify the management of complex UIs by breaking them into smaller, manageable pieces. - Consistency: Ensure a consistent look and feel across different parts of your application.
// app/routes/dashboard.tsx
import { Outlet } from "@remix-run/react";
import Navbar from "~/components/Navbar";
export default function Dashboard() {
return (
<div className="min-h-screen bg-gray-100">
<Navbar />
<div className="container mx-auto p-4">
<h1 className="text-4xl font-bold mb-4">Dashboard</h1>
<Outlet />
</div>
</div>
);
}
// app/routes/dashboard.index.tsx
export default function DashboardIndex() {
return (
<div className="p-4 bg-white shadow-md rounded-md">
<h2 className="text-2xl font-semibold mb-2">Welcome to the Dashboard</h2>
<p className="text-gray-700">This is the main dashboard page.</p>
</div>
);
}
// app/routes/dashboard.settings.tsx
export default function DashboardSettings() {
return (
<div className="p-4 bg-white shadow-md rounded-md">
<h2 className="text-2xl font-semibold mb-2">Settings</h2>
<p className="text-gray-700">Manage your settings here.</p>
</div>
);
}
How to Define Nested Routes - Create a parent route file (e.g., dashboard.tsx
) that includes the <Outlet />
component. - Create child route files (e.g., dashboard.index.tsx
and dashboard.settings.tsx
) within the same directory as the parent route. - The child routes will be rendered inside the <Outlet />
component of the parent route.
Accessing Nested Routes - Navigate to the parent route URL to access the nested routes. - Example: - http://localhost:3000/dashboard
will render the Dashboard
component and the DashboardIndex
component. - http://localhost:3000/dashboard/settings
will render the Dashboard
component and the DashboardSettings
component.
What are Parameters? - Parameters are dynamic segments of the URL that can be used to capture values and pass them to your components. - They allow you to create dynamic routes that can handle different values.
Defining Parameters in Routes - Use the :
prefix to define a parameter in your route path. - Example: routes/products.$productId.tsx
where $productId
is a parameter.
Accessing Parameters in Components - Use the useParams
hook from Remix to access the parameters in your component. - Example: ```typescript // app/routes/products.$productId.tsx import { useParams } from ‘@remix-run/react’;
<h2 className="text-2xl font-semibold mb-2">Product ID: {productId}</h2>
<p className="text-gray-700">Details about product {productId}.</p>
</div>
);
} ```
Example Usage - Navigate to http://localhost:3000/products/123
to see the product with ID 123
. - The Product
component will render with the productId
parameter value.
Benefits of Using Parameters - Dynamic Routing: Create flexible routes that can handle different values. - Simplified Code: Easily access and use parameter values in your components. - Improved User Experience: Provide users with dynamic and personalized content based on the URL parameters.
What is Client-Side Routing? - Client-side routing allows navigation between different parts of your application without a full page reload. - It provides a smoother and faster user experience by updating the URL and rendering the appropriate components dynamically.
Benefits of Client-Side Routing - Performance: Reduces the need for full page reloads, resulting in faster navigation. - User Experience: Provides a seamless and smooth transition between pages. - State Preservation: Maintains the application state during navigation.
Using the <Link>
Component - Remix provides the <Link>
component for client-side navigation. - Example: ```typescript // app/routes/index.tsx import { Link } from “remix”;
<h1>Welcome to the Home Page</h1>
<nav>
<ul>
<li><Link to="/about">About</Link></li>
<li><Link to="/products">Products</Link></li>
</ul>
</nav>
</div>
);
} ```
NavLink
Using the NavLink
Component - The NavLink
component in Remix is used to apply styles to active links, making it easy to highlight the current page in your navigation. - It automatically adds an active
class to the link that matches the current URL.
Example Usage - Example of using the NavLink
component in a Navbar
component: ```typescript // app/components/Navbar.tsx import { NavLink } from “remix”;
);
} ```
public
directory, and routes are defined in the app/routes
directory.app/components
directory for better reusability and maintainability.E. Bruno