Jacob Paris
← Back to all content

Insert Remix loaders and actions with VS Code snippets

Remix doesn't have a lot of boilerplate, but there are some functions, like the loader, action, and default export, that are used often enough to warrant a snippet.

VS Code's snippets feature lets you define a block of text that you can insert by typing a keyword or with a keyboard shortcut.

You can make snippets for a specific project by adding them to the .vscode folder as a JSON file named something.code-snippets

Otherwise, you can add them to your user snippets by opening the command palette and typing Preferences: Configure User Snippets and selecting New Global Snippets File.... This way it will only apply for you.

Here are some tips for making snippets:

  • Let each snippet import the dependencies it needs, rather than assuming they'll be available.
  • Use the 'import/no-duplicates': 'warn', rule in your .eslintrc file to prevent duplicate imports. If you have autofix on save, it will automatically merge your imports.
  • Don't be afraid to customize these. Maybe most of your loaders have the same auth guards in the first few lines. Add those to the snippet and save yourself some time.

Example snippet file

Add this to your .vscode folder as remix.code-snippets or keep it to yourself in your personal preferences.

Last updated on Oct 29 2023

json
/** @tutorial https://www.jacobparis.com/content/remix-snippets */
{
"loader": {
"prefix": "/ loader",
"body": [
"import type { LoaderFunctionArgs } from \"@remix-run/node\"",
"",
"export async function loader({ request }: LoaderFunctionArgs) {",
" return null",
"}"
]
},
"action": {
"prefix": "/action",
"body": [
"import type { ActionFunctionArgs } from \"@remix-run/node\"",
"",
"export async function action({ request }: ActionFunctionArgs) {",
" return null",
"}"
]
},
"default": {
"prefix": "/default",
"body": [
"export default function ${TM_FILENAME_BASE/[^a-zA-Z0-9]*([a-zA-Z0-9])([a-zA-Z0-9]*)/${1:/capitalize}${2}/g}() {",
" return (",
" <div>",
" <h1>Unknown Route</h1>",
" </div>",
" )",
"}"
]
},
"headers": {
"prefix": "/headers",
"body": [
"import type { HeadersFunction } from '@remix-run/node'",
"",
"export const headers: HeadersFunction = ({ loaderHeaders }) => ({",
" 'Cache-Control': loaderHeaders.get('Cache-Control') ?? '',",
"})"
]
},
"links": {
"prefix": "/links",
"body": [
"import type { LinksFunction } from '@remix-run/node'",
"",
"export const links: LinksFunction = () => {",
" return []",
"}"
]
},
"meta": {
"prefix": "/meta",
"body": [
"import type { MetaFunction } from '@remix-run/node'",
"",
"export const meta: MetaFunction<typeof loader> = ({ data }) => [{",
" title: 'Title',",
"}]"
]
},
"shouldRevalidate": {
"prefix": "/shouldRevalidate",
"body": [
"import type { ShouldRevalidateFunction } from '@remix-run/react'",
"",
"export const shouldRevalidate: ShouldRevalidateFunction = ({",
" defaultShouldRevalidate",
"}) => {",
" return defaultShouldRevalidate",
"}"
]
}
}
Professional headshot
Moulton
Moulton

Hey there! I'm a developer, designer, and digital nomad building cool things with Remix, and I'm also writing Moulton, the Remix Community Newsletter

About once per month, I send an email with:

  • New guides and tutorials
  • Upcoming talks, meetups, and events
  • Cool new libraries and packages
  • What's new in the latest versions of Remix

Stay up to date with everything in the Remix community by entering your email below.

Unsubscribe at any time.