diff --git a/docs/posts/4.6.0/_index.mdx b/docs/posts/4.6.0/_index.mdx new file mode 100644 index 0000000..32a6caf --- /dev/null +++ b/docs/posts/4.6.0/_index.mdx @@ -0,0 +1,44 @@ +--- +title: Quick Start +hidden: true +toc: false +--- + +import Info from './info.tsx' + +This documentation covers everything you need to know to get started with `remix-development-tools`. + +## Prerequisites + +- Remix version **2.8** or higher. +- Your project needs to run on **ESM**. If you are using CommonJS, you will need to convert your project to ESM. +- Remix has to run on **Vite**. + +## Why ESM and Vite? + +If you don't already know, Remix has become a Vite plugin. This means that Remix is now using Vite for bundling +and development instead of their own custom solution. Due to this `remix-development-tools` is also built on top of +Vite and uses it extensively. + +In order to use the full feature-set of **Vite** the project has to run on ESM. This is because Vite exposes a websocket +that **remix-development-tools** uses to communicate with the server. This websocket is **only** available in ESM projects +because it's exposed by `import.meta` which is only available in ESM. + +To avoid creating user confusion and giving you a subpar experience, we have decided to only support ESM projects running on Vite. + + + If you are using CommonJS non-Vite Remix app, you will need to convert your project to ESM. This is not as hard as it sounds. + You can find a guide on how to do this [here](https://remix.run/docs/en/main/future/vite#migrating) and [here](https://alemtuzlak.hashnode.dev/migrating-a-v1-cjs-remix-project-to-remix-vite-esm) + + +## Why use `remix-development-tools`? + +`remix-development-tools` is a set of tools that help you to develop your Remix application. + +They help you, but are not limited to, to do the following things: +- **Loader data display** - You can see the data that is being loaded by your loaders. +- **Route display** - You can see the routes that are being used by your application in list/tree format. +- **Error tracking** - You can see invalid HTML rendered on your page and where it's coming from. +- **Hydration mismatch tracking** - You can see if there are any hydration mismatches in your application, what was rendered on the client and what was rendered on the server. +- **Server logs** - You can see the logs of your server in the browser. +- **Route boundaries** - You can see the route boundaries by hovering over elements. diff --git a/docs/posts/4.6.0/configuration/client.mdx b/docs/posts/4.6.0/configuration/client.mdx new file mode 100644 index 0000000..8c9a560 --- /dev/null +++ b/docs/posts/4.6.0/configuration/client.mdx @@ -0,0 +1,195 @@ +--- +title: Remix Development Tools Client Configuration +description: Configuration options for the Remix Development Tools client +--- + +import Info from "./info.tsx"; +import Warn from "./warn.tsx"; + + +All of the following options can be set in the dev tools panel **"Settings page"** and they override the default ones. Your preferences are +stored in localStorage and if they do not exist there the default ones are used. + + +Before we explain all the possible options here is the client configuration Typescript type: + +```ts +type RdtClientConfig = { + position: "top-left" | "top-right" | "bottom-left" | "bottom-right" | "middle-left" | "middle-right"; + liveUrls: { name: string, url: string }[]; + liveUrlsPosition: "top-left" | "top-right" | "bottom-left" | "bottom-right"; + defaultOpen: boolean; + expansionLevel: number; + height: number; + minHeight: number; + maxHeight: number; + hideUntilHover: boolean; + panelLocation: "top" | "bottom"; + requireUrlFlag: boolean; + urlFlag: string; + breakpoints: {name: string, min: number, max: number }[], + routeBoundaryGradient: "sea" | "hyper" | "gotham" | "gray" | "watermelon" | "ice" | "silver"; + showBreakpointIndicator: boolean; +} +``` + +Let's go through each option and see what it does. + +## Live URLs + +This option is used to set the live urls that will be displayed in the bottom left corner of the screen. The default value is an empty array. +It allows you to specify multiple live urls that you can use to open the current page in a new tab. + +## Live URLs position + +This option is used to set the position of the live urls that will be displayed in the bottom left corner of the screen. The possible values are: +- `top-left` - the live urls will be positioned at the top left corner of the screen +- `top-right` - the live urls will be positioned at the top right corner of the screen +- `bottom-left` - the live urls will be positioned at the bottom left corner of the screen +- `bottom-right` - the live urls will be positioned at the bottom right corner of the screen + +## Position + +This option is used to set the position of the Remix Development Tools trigger (the button that opens the panel). The possible values are: +- `top-left` - the trigger will be positioned at the top left corner of the screen +- `top-right` - the trigger will be positioned at the top right corner of the screen +- `bottom-left` - the trigger will be positioned at the bottom left corner of the screen +- `bottom-right` - the trigger will be positioned at the bottom right corner of the screen +- `middle-left` - the trigger will be positioned at the middle left of the screen +- `middle-right` - the trigger will be positioned at the middle right of the screen + +## Default Open + +This option is used to set the initial state of the panel. If set to `true` the panel will be open by default, if set to `false` +the panel will be closed by default. + +## Expansion Level + +This option is used to set the initial expansion level of the returned JSON data in the **Active Page** tab. By default it is set to +0 and if you open up the **Active Page** and look at the returned loader data it will look like this: + +```ts +"data": { ... } + +``` + +If you set the expansion level to 1 the returned loader data will look like this: + +```ts +"data": { + "property": "value" +} +``` + +## Height + +This option is used to set the initial height of the panel. The default value is 400px. + +## Min Height + +This option is used to set the minimum height of the panel. The default value is 200px. + +## Max Height + +This option is used to set the maximum height of the panel. The default value is 800px. + +## Hide Until Hover + +This option is used to set whether the trigger should be hidden until you hover over it. The default value is `false`. + +## Panel Location + +This option is used to set the location of the panel. The possible values are: +- `top` - the panel will be positioned at the top of the screen +- `bottom` - the panel will be positioned at the bottom of the screen + +## Require URL Flag + +This option is used to set whether the panel should be opened only if the URL contains a specific flag. The default value is `false`. + + +If you set this option to `true` and you forget to set the URL flag, the panel will hide and you will not be able to see it +until you enter the url flag. + +The default one is `rdt=true` and if you set this option to `true` you will have to add `?rdt=true` to the URL in order to see the panel. + + +## URL Flag + +This option is used to set the URL flag that is required to open the panel. The default value is `rdt`. + +You can set it to whatever you wish and if you set the **Require URL Flag** option to `true` you will have to add `?yourFlag=true` to the URL in order to see the panel. + +## Route Boundary Gradient + +This option is used to set the color of the route boundary gradient. The possible values are: +- `sea` +- `hyper` +- `gotham` +- `gray` +- `watermelon` +- `ice` +- `silver` + + +This changes the color of the route boundary gradient in the **Active Page** tab. When you hover over any route in the panel it will show you it's boundaries. + + +The default value is `ice`. + +## Breakpoints + +This option allows you to define custom breakpoints that show in the bottom left corner of the panel to help you determine the current screen breakpoint you have defined. +By default the breakpoints are set to tailwind breakpoints but you can change them to whatever you want. + +Eg: +```ts + breakpoints: [{name: "lg", min: 0, max: 768}, {name: "xl", min: 768, max: 1024}, {name: "2xl", min: 1024, max: Infinity}], +``` + +## Show breakpoint indicator + +This option allows you to show/hide the current breakpoint in the bottom left corner of the panel. + +## Creating a custom configuration + +To create a custom configuration you can use the following code snippet: + + ```ts + import { defineRdtConfig } from "remix-development-tools"; + + const customConfig = defineRdtConfig({ + client: { + position: "top-right", + defaultOpen: true, + expansionLevel: 1, + height: 500, + minHeight: 300, + maxHeight: 1000, + hideUntilHover: true, + panelLocation: "bottom", + requireUrlFlag: true, + urlFlag: "customFlag", + routeBoundaryGradient: "gotham", + breakpoints: [{name: "lg", min: 0, max: 768}, {name: "xl", min: 768, max: 1024}, {name: "2xl", min: 1024, max: Infinity}], + showBreakpointIndicator: false + } + }); + + export default customConfig; + ``` + +Then you can use this configuration in your `vite.config.js` file like this: + +```ts +import customConfig from "./rdt.config"; +import { remixDevTools } from "remix-development-tools"; + +export default defineConfig({ + plugins: [remixDevTools(customConfig)], +}); +``` + + + Try opening up the dev tools panel deployed on this site and playing around with the settings in the settings tab! + + diff --git a/docs/posts/4.6.0/configuration/editor.mdx b/docs/posts/4.6.0/configuration/editor.mdx new file mode 100644 index 0000000..acd972e --- /dev/null +++ b/docs/posts/4.6.0/configuration/editor.mdx @@ -0,0 +1,80 @@ +--- +title: Remix Development Tools Editor Configuration +description: Configuration options for the Remix Development Tools to interface with your editor +--- + +Everyone uses their own editors, so it's important to be able to configure the editor that Remix Development Tools will open your files in. + +```ts +type EditorConfig = { + name: string; + open(path: string, lineNumber: string | undefined): void; +} +``` + +## `name` + +The name of the editor that will be displayed on the Open in Editor button. + +## `open` + +This function will be called when the user clicks the Open in Editor button. It will receive the path to the file and the line number to open the file at. +This function will both handle the case where you shift + right click an element on the page AND the open in X button in the UI, they return different values +so be sure to cover both of them. + +```ts +import { exec } from "node:child_process"; +import { normalizePath } from "vite"; + +function open(path: string, lineNumber: string | undefined) { + exec(`code -g "${normalizePath(path)}${lineNumber ? `:${lineNumber}` : ""}"`); +} +``` + +## Editors + +Below are some examples of configurations for popular editors. + +### VS Code + +To use VS Code as your editor, you don't need to do anything, it's the default editor. + +### WebStorm + +To use WebStorm as your editor, you can use the following configuration: + +```ts +import { exec } from "node:child_process"; +import { cwd } from "node:process"; + +const editor = { + name: "WebStorm", + open(path, lineNumber) { + exec( + `webstorm "${process.cwd()}/${path}" --line ${lineNumber ? `--line ${lineNumber}` : ""}`.replace( + /\$/g, + "\\$", + ), + ); + }, +}; +``` + +### GoLand + +To use WebStorm as your editor, you can use the following configuration: + +```ts +import { exec } from "node:child_process"; +import { cwd } from "node:process"; + +const editor = { + name: "WebStorm", + open(path, lineNumber) { + if (!path) return; + exec( + `goland "${process.cwd()}/${path}" ${lineNumber ? `--line ${lineNumber}` : ""}` + ); + }, +}; +``` \ No newline at end of file diff --git a/docs/posts/4.6.0/configuration/index.md b/docs/posts/4.6.0/configuration/index.md new file mode 100644 index 0000000..3352b97 --- /dev/null +++ b/docs/posts/4.6.0/configuration/index.md @@ -0,0 +1,4 @@ +--- +title: Configuration +order: 3 +--- \ No newline at end of file diff --git a/docs/posts/4.6.0/configuration/server.mdx b/docs/posts/4.6.0/configuration/server.mdx new file mode 100644 index 0000000..d9124dd --- /dev/null +++ b/docs/posts/4.6.0/configuration/server.mdx @@ -0,0 +1,61 @@ +--- +title: Remix Development Tools Server Configuration +description: Configuration options for the Remix Development Tools server +--- + +import Info from "./info.tsx"; +import Warn from "./warn.tsx"; + +As with the client configuration, we will first see the full configuration type: + +```ts +interface RemixServerConfig { + silent?: boolean; + logs?: { + cookies?: boolean; + defer?: boolean; + actions?: boolean; + loaders?: boolean; + cache?: boolean; + siteClear?: boolean; + }; +} +``` + +## `silent` + +When `true`, the server will not log anything to the console. This is useful for production environments. + +## `logs` + +This object allows you to configure the server logs. Each key is a log type and the value is a boolean indicating whether to log that type. +All are `true` by default so you don't have to provide anything, if you want to be granular you can, otherwise you can use the `silent` option to turn off +all logs. + +### `cookies` + +When `true`, the server will log all cookies sent by the server in the "Set-Cookie" header. + +### `defer` + +When `true`, the server will log all deferred actions. +The following gets logged: +- The defer location +- The keys that were deferred +- The time it took for each key to resolve + +### `actions` + +When `true`, the server will log all actions that are hit with a request. + +### `loaders` + +When `true`, the server will log all loaders that are hit with a request. + +### `cache` + +When `true`, the server will log all loaders/actions that return a `Cache Control` header. + +### `siteClear` + +When `true`, the server will log when the site cache is cleared, or anything else with the `Clear-Site-Data` header. \ No newline at end of file diff --git a/docs/posts/4.6.0/features/active-page-tab.mdx b/docs/posts/4.6.0/features/active-page-tab.mdx new file mode 100644 index 0000000..f808019 --- /dev/null +++ b/docs/posts/4.6.0/features/active-page-tab.mdx @@ -0,0 +1,118 @@ +--- +title: "Active Page Tab" +description: "Detailed overview of all features on the active page tab." +--- + +import Info from "./info.tsx"; + +The Active Page tab is the first tab that appears when you open up the dev tools panel. It contains an overview of all active loaders +on the current page and detailed information about each loader. + +## Route boundaries + +The first feature we will go over is the route boundaries. This feature shows you the current route boundaries on the actual page. +This is useful for debugging and testing purposes. It finds the `` component in the route and highlights it with a +gradient background that can be set in the settings. + + + This feature is only available in the development mode because it used react dev tools to find the `` component. + + If you want to try it open up the dev tools right now nad hover over `/docs/main` in the panel. + + You can also change the gradient background color in the settings. + + +## Loader list + +The loader list is a list of all active loaders on the current page. It shows the url segment of the loader, +the loader type and the loader file. + + + The loader type is determined by the routing convention. + - `purple` - represents the root.tsx file + - `blue` - represents a pathless layout file + - `green` - represents a normal route file, whether index or not + + +### Open in VS code + +Each segment has an **open in VS code** button that opens the loader file in VS code. +This is useful for quick navigation to the loader file. + + +This only works if you have the `code` command installed in your terminal. If you don't have it installed you can + install it by following the instructions [here](https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line). + + +### Loader data + +Each segment has a loader data **JSON** object that contains all the information returned by the loader of that segment. + +If you open the dev tools on this page and look at the `/docs/main` segment you will see the **loader data object** which contains +`metadata`, `tag`, `serverData`, `deferredServerData` and `key` properties. + +This part will contain everything returned from the server and it will be **hot swapped** if the data changes. + + + When keys are deferred on the server, the data will hot swap when the key is resolved on the client. + + + +### Route params + +The route params section contains all the route params for the current segment. + +This will contain all the **wildcard** params currently available on this route. + +If you open up the dev tools, you will be able to see that `tag` and `slug` are both in +the route params. + +### Server info + +The server info section contains all the server information for the current segment, including: +- `loaderTriggerCount` - the number of times the loader has been triggered (updates in real-time) +- `actionTriggerCount` - the number of times the action has been triggered (updates in real-time) +- `lowestExecutionTime` - the lowest execution time of the loader (updates in real-time) +- `highestExecutionTime` - the highest execution time of the loader (updates in real-time) +- `averageExecutionTime` - the average execution time of the loader (updates in real-time) +- `lastLoaderInfo` - the last loader info object (updates in real-time), includes execution time, request headers and response headers. +- `lastActionInfo` - the last action info object (updates in real-time), includes execution time, request headers and response headers. +- `loaderCalls` - an array of loaderInfo objects ordered from most recent to least recent (updates in real-time) +- `actionCalls` - an array of actionInfo objects ordered from most recent to least recent (updates in real-time) + +### handles + +The handles section contains all the handles for the current segment. + +This will contain all the **handles** currently available on this route. + +Remix allows you to export a custom **handle** export which can be anything, it will be shown here if it is exported. + +## Revalidation + +There is a **Revalidate** button that allows you to revalidate all the loaders on the page. + + +## Timeline + +The timeline section on the right contains useful information on navigation and submission events in your application. + +Every time there is a navigation or submission event, a new entry will be added to the timeline on the top. + +It is limited to 50 entries and will remove the oldest entry when the limit is reached. + +The timeline will contain the following information for each event: +- `type` - the type of event (navigation or submission, fetcher or normal) +- `method` - the method of the event (GET, POST, PUT, DELETE) +- `url` - the url of the event +- `data sent` - the data sent in the event +- `response` - the response of the event + + +This only happens for events that change the state of the app, if there is a client-side navigation to a +new location that has no loaders nothing will happen because the state has remained idle. + + +### Clearing the timeline + +You can clear the timeline by clicking the **clear** button at the top right of the timeline. \ No newline at end of file diff --git a/docs/posts/4.6.0/features/detach.mdx b/docs/posts/4.6.0/features/detach.mdx new file mode 100644 index 0000000..ed47f92 --- /dev/null +++ b/docs/posts/4.6.0/features/detach.mdx @@ -0,0 +1,15 @@ +--- +title: "Detached mode" +alternateTitle: "Detached mode" +description: "How you can detach your panel into a new window" +--- + +There is a special button on the bottom left side of the panel above the X button. +When you click on it, the panel will detach and open in a new window. + +The detached window will keep in sync with the main panel and will show the same content. +The logs on the server will happen twice, once for the main panel and once for the detached window. + +When you close the detached window, or the main panel, the other one will be terminated and closed. +In case the detached mode hangs for some reason, you can always return it to the main site by +clicking the trigger while in detached mode. \ No newline at end of file diff --git a/docs/posts/4.6.0/features/errors-tab.mdx b/docs/posts/4.6.0/features/errors-tab.mdx new file mode 100644 index 0000000..cfec3b9 --- /dev/null +++ b/docs/posts/4.6.0/features/errors-tab.mdx @@ -0,0 +1,40 @@ +--- +title: "Errors Tab" +description: "Detailed overview of all features on the Errors Tab." +--- + +import Info from "./info.tsx"; + +The errors tab is a powerful tool for debugging issues with your react code, namely invalid HTML. +It helps you detect potential HTML issues in your code, such as invalid HTML nesting or hydration issues. + +## Invalid HTML + +If you have invalidely nested HTML (eg. a `div` inside a `p`), you will see an error in the errors tab. +These kind of nesting issues can cause unexpected behavior in your application, namely hydration issues. +The browser does a lot of work to make sure that the HTML you send to the client is valid so it can +sometimes move the order of elements around to make sure it's valid. This can cause unexpected hydration +issues in your application. + +Whenever there is a case of this found in your html the errors tab will show you the error and the file +where the error is found. If the error is found in a file that is a part of your project you can click on the +file name to open the file in your editor and change the issue right away. + +## Hydration Mismatch + +Hydration mismatch is a common issue in React applications. It occurs when the server-rendered HTML does not match the +HTML generated by the client. This can cause unexpected behavior in your application, +such as the loss of user input or the loss of scroll position. In Remix it can also cause FOUC (Flash of Unstyled Content). + +To avoid hydration mismatch, you should make sure that the HTML generated by the server matches the HTML generated by +the client. + +These kind of issues are very hard to track down because they can be caused by a lot of different things. + +If a hydration mismatch happens the errors tab will show you the **diff** between the server and client HTML, allowing +you to analyze the differences and fix the issue. + + +Hydration mismatches happen on document requests (hard refresh or initial load in Remix). So if you don't see it at first +try refreshing your page. + \ No newline at end of file diff --git a/docs/posts/4.6.0/features/index.md b/docs/posts/4.6.0/features/index.md new file mode 100644 index 0000000..51fbc36 --- /dev/null +++ b/docs/posts/4.6.0/features/index.md @@ -0,0 +1,4 @@ +--- +title: Guides +order: 2 +--- \ No newline at end of file diff --git a/docs/posts/4.6.0/features/routes-tab.mdx b/docs/posts/4.6.0/features/routes-tab.mdx new file mode 100644 index 0000000..be877d8 --- /dev/null +++ b/docs/posts/4.6.0/features/routes-tab.mdx @@ -0,0 +1,52 @@ +--- +title: "Routes Tab" +description: "Detailed overview of all features on the Routes Tab." +--- + +import Info from "./info.tsx"; + +The Routes tab shows you all the routes in your Remix.run application either in the tree view or a list view. +The default is the tree view which shows the routes in a nested tree structure. You can switch to the list view by + clicking the list icon in the top left corner of the tab. + +The featureset is identical across both but only shown differently based on your preference. + +The only difference is the fact that the **tree view** shows you which routes are currently active on the page. This is + indicated by a golden line going through the tree from the root to the active route. The **list view** does not have this + feature. + +## Route types + +There are three types of routes in remix-development-tools: +- *root* - The root route is the first route that is loaded when you open the application. +It is the first route in the tree. (purple) +- *route* - A route is a route that is not a root route. It is a route that is nested under another route and has +a url segment. (green) +- *layout* - A layout is a route that is not a root route and is a special kind of route that does not have a url +segment but provides only an outlet with some layout for the child routes (blue) + +## Route info + +Clicking on any route name will show you detailed information about that route. This includes the route's name, the +route's path, the route's url, the route's file and does it contain the following things: +- *loader* - The loader is the function that is called when the route is loaded. It is responsible for fetching the data + needed for the route. +- *action* - The action is the function that is called when the route is submitted. It is responsible for handling the + form submission. +- *ErrorBoundary* - The ErrorBoundary is the component that is called when the route has an error. It is responsible for + showing the error message to the user. + +All of these segments are colored in either red or green indicating if it exists or not. + + + The error boundary will tell you if the error boundary for the current route comes from the route itself or is inherited + from a parent route. If it is inherited, it will show you the name of the parent route. + + +## Wildcard parameters + +If a route has a wildcard parameter, it will be shown in the **Wildcard parameters** section which allows you to enter +any value for the wildcard parameter. This is useful when combined with the **Open in Browser** button that redirects +you to the route with the wildcard parameter. + +The wildcard values are saved in the browser so you can persist them across development sessions. \ No newline at end of file diff --git a/docs/posts/4.6.0/features/settings-tab.mdx b/docs/posts/4.6.0/features/settings-tab.mdx new file mode 100644 index 0000000..5680060 --- /dev/null +++ b/docs/posts/4.6.0/features/settings-tab.mdx @@ -0,0 +1,98 @@ +--- +title: "Settings Tab" +description: "Detailed overview of all features on the Settings Tab." +--- + +import Info from "./info.tsx"; +import Warn from "./warn.tsx"; + +The settings tab is where you can override the default settings for your project. + + +## Position + +This option is used to set the position of the Remix Development Tools trigger (the button that opens the panel). The possible values are: +- `top-left` - the trigger will be positioned at the top left corner of the screen +- `top-right` - the trigger will be positioned at the top right corner of the screen +- `bottom-left` - the trigger will be positioned at the bottom left corner of the screen +- `bottom-right` - the trigger will be positioned at the bottom right corner of the screen +- `middle-left` - the trigger will be positioned at the middle left of the screen +- `middle-right` - the trigger will be positioned at the middle right of the screen + +## Default Open + +This option is used to set the initial state of the panel. If set to `true` the panel will be open by default, if set to `false` +the panel will be closed by default. + +## Expansion Level + +This option is used to set the initial expansion level of the returned JSON data in the **Active Page** tab. By default it is set to +0 and if you open up the **Active Page** and look at the returned loader data it will look like this: + +```ts +"data": { ... } + +``` + +If you set the expansion level to 1 the returned loader data will look like this: + +```ts +"data": { + "property": "value" +} +``` + +## Height + +This option is used to set the initial height of the panel. The default value is 400px. + +## Min Height + +This option is used to set the minimum height of the panel. The default value is 200px. + +## Max Height + +This option is used to set the maximum height of the panel. The default value is 800px. + +## Hide Until Hover + +This option is used to set whether the trigger should be hidden until you hover over it. The default value is `false`. + +## Panel Location + +This option is used to set the location of the panel. The possible values are: +- `top` - the panel will be positioned at the top of the screen +- `bottom` - the panel will be positioned at the bottom of the screen + +## Require URL Flag + +This option is used to set whether the panel should be opened only if the URL contains a specific flag. The default value is `false`. + + +If you set this option to `true` and you forget to set the URL flag, the panel will hide and you will not be able to see it +until you enter the url flag. + +The default one is `rdt=true` and if you set this option to `true` you will have to add `?rdt=true` to the URL in order to see the panel. + + +## URL Flag + +This option is used to set the URL flag that is required to open the panel. The default value is `rdt`. + +You can set it to whatever you wish and if you set the **Require URL Flag** option to `true` you will have to add `?yourFlag=true` to the URL in order to see the panel. + +## Route Boundary Gradient + +This option is used to set the color of the route boundary gradient. The possible values are: +- `sea` +- `hyper` +- `gotham` +- `gray` +- `watermelon` +- `ice` +- `silver` + + +This changes the color of the route boundary gradient in the **Active Page** tab. When you hover over any route in the panel it will show you it's boundaries. + + +The default value is `ice`. diff --git a/docs/posts/4.6.0/features/shortcuts.mdx b/docs/posts/4.6.0/features/shortcuts.mdx new file mode 100644 index 0000000..4b3561f --- /dev/null +++ b/docs/posts/4.6.0/features/shortcuts.mdx @@ -0,0 +1,27 @@ +--- +title: "Keyboard Shortcuts" +description: "Detailed overview of all keyboard shortcuts in Remix Development Tools" +--- + +## Go To Source + +**Shift + Right Click** + +When you are in the browser and you want to go to the source code of a component, you can right click on the component +while holding down shift. This will open the source code of the component in your code editor. + +## Opening/closing the DevTools + +**Shift + A** + +When you are in the browser and you want to open the Remix DevTools, you can press `Shift + A`. +This will open the DevTools, if you're already in the DevTools, it will close it. + +While in the DevTools, you can also use `Esc` to close them. + +From version 4.2.0 is fully configurable and you can change the shortcut in the settings. + +We use [react-hotkeys-hook](https://www.npmjs.com/package/react-hotkeys-hook) to handle the keyboard shortcuts under the hood. +You can adapt to their API to add your own shortcuts. + +Check out the settings tab for details \ No newline at end of file diff --git a/docs/posts/4.6.0/guides/contributing.mdx b/docs/posts/4.6.0/guides/contributing.mdx new file mode 100644 index 0000000..8fa9b4f --- /dev/null +++ b/docs/posts/4.6.0/guides/contributing.mdx @@ -0,0 +1,28 @@ +--- +title: "Contributing to Remix Development Tools" +description: "Contributions to Remix Development Tools are welcome! To contribute, please follow these guidelines." +--- + +## Contributing + +Contributions to Remix Development Tools are welcome! To contribute, please follow these guidelines: + +1. Fork the repository and clone it locally. +2. Create a new branch for your feature or bug fix. +4. Run `npm run dev` to start the development server with a vanilla Remix app setup. +5. Implement your changes, adhering to the existing code style and best practices. +5. Please add tests for any new features or bug fixes. +6. Commit and push your changes to your forked repository. +7. Open a pull request, providing a clear description of your changes and their purpose. + +### Contributing on Remix Forge integrations + +If you want to contribute to the VS Code extension integration follow the steps above and then: +1. Clone the repo for Remix Forge locally. +2. Open it in VS Code. +3. Run `npm install` +4. Run `npm run dev` +5. Click `F5` which will launch a debugger instance of VS Code. +6. In the debugger instance of VS Code, start the remix dev tools +7. Click `Connect to Remix Forge` in the Remix Dev Tools +8. Code on! diff --git a/docs/posts/4.6.0/guides/index.md b/docs/posts/4.6.0/guides/index.md new file mode 100644 index 0000000..8e26ecf --- /dev/null +++ b/docs/posts/4.6.0/guides/index.md @@ -0,0 +1,4 @@ +--- +title: Guides +order: 4 +--- \ No newline at end of file diff --git a/docs/posts/4.6.0/guides/migration.mdx b/docs/posts/4.6.0/guides/migration.mdx new file mode 100644 index 0000000..f35ce03 --- /dev/null +++ b/docs/posts/4.6.0/guides/migration.mdx @@ -0,0 +1,106 @@ +--- +title: "Migration guide" +description: "Migration guide from older version of remix-development-tools" +--- + +import Info from "./info.tsx"; + +## v3.x => v4.x + +### Vite plugin + +If you're migrating your `remix-development-tools` from v3.x to v4.x and you were already running it as +a Vite plugin here is all you need to do: + +```diff +import { defineConfig } from 'vite'; +import { vitePlugin as remix } from '@remix-run/dev'; +- import { remixDevTools } from 'remix-development-tools/vite' ++ import { remixDevTools } from 'remix-development-tools' + +export default defineConfig({ + plugins: [remixDevTools(), remix()], +}) +``` + +### Remix compiler + + +This section is only valid if you were not using the Vite plugin for Remix. + + +If you were using the Remix compiler and not the Vite plugin, you will first need to do the following: +- Migrate your app to use the Vite plugin. +- Migrate your app from CJS to ESM (if applicable). + +First thing you need to do after the above is change your package.json scripts to use the `remix vite:dev` command. +```diff +- "dev": "remix dev -c \"rdt-serve ./build/index.js\" --manual", ++ "dev": "remix vite:dev", +``` + +After you've done these things you need to remove everything from your `root.tsx` file that is +related to `remix-development-tools`. + +```diff +// Import styles +- import rdtStylesheet from "remix-development-tools/index.css"; +export const links: LinksFunction = () => [ +- ...(process.env.NODE_ENV === "development" ? [{ rel: "stylesheet", href: rdtStylesheet }] : []), +] + +- let AppExport = App; +// This imports the dev tools only if you're in development +- if(process.env.NODE_ENV === 'development') { +- const { withDevTools } = await import("remix-development-tools"); +- AppExport = withDevTools(AppExport); +- } + +- export default AppExport; +``` + +After this is done you might also need to remove the `remix-development-tools` package from your +custom server. An example of that would be something like this: +```diff + // Somewhere in your server.ts file + const build = await import(BUILD_PATH) + let devBuild = build + let devToolsConfig = null; +- if(process.env.NODE_ENV === 'development') { +- const { withServerDevTools, defineServerConfig } = await import("remix-development-tools/server"); +- // Allows you to define the configuration for the dev tools +- devToolsConfig = defineServerConfig({ +- //... your config here ... +- }) +- // wrap the build with the dev tools +- devBuild = withServerDevTools(build, devToolsConfig) +- } + +if(process.env.NODE_ENV === "development"){ + // .... somewhere later in your code ... + // This makes sure the build is wrapped on reload, you will need this if you're running with the --manual flag + async function reloadBuild() { + devBuild = await import(`${BUILD_PATH}?update=${Date.now()}`) + // wrap the build with dev tools on re-import +- devBuild = withServerDevTools(devBuild, devToolsConfig) + broadcastDevReady(devBuild) + } +} +``` + +After all of this is done. You just need to add the `remix-development-tools` to your `vite.config.ts` file. + +```diff +import { defineConfig } from 'vite'; +import { vitePlugin as remix } from '@remix-run/dev'; ++ import { remixDevTools } from 'remix-development-tools' + +export default defineConfig({ + plugins: [ ++ remixDevTools(), + remix() + ] +}) +``` + +And that's it! You should be good to go. If you have any issues, please reach out to us. \ No newline at end of file diff --git a/docs/posts/4.6.0/guides/plugins.mdx b/docs/posts/4.6.0/guides/plugins.mdx new file mode 100644 index 0000000..d5edbf3 --- /dev/null +++ b/docs/posts/4.6.0/guides/plugins.mdx @@ -0,0 +1,99 @@ +--- +title: "Plugins" +description: "Remix Development Tools plugins" +--- + +## Plugins in Vite +Plugins work in a different way in Vite. You create a directory for plugins and just provide the path to the directory to the plugin. The plugin will automatically import all the plugins from the directory and add them to the dev tools. You only need to make sure your exports are named exports and not default exports and that they are uniquely named. + +You can create a directory called plugins in your project and add your plugins there. Then you can add the following to your vite.config.js file: +```ts +import { remixDevTools } from "remix-development-tools/vite"; +export default defineConfig({ + plugins: [ + remixDevTools({ + pluginsDir: "./plugins" + })], +}); +``` + +## Plugins in Remix bundler (v3 only) +Writing plugins for Remix Development Tools is easy. You can write a plugin that adds a new tab to the Remix Development Tools in the following way: + +Create a new file in your project called remix-dev-tools-plugin.tsx +Implement your jsx component and add the logic you wish to add to the Remix Development Tools. +Export a function with the following contract: +```tsx + const MyComponent = () => { + // Implement your logic here + return
My Component
+ } + + export function remixDevToolsPlugin(yourOptions?: { ... }): JSX.Element { + return { + // can't be page, terminal or routes, must be unique + id: "my-plugin", + // Name that is shown in the tab next to the icon + name: "My Plugin", + // Icon to be shown in the tab + icon: , + // The component to be rendered when the tab is active + component: , + // Whether the tab requires the Remix Forge VS Code extension to be connected to be shown + requiresForge: false, + // Whether the timeline should be shown on the tab + hideTimeline: false, + } + } + +``` + +Import it in your root.tsx file and pass it to your Remix Development Tools: + +```diff +import { remixDevToolsPlugin } from "./remix-dev-tools-plugin"; + +- withDevTools(App); ++ withDevTools(App, { plugins: [remixDevToolsPlugin()] }) +``` + +You should now see your plugin in the Remix Development Tools as a new tab. + +## Using Remix Forge with your plugin +If you want to use Remix Forge with your plugin you can do so by setting the requiresForge property to true in your plugin. This will make sure that the plugin is only shown when the Remix Forge VS Code extension is connected. + +Follow the above guide to create a plugin. +Import the following hook from remix-development-tools: +```tsx +import { useRemixForgeSocket } from "remix-development-tools"; + + const MyComponent = () => { + const socket = useRemixForgeSocket(); + // Implement your logic here + return
My Component
+ } +``` + +You can now use the socket to send messages to the Remix Forge VS Code extension. For now it accepts reading/deleting/opening files in VS Code +```tsx + const MyComponent = () => { + const socket = useRemixForgeSocket(); + const runCommand = () => { + socket.sendJsonMessage({ subtype: "read_file", path: "package.json" }) + } + // Implement your logic here + return
My Component
+ } + ``` +The following contract is returned from the extension: + ```tsx + interface RemixForgeResponse { + type: "plugin"; + subtype: "read_file" | "open_file" | "delete_file" | "write_file"; + error: boolean; + data: string | null; + } + ``` +Make sure you check if the type and subtype match your needs before using the data. +Refer to react-use-websocket for more information on how to use the socket and what options it accepts because that is what is used under the hood. +After you're done share your plugin with the community by opening a discussion! \ No newline at end of file diff --git a/docs/posts/4.6.0/metadata.json b/docs/posts/4.6.0/metadata.json new file mode 100644 index 0000000..d0d434c --- /dev/null +++ b/docs/posts/4.6.0/metadata.json @@ -0,0 +1,126 @@ +{ + "paths": { + "installation": "started/installation", + "client": "configuration/client", + "editor": "configuration/editor", + "server": "configuration/server", + "shortcuts": "features/shortcuts", + "active-page-tab": "features/active-page-tab", + "routes-tab": "features/routes-tab", + "errors-tab": "features/errors-tab", + "settings-tab": "features/settings-tab", + "detach": "features/detach", + "examples": "features/examples", + "migration": "guides/migration", + "plugins": "guides/plugins", + "contributing": "guides/contributing" + }, + "sections": [ + "Getting Started", + "Configuration", + "Features", + "Guides" + ], + "meta": { + "installation": { + "title": "Setting up Remix Development Tools", + "alternateTitle": "Installation", + "description": "Learn how to setup remix-development-tools in your project.", + "section": "Getting Started", + "slug": "installation", + "spacer": true + }, + "client": { + "title": "Client config", + "alternateTitle": "Client config", + "description": "Learn about everything you can configure inside of remix-development-tools client-side part.", + "section": "Configuration", + "slug": "client", + "spacer": true + }, + "editor": { + "title": "Editor config", + "alternateTitle": "Editor config", + "description": "Learn about everything you can configure with the custom editor you are using.", + "section": "Configuration", + "slug": "editor", + "spacer": true + }, + "server": { + "title": "Server config", + "alternateTitle": "Server config", + "description": "Learn about everything you can configure inside of remix-development-tools server-side part.", + "section": "Configuration", + "slug": "server", + "spacer": true + }, + "shortcuts": { + "title": "Keyboard Shortcuts", + "description": "Learn about all keyboard shortcuts", + "section": "Features", + "slug": "shortcuts", + "spacer": true + }, + "active-page-tab": { + "title": "Active Page Tab", + "alternateTitle": "Active Page Tab", + "description": "Detailed overview of all the features offered on the active page tab.", + "section": "Features", + "slug": "active-page-tab", + "spacer": true + }, + "routes-tab": { + "title": "Routes Tab", + "alternateTitle": "Routes Tab", + "description": "Detailed overview of all the features offered on the Routes tab.", + "section": "Features", + "slug": "routes-tab", + "spacer": true + }, + "errors-tab": { + "title": "Errors Tab", + "alternateTitle": "Errors Tab", + "description": "Detailed overview of all the features offered on the Errors tab.", + "section": "Features", + "slug": "errors-tab", + "spacer": true + }, + "settings-tab": { + "title": "Settings Tab", + "alternateTitle": "Settings Tab", + "description": "Detailed overview of all the features offered on the Settings tab.", + "section": "Features", + "slug": "settings-tab", + "spacer": true + }, + "detach": { + "title": "Detach mode", + "alternateTitle": "Detach mode", + "description": "Explanation on detach mode and how to use it.", + "section": "Features", + "slug": "detach" + }, + "migration": { + "title": "Migrating to v4", + "alternateTitle": "Migrating to v4", + "description": "How to migrate your project to v4.", + "section": "Guides", + "slug": "migration" + }, + "plugins": { + "title": "Plugins", + "alternateTitle": "Plugins", + "description": "Using plugins with remix-development-tools.", + "section": "Guides", + "slug": "plugins" + }, + "contributing": { + "title": "Contributing", + "alternateTitle": "Contributing", + "description": "Contributing to remix-development-tools.", + "section": "Guides", + "slug": "contributing" + } + }, + "hasIndex": true +} \ No newline at end of file diff --git a/docs/posts/4.6.0/started/index.md b/docs/posts/4.6.0/started/index.md new file mode 100644 index 0000000..5c68474 --- /dev/null +++ b/docs/posts/4.6.0/started/index.md @@ -0,0 +1,4 @@ +--- +title: Getting Started +order: 1 +--- \ No newline at end of file diff --git a/docs/posts/4.6.0/started/installation.mdx b/docs/posts/4.6.0/started/installation.mdx new file mode 100644 index 0000000..2728d31 --- /dev/null +++ b/docs/posts/4.6.0/started/installation.mdx @@ -0,0 +1,56 @@ +--- +title: "Setting up Remix Development Tools" +alternateTitle: "Beginner's Guide" +description: "Follow this page to learn how to set up Remix Development Tools in your Remix project." +--- + +import Warn from "./warn.tsx"; + + +## Installation +Adding Remix Development Tools to your project is easy. First install it into your project by running: + +```bash +npm install remix-development-tools -D +``` + +This will install it as a dev dependency in your project. + +## Enabling the tools + +After you have installed the tools, you need to go to your `vite.config.ts` file which will probably look something like this: + +```ts +import { vitePlugin as remix } from '@remix-run/dev' +import { defineConfig } from 'vite' +import tsconfigPaths from 'vite-tsconfig-paths' + +export default defineConfig({ + plugins: [remix(), tsconfigPaths()], +}) + +``` + +All you have to do is add the plugin into the `plugins` array in your `vite.config.ts` file. + +```diff +import { vitePlugin as remix } from '@remix-run/dev' +import { defineConfig } from 'vite' +import tsconfigPaths from 'vite-tsconfig-paths' ++import { remixDevTools } from "remix-development-tools"; + +export default defineConfig({ +- plugins: [remix(), tsconfigPaths()], ++ plugins: [remixDevTools(), remix(), tsconfigPaths()], +}) + +``` + +Make sure your plugin is BEFORE the remix one! + + +**That's it!** + +You should now see the Remix Development Tools in your browser when you run your app. + + diff --git a/docs/posts/main/configuration/client.mdx b/docs/posts/main/configuration/client.mdx index 63681df..8c9a560 100644 --- a/docs/posts/main/configuration/client.mdx +++ b/docs/posts/main/configuration/client.mdx @@ -27,7 +27,9 @@ type RdtClientConfig = { panelLocation: "top" | "bottom"; requireUrlFlag: boolean; urlFlag: string; + breakpoints: {name: string, min: number, max: number }[], routeBoundaryGradient: "sea" | "hyper" | "gotham" | "gray" | "watermelon" | "ice" | "silver"; + showBreakpointIndicator: boolean; } ``` @@ -134,6 +136,20 @@ This changes the color of the route boundary gradient in the **Active Page** tab The default value is `ice`. +## Breakpoints + +This option allows you to define custom breakpoints that show in the bottom left corner of the panel to help you determine the current screen breakpoint you have defined. +By default the breakpoints are set to tailwind breakpoints but you can change them to whatever you want. + +Eg: +```ts + breakpoints: [{name: "lg", min: 0, max: 768}, {name: "xl", min: 768, max: 1024}, {name: "2xl", min: 1024, max: Infinity}], +``` + +## Show breakpoint indicator + +This option allows you to show/hide the current breakpoint in the bottom left corner of the panel. + ## Creating a custom configuration To create a custom configuration you can use the following code snippet: @@ -154,6 +170,8 @@ To create a custom configuration you can use the following code snippet: requireUrlFlag: true, urlFlag: "customFlag", routeBoundaryGradient: "gotham", + breakpoints: [{name: "lg", min: 0, max: 768}, {name: "xl", min: 768, max: 1024}, {name: "2xl", min: 1024, max: Infinity}], + showBreakpointIndicator: false } }); diff --git a/docs/posts/main/metadata.json b/docs/posts/main/metadata.json index b74ae64..d0d434c 100644 --- a/docs/posts/main/metadata.json +++ b/docs/posts/main/metadata.json @@ -2,6 +2,7 @@ "paths": { "installation": "started/installation", "client": "configuration/client", + "editor": "configuration/editor", "server": "configuration/server", "shortcuts": "features/shortcuts", "active-page-tab": "features/active-page-tab", @@ -37,6 +38,14 @@ "slug": "client", "spacer": true }, + "editor": { + "title": "Editor config", + "alternateTitle": "Editor config", + "description": "Learn about everything you can configure with the custom editor you are using.", + "section": "Configuration", + "slug": "editor", + "spacer": true + }, "server": { "title": "Server config", "alternateTitle": "Server config", diff --git a/docs/posts/versions.json b/docs/posts/versions.json index 8dba0b9..e74ef77 100644 --- a/docs/posts/versions.json +++ b/docs/posts/versions.json @@ -1,11 +1,15 @@ [ { - "version": "4.2.0", + "version": "4.6.0", "tag": "main" }, { - "version": "4.1.0", - "tag": "4.1.0" + "version": "4.6.0", + "tag": "4.6.0" + }, + { + "version": "4.2.0", + "tag": "4.2.0" }, { "version": "4.1.0", diff --git a/package.json b/package.json index b288452..e6be362 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "remix-development-tools", "description": "Remix development tools - a set of tools for developing/debugging Remix.run apps", "author": "Alem Tuzlak", - "version": "4.5.2", + "version": "4.6.0", "license": "MIT", "keywords": [ "remix", diff --git a/src/client/RemixDevTools.tsx b/src/client/RemixDevTools.tsx index 67e8032..45b55bc 100644 --- a/src/client/RemixDevTools.tsx +++ b/src/client/RemixDevTools.tsx @@ -59,6 +59,46 @@ const LiveUrls = () =>{ } +type WindowSize = { + width: number; + height: number; +}; +const useOnWindowResize = () => { + const [windowSize, setWindowSize] = useState({ + width: window.innerWidth, + height: window.innerHeight, + }); + + useEffect(() => { + const handleResize = () => { + setWindowSize({ + width: window.innerWidth, + height: window.innerHeight, + }); + }; + + window.addEventListener("resize", handleResize); + + return () => { + window.removeEventListener("resize", handleResize); + }; + }, []); + return windowSize +} + +const Breakpoints = () => { + const { width } = useOnWindowResize(); + const { settings } = useSettingsContext(); + const breakpoints = settings.breakpoints; + const show= settings.showBreakpointIndicator; + const breakpoint = breakpoints.find(bp => bp.min <= width && bp.max >= width); + if(!breakpoint || !breakpoint.name || !show){ + return null; + } + return
+ {breakpoint?.name} +
+} const DevTools = ({ plugins: pluginArray }: RemixDevToolsProps) => { useTimelineHandler(); @@ -111,6 +151,7 @@ const DevTools = ({ plugins: pluginArray }: RemixDevToolsProps) => {
+
diff --git a/src/client/components/Trigger.tsx b/src/client/components/Trigger.tsx index e324e26..fca313b 100644 --- a/src/client/components/Trigger.tsx +++ b/src/client/components/Trigger.tsx @@ -55,7 +55,7 @@ export const Trigger = ({
diff --git a/src/client/context/RDTContext.tsx b/src/client/context/RDTContext.tsx index 21f1854..35180bb 100644 --- a/src/client/context/RDTContext.tsx +++ b/src/client/context/RDTContext.tsx @@ -78,6 +78,8 @@ export const getExistingStateFromStorage = (config?: RdtClientConfig & { editorN ...settings, editorName: config?.editorName ?? initialState.settings.editorName, liveUrls: config?.liveUrls ?? initialState.settings.liveUrls, + breakpoints: config?.breakpoints ?? initialState.settings.breakpoints, + }, detachedWindow, detachedWindowOwner, @@ -86,8 +88,7 @@ export const getExistingStateFromStorage = (config?: RdtClientConfig & { editorN return state; }; -export type RdtClientConfig = Pick - +export type RdtClientConfig = Pick export const RDTContextProvider = ({ children, config }: ContextProps) => { const [state, dispatch] = useReducer(rdtReducer, getExistingStateFromStorage(config)); diff --git a/src/client/context/rdtReducer.ts b/src/client/context/rdtReducer.ts index e30a164..2560e6d 100644 --- a/src/client/context/rdtReducer.ts +++ b/src/client/context/rdtReducer.ts @@ -69,6 +69,14 @@ export type RemixDevToolsState = { timeline: TimelineEvent[]; terminals: Terminal[]; settings: { + /** + * The breakpoints to show in the corner so you can see the current breakpoint that you defined + */ + breakpoints: { name: string, min: number, max: number}[], + /** + * Whether to show the breakpoint indicator + */ + showBreakpointIndicator: boolean, /** * The live urls to show in the corner which allow you to open the app in a different environment (eg. staging, production) * @default [] @@ -157,6 +165,15 @@ export const initialState: RemixDevToolsState = { terminals: [{ id: 0, locked: false, output: [], history: [] }], server: undefined, settings: { + breakpoints: [ + { name: "", min: 0, max: 639 }, + { name: "sm", min: 640, max: 767 }, + { name: "md", min: 768, max: 1023 }, + { name: "lg", min: 1024, max: 1279 }, + { name: "xl", min: 1280, max: 1535 }, + { name: "2xl", min: 1536, max: 9999 }, + ], + showBreakpointIndicator: true, liveUrls: [], liveUrlsPosition: "bottom-left", editorName: "VSCode", diff --git a/src/client/tabs/SettingsTab.tsx b/src/client/tabs/SettingsTab.tsx index 95ff064..b6b7112 100644 --- a/src/client/tabs/SettingsTab.tsx +++ b/src/client/tabs/SettingsTab.tsx @@ -44,6 +44,14 @@ export const SettingsTab = () => { > Hide the trigger until hovered + setSettings({ showBreakpointIndicator: !settings.showBreakpointIndicator })} + value={settings.showBreakpointIndicator} + > + Show breakpoint indicator +