forge42dev / remix-dev-tools Goto Github PK
View Code? Open in Web Editor NEWOwn your Remix.run apps with these development tools.
Home Page: https://remix-development-tools.fly.dev/
License: MIT License
Own your Remix.run apps with these development tools.
Home Page: https://remix-development-tools.fly.dev/
License: MIT License
Not sure if this is intentional or a bug, but I've noticed the Timeline pane only seems to list navigations where the destination route includes a loader. I was expecting all navigations would show up, but perhaps this is by design?
For some reason when exporting a links
function the dev tools plugin blows up ๐ฌ
https://stackblitz.com/edit/remix-run-remix-qrkkuu?file=app%2Froot.tsx
Right now, uncaught errors are shown in the terminal. It would be nice to see them somehow within the dev tools
Getting title error on a fresh project.
System:
OS: macOS 14.2.1
CPU: (8) arm64 Apple M1
Memory: 73.50 MB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.10.0 - ~/Library/pnpm/node
Yarn: 1.22.21 - /opt/homebrew/bin/yarn
npm: 10.2.3 - ~/Library/pnpm/npm
pnpm: 8.15.1 - ~/Library/pnpm/pnpm
bun: 1.0.26 - ~/.bun/bin/bun
Watchman: 2023.12.04.00 - /opt/homebrew/bin/watchman
Browsers:
Brave Browser: 108.1.46.140
Safari: 17.2.1
npmPackages:
@remix-run/dev: ^2.6.0 => 2.6.0
@remix-run/node: ^2.6.0 => 2.6.0
@remix-run/react: ^2.6.0 => 2.6.0
@remix-run/serve: ^2.6.0 => 2.6.0
remix-development-tools: 3.7.4 => 3.7.4
vite: ^5.0.0 => 5.0.12
There seems to be a subission issue with submissions and remix dev tools where rdt causes issues with submissions that include search parameters
epicweb-dev/epic-stack#414
If I open a route accordion inside Active page tab, calling useRevalidator().revalidate makes all accordions to collapse.
That is bad because I have to open the accordion again to see the data I was looking.
I'm using RDT version 3 with remix 2.3
dev: "PORT=4000 dotenv -e .env.local remix dev -c \"rdt-serve ./build/index.js\" --manual"
I'm actually using remix dev for the server without any custom server and port 80 for third api with remix and i can't replaced with any other port. but websocket of RDT is taking 8080
const port = (config == null ? void 0 : config.wsPort) || 8080;
how i can change that port without creating a custom server ? it's possible to use flag (--port 8181) ?
The readme already shows how to conditionally show based on NODE_ENV. However, I really do want to show the development tools even on a production build. (In my case I am using a special cookie to decide to show/hide dev tools).
Since the readme already shows how to use NODE_ENV to hide, this package should not make the decision to hide internally.
Could the README be expanded with a section explaining how to only load in the component/styles when running the dev server? I saw you tweet that that's what you were doing.
Took 3.5.0 out for a test drive with Vite and it crashed when I submitted a form.
Stacktrace:
Error: cannot clone body after it is used
at clone (C:\Users\user\dev\project\node_modules\@remix-run\web-fetch\dist\lib.node.cjs:588:9)
at new Request (C:\Users\user\dev\project\node_modules\@remix-run\web-fetch\dist\lib.node.cjs:1456:6)
at Request.clone (C:\Users\user\dev\project\node_modules\@remix-run\web-fetch\dist\lib.node.cjs:1604:10)
at extractDataFromResponseOrRequest (file:///C:/Users/user/dev/project/node_modules/remix-development-tools/dist/server.js:702:32)
at storeAndEmitActionOrLoaderInfo (file:///C:/Users/user/dev/project/node_modules/remix-development-tools/dist/server.js:732:26)
at file:///C:/Users/user/dev/project/node_modules/remix-development-tools/dist/server.js:774:7
at unAwaited (file:///C:/Users/user/dev/project/node_modules/remix-development-tools/dist/server.js:667:3)
at file:///C:/Users/user/dev/project/node_modules/remix-development-tools/dist/server.js:772:5
RDT adds a decent overhead to the hmr rebuild atm, adding up to half second to a clean template on an older machine.
This is probably because the lucide dependency, here's a tree-map comparison with/without RDT installed:
We should able to at least treeshake out lucide by using @jacobparis' Sly https://sly-cli.fly.dev/
I followed the docs to upgrade to remix-development-tools": "2.0.0".
I'm getting errors after upgrading.
Hydration failed because the initial UI does not match what was rendered on the server
seems to be the most relevant error..."@remix-run/node": "^1.14.3",
"@remix-run/react": "^1.14.1",
"@remix-run/dev": "^1.12.0",
"remix-development-tools": "2.0.0",
node: 18.16.1
npm: 9.5.1
remix-island
with Remix-Dev-Tools? Likely...On the routes tab, if you have a resource route and click the button to open the route, it will open in the same window, but data from the resource route is not shown as it requires a full browser reload to work.
P.S. Thanks for this, it's pretty cool :)
Hi,
I made a custom remix stack based on Remix Blues Stack. I recently upgraded to Remix v2.
Im trying to add Remix Dev Tools. I followed the guide but the part about custom server config is a bit confusing.
As a result, i managed to make the dev tool ui working but server logs are not logged.
Here is the relevant code:
// server.ts
import fs from 'node:fs'
import path from 'node:path'
import url from 'node:url'
import prom from '@isaacs/express-prometheus-middleware'
import { createRequestHandler } from '@remix-run/express'
import type { ServerBuild } from '@remix-run/node'
import { broadcastDevReady, installGlobals } from '@remix-run/node'
import compression from 'compression'
import type { RequestHandler } from 'express'
import express from 'express'
import morgan from 'morgan'
import {
defineServerConfig,
withServerDevTools,
} from 'remix-development-tools/server'
import sourceMapSupport from 'source-map-support'
const rdtConfig = {
logs: {
cookies: true,
defer: true,
actions: true,
loaders: true,
cache: true,
siteClear: true,
},
}
sourceMapSupport.install()
installGlobals()
run()
async function run() {
const BUILD_PATH = path.resolve('build/index.js')
const VERSION_PATH = path.resolve('build/version.txt')
const initialBuild = await reimportServer()
const app = express()
const metricsApp = express()
app.use(
prom({
metricsPath: '/metrics',
collectDefaultMetrics: true,
metricsApp,
}),
)
app.use((req, res, next) => {
// helpful headers:
res.set('Strict-Transport-Security', `max-age=${60 * 60 * 24 * 365 * 100}`)
// /clean-urls/ -> /clean-urls
if (req.path.endsWith('/') && req.path.length > 1) {
const query = req.url.slice(req.path.length)
const safepath = req.path.slice(0, -1).replace(/\/+/g, '/')
res.redirect(301, safepath + query)
return
}
next()
})
app.use(compression())
// http://expressjs.com/en/advanced/best-practice-security.html#at-a-minimum-disable-x-powered-by-header
app.disable('x-powered-by')
// Remix fingerprints its assets so we can cache forever.
app.use(
'/build',
express.static('public/build', { immutable: true, maxAge: '1y' }),
)
// Everything else (like favicon.ico) is cached for an hour. You may want to be
// more aggressive with this caching.
app.use(express.static('public', { maxAge: '1h' }))
app.use(morgan('tiny'))
app.all('*', async (...args) => {
const handler =
process.env.NODE_ENV === 'development'
? await createDevRequestHandler(initialBuild)
: createRequestHandler({
build: initialBuild,
mode: initialBuild.mode,
})
return handler(...args)
})
const port = process.env.PORT || 3000
app.listen(port, () => {
console.log(`โ
app ready: http://localhost:${port}`)
if (process.env.NODE_ENV === 'development') {
broadcastDevReady(initialBuild)
}
})
const metricsPort = process.env.METRICS_PORT || 3010
metricsApp.listen(metricsPort, () => {
console.log(`โ
metrics ready: http://localhost:${metricsPort}/metrics`)
})
async function reimportServer(): Promise<ServerBuild> {
// cjs: manually remove the server build from the require cache
Object.keys(require.cache).forEach(key => {
if (key.startsWith(BUILD_PATH)) {
delete require.cache[key]
}
})
const stat = fs.statSync(BUILD_PATH)
// convert build path to URL for Windows compatibility with dynamic `import`
const BUILD_URL = url.pathToFileURL(BUILD_PATH).href
// use a timestamp query parameter to bust the import cache
return import(BUILD_URL + '?t=' + stat.mtimeMs)
}
async function createDevRequestHandler(
initialBuild: ServerBuild,
): Promise<RequestHandler> {
let build = initialBuild
async function handleServerUpdate() {
// 1. re-import the server build
build = await reimportServer()
const devBuild = withServerDevTools(build, defineServerConfig(rdtConfig))
// 2. tell Remix that this app server is now up-to-date and ready
broadcastDevReady(devBuild)
}
const chokidar = await import('chokidar')
chokidar
.watch(VERSION_PATH, { ignoreInitial: true })
.on('add', handleServerUpdate)
.on('change', handleServerUpdate)
// wrap request handler to make sure its recreated with the latest build for every request
return async (req, res, next) => {
try {
return createRequestHandler({
build,
mode: 'development',
})(req, res, next)
} catch (error) {
next(error)
}
}
}
}
// root.tsx
import { cssBundleHref } from '@remix-run/css-bundle'
import type { LinksFunction, LoaderFunctionArgs } from '@remix-run/node'
import { json } from '@remix-run/node'
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from '@remix-run/react'
import rdtStylesheet from 'remix-development-tools/index.css'
import { getUser } from '~/utils/auth.server'
import appStylesHref from './styles/app.css?inline'
import tailwindStylesHref from './styles/tailwind.css?inline'
export const links: LinksFunction = () => [
{ rel: 'stylesheet', href: tailwindStylesHref },
{ rel: 'stylesheet', href: appStylesHref },
...(cssBundleHref ? [{ rel: 'stylesheet', href: cssBundleHref }] : []),
...(process.env.NODE_ENV === 'development'
? [{ rel: 'stylesheet', href: rdtStylesheet }]
: []),
]
export const loader = async ({ request }: LoaderFunctionArgs) => {
return json({ user: await getUser(request) } as const)
}
function App() {
return (
<html lang="en" className="h-full">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<Meta />
<Links />
</head>
<body className="h-full">
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
)
}
let AppExport = App
if (process.env.NODE_ENV === 'development') {
const { withDevTools } = require('remix-development-tools')
AppExport = withDevTools(AppExport)
}
export default AppExport
Build scripts
...
"build": "run-s build:*",
"build:remix": "remix build",
"build:server": "esbuild --platform=node --format=cjs ./server.ts --outdir=build --bundle --external:fsevents",
"dev": "run-p dev:*",
"dev:server": "cross-env NODE_ENV=development npm run build:server -- --watch",
"dev:remix": "remix dev --manual -c \"node --require ./mocks ./build/server.js\"",
...
Terminal
๐ฟ remix dev
info building...
info built (2.9s)
๐ถ Mock server running
โ
app ready: http://localhost:3000
โ
metrics ready: http://localhost:3010/metrics
GET /login?index 200 - - 48.300 ms
GET /login?index 200 - - 7.975 ms
GET /login 200 - - 10.662 ms
GET / 200 - - 7.115 ms
Thanks!
Add plugin support to the project
remix vite expressjs
way to reproduce is to fast navigate from and away of two pages with deferred values
sample:
https://codesandbox.io/p/devbox/vite-rdt-test-l36c2f
I'm developing an accessibility focused Remix application and then I found my navigation with keyboard stopped working for "a while" (some TAB clicks).
Finally I found that development tools are capturing keyboard navigation.
This maybe can be a good think (if you plan to have this extension accessible), but:
or, alternatively: disable the keyboard navigation entirely when Remix-Dev-Tools is closed.
Installing the Server RDT cause node --watch to hang at "Waiting for graceful termination..." when restarting.
server.js
.If we remove server RDT, (revert to this commit xHomu/rdt-node-watch@88e86da), then the Express server restarts as expected.
Every time I kill the server with ctrl + c
on mac my list of node processes grows by 1. I have confirmed this behavior stops when I remove the dev tools from my startup script. This happens regardless of the terminal i use (vscode integrated, warp, etc).
Version: v3.4.0
Startup Script: "remix dev -c \"rdt-cjs-serve ./build/index.js\" --manual"
When clicking in the error pane on a route file that has dot delimiters it does not open the desired file.
Instead it seems it opens the part before the $
and then uses two dots.
remix 2.5.0
"remix-development-tools": "^3.7.2"
VSCode: Version: 1.85.1
Mac Sonoma 14.2.1
While the extension is working properly, VSCode is complaining about missing support for dynamic import.
Dynamic imports are only supported when the '--module' flag is set to 'es2020', 'es2022', 'esnext', 'commonjs', 'amd', 'system', 'umd', 'node16', or 'nodenext'.ts(1323)
I don't know is this is related to the remix v1/v2 state, but I'm wondering if the README can provide better help on how to properly fix this error.
Edit: After preliminary debugging with @AlemTuzlak, it appears to be related to url SearchParams on your entry page.
Not quite sure if there's something particular with our app or is it with the new feature, but turning on showRouteBoundaries causes our home page to infinite loop:
Disabling it and RDT works just as expected.
Repo: https://github.com/manawiki/core
If you want to take a look @AlemTuzlak , I'll dm you the env variables.
Simple breaking demo:
Add three route files:
other.tsx
: A layout route file
other._index.tsx
: Index route
other.page.tsx
: Normal page route
In the routes tab all three routes are shown, the other path twice.
With custom routing or remix-flat-routes there are more breaks to expect.
rather than always showing the remix devtools, maybe it can be configured such that it only loads/shows up when there is a specific search param (?remix-dev=true
) in the url? This makes it easier to toggle on and off.
When I make a change in the Epic Stack and I get an HMR reload, I get the following error in the console:
error-boundary.tsx:38 Error: A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition.
at throwException (react-dom.development.js:19055:35)
at handleError (react-dom.development.js:26311:7)
at renderRootSync (react-dom.development.js:26437:7)
at performSyncWorkOnRoot (react-dom.development.js:26085:20)
at flushSyncCallbacks (react-dom.development.js:12042:22)
at flushSync (react-dom.development.js:26201:7)
at scheduleRefresh (react-dom.development.js:27795:5)
at renderer.scheduleRefresh (renderer.js:584:1)
at react-refresh-runtime.development.js:265:17
at Set.forEach (<anonymous>) '\n at GeneralErrorBoundary (http://localhost:3000/build/_shared/chunk-GHJAN7NM.js:42:3)\n at body\n at html\n at Document (http://localhost:3000/build/root-XJYL7V5A.js?t=1690338998889:4736:3)\n at ErrorBoundary (http://localhost:3000/build/root-XJYL7V5A.js?t=1690338998889:4928:17)\n at RemixRouteError (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:8710:3)\n at RenderErrorBoundary (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3640:9)\n at DataRoutes (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3354:5)\n at Router (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3433:15)\n at RouterProvider (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3303:5)\n at RemixErrorBoundary (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:8278:5)\n at RemixBrowser (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:10443:40)'
overrideMethod @ console.js:213
GeneralErrorBoundary @ error-boundary.tsx:38
renderWithHooks @ react-dom.development.js:16305
mountIndeterminateComponent @ react-dom.development.js:20074
beginWork @ react-dom.development.js:21587
beginWork$1 @ react-dom.development.js:27426
performUnitOfWork @ react-dom.development.js:26557
workLoopSync @ react-dom.development.js:26466
renderRootSync @ react-dom.development.js:26434
performSyncWorkOnRoot @ react-dom.development.js:26085
flushSyncCallbacks @ react-dom.development.js:12042
flushSync @ react-dom.development.js:26201
scheduleRefresh @ react-dom.development.js:27795
renderer.scheduleRefresh @ renderer.js:584
(anonymous) @ react-refresh-runtime.development.js:265
performReactRefresh @ react-refresh-runtime.development.js:254
(anonymous) @ browser.js:72
setTimeout (async)
(anonymous) @ browser.js:70
(anonymous) @ router.ts:977
updateState @ router.ts:977
completeNavigation @ router.ts:1058
startNavigation @ router.ts:1356
await in startNavigation (async)
revalidate @ router.ts:1206
(anonymous) @ browser.js:77
await in (anonymous) (async)
emit @ hmr-runtime:remix:hmr:64
ws.onmessage @ verify:73
Show 2 more frames
Show less
error-boundary.tsx:38 Error: A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition.
at throwException (react-dom.development.js:19055:35)
at handleError (react-dom.development.js:26311:7)
at renderRootSync (react-dom.development.js:26437:7)
at recoverFromConcurrentError (react-dom.development.js:25850:20)
at performSyncWorkOnRoot (react-dom.development.js:26096:20)
at flushSyncCallbacks (react-dom.development.js:12042:22)
at flushSync (react-dom.development.js:26201:7)
at scheduleRefresh (react-dom.development.js:27795:5)
at renderer.scheduleRefresh (renderer.js:584:1)
at react-refresh-runtime.development.js:265:17 '\n at GeneralErrorBoundary (http://localhost:3000/build/_shared/chunk-GHJAN7NM.js:42:3)\n at body\n at html\n at Document (http://localhost:3000/build/root-XJYL7V5A.js?t=1690338998889:4736:3)\n at ErrorBoundary (http://localhost:3000/build/root-XJYL7V5A.js?t=1690338998889:4928:17)\n at RemixRouteError (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:8710:3)\n at RenderErrorBoundary (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3640:9)\n at DataRoutes (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3354:5)\n at Router (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3433:15)\n at RouterProvider (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3303:5)\n at RemixErrorBoundary (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:8278:5)\n at RemixBrowser (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:10443:40)'
overrideMethod @ console.js:213
GeneralErrorBoundary @ error-boundary.tsx:38
renderWithHooks @ react-dom.development.js:16305
mountIndeterminateComponent @ react-dom.development.js:20074
beginWork @ react-dom.development.js:21587
beginWork$1 @ react-dom.development.js:27426
performUnitOfWork @ react-dom.development.js:26557
workLoopSync @ react-dom.development.js:26466
renderRootSync @ react-dom.development.js:26434
recoverFromConcurrentError @ react-dom.development.js:25850
performSyncWorkOnRoot @ react-dom.development.js:26096
flushSyncCallbacks @ react-dom.development.js:12042
flushSync @ react-dom.development.js:26201
scheduleRefresh @ react-dom.development.js:27795
renderer.scheduleRefresh @ renderer.js:584
(anonymous) @ react-refresh-runtime.development.js:265
performReactRefresh @ react-refresh-runtime.development.js:254
(anonymous) @ browser.js:72
setTimeout (async)
(anonymous) @ browser.js:70
(anonymous) @ router.ts:977
updateState @ router.ts:977
completeNavigation @ router.ts:1058
startNavigation @ router.ts:1356
await in startNavigation (async)
revalidate @ router.ts:1206
(anonymous) @ browser.js:77
await in (anonymous) (async)
emit @ hmr-runtime:remix:hmr:64
ws.onmessage @ verify:73
Show 2 more frames
Show less
react-dom.development.js:18687 The above error occurred in one of your React components:
at Lazy
at body
at html
at Document (http://localhost:3000/build/root-XJYL7V5A.js?t=1690338998889:4736:3)
at App (http://localhost:3000/build/root-XJYL7V5A.js?t=1690338998889:4773:16)
at SentryRoot
at RemixRoute (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:8690:3)
at RenderedRoute (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3056:5)
at RenderErrorBoundary (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3640:9)
at DataRoutes (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3354:5)
at Router (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3433:15)
at RouterProvider (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3303:5)
at RemixErrorBoundary (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:8278:5)
at RemixBrowser (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:10443:40)
React will try to recreate this component tree from scratch using the error boundary you provided, RenderErrorBoundary.
overrideMethod @ console.js:213
logCapturedError @ react-dom.development.js:18687
callback @ react-dom.development.js:18755
callCallback @ react-dom.development.js:13923
commitUpdateQueue @ react-dom.development.js:13944
commitLayoutEffectOnFiber @ react-dom.development.js:23364
commitLayoutMountEffects_complete @ react-dom.development.js:24688
commitLayoutEffects_begin @ react-dom.development.js:24674
commitLayoutEffects @ react-dom.development.js:24612
commitRootImpl @ react-dom.development.js:26823
commitRoot @ react-dom.development.js:26682
performSyncWorkOnRoot @ react-dom.development.js:26117
flushSyncCallbacks @ react-dom.development.js:12042
flushSync @ react-dom.development.js:26201
scheduleRefresh @ react-dom.development.js:27795
renderer.scheduleRefresh @ renderer.js:584
(anonymous) @ react-refresh-runtime.development.js:265
performReactRefresh @ react-refresh-runtime.development.js:254
(anonymous) @ browser.js:72
setTimeout (async)
(anonymous) @ browser.js:70
(anonymous) @ router.ts:977
updateState @ router.ts:977
completeNavigation @ router.ts:1058
startNavigation @ router.ts:1356
await in startNavigation (async)
revalidate @ router.ts:1206
(anonymous) @ browser.js:77
await in (anonymous) (async)
emit @ hmr-runtime:remix:hmr:64
ws.onmessage @ verify:73
Show 2 more frames
Show less
hooks.tsx:608 React Router caught the following error during render Error: A component suspended while responding to synchronous input. This will cause the UI to be replaced with a loading indicator. To fix, updates that suspend should be wrapped with startTransition.
at throwException (react-dom.development.js:19055:35)
at handleError (react-dom.development.js:26311:7)
at renderRootSync (react-dom.development.js:26437:7)
at recoverFromConcurrentError (react-dom.development.js:25850:20)
at performSyncWorkOnRoot (react-dom.development.js:26096:20)
at flushSyncCallbacks (react-dom.development.js:12042:22)
at flushSync (react-dom.development.js:26201:7)
at scheduleRefresh (react-dom.development.js:27795:5)
at renderer.scheduleRefresh (renderer.js:584:1)
at react-refresh-runtime.development.js:265:17 {componentStack: '\n at Lazy\n at body\n at html\n at Documeโฆst:3000/build/_shared/chunk-DJH6CC34.js:10443:40)'}
at RenderErrorBoundary (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3640:9)
at DataRoutes (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3354:5)
at Router (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3433:15)
at RouterProvider (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:3303:5)
at RemixErrorBoundary (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:8278:5)
at RemixBrowser (http://localhost:3000/build/_shared/chunk-DJH6CC34.js:10443:40)
I haven't spent any time debugging this, but if I remove the dev tools then the issue goes away.
Hi, I followed the pattern in the example to setup devtools but I do not see the devtools in the DOM. The style sheet gets added though.
This is my root.tsx
import { cssBundleHref } from "@remix-run/css-bundle";
import React, { useContext, useState } from "react";
import rdtStylesheet from "remix-development-tools/stylesheet.css";
import ReactDOM from "react-dom";
import type { LinksFunction, V2_MetaFunction } from "@remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
useCatch,
useLoaderData,
} from "@remix-run/react";
import { withEmotionCache } from "@emotion/react";
import { unstable_useEnhancedEffect as useEnhancedEffect } from "@mui/material";
import {
Hydrate,
QueryClient,
QueryClientProvider,
} from "@tanstack/react-query";
import { useDehydratedState } from "use-dehydrated-state";
import ClientStyleContext from "~/src/ClientStyleContext";
import Layout from "~/src/Layout";
import theme from "~/src/theme";
import { LicenseManager } from "ag-grid-enterprise";
import "ag-grid-community/styles/ag-grid.min.css";
import "ag-grid-community/styles/ag-theme-alpine.min.css";
import "react-toastify/dist/ReactToastify.min.css";
import styles from "./styles/style.css";
import { json } from "@remix-run/node";
import type { Environment } from "~/environment.server";
import { getPublicKeys } from "~/environment.server";
import { PublicEnv } from "~/ui/public-env";
import { useIsBot } from "~/isBotProvider";
import { ToastContainer } from "react-toastify";
import * as process from "process";
import { compact } from "lodash";
const RemixDevTools =
process.env.NODE_ENV === "development"
? React.lazy(() => import("remix-development-tools"))
: undefined;
if (process.env.NODE_ENV !== "production" && typeof window !== "undefined") {
const axe = require("@axe-core/react");
axe(React, ReactDOM, 1000);
}
interface DocumentProps {
children: React.ReactNode;
title?: string;
env?: Pick<Environment, "AG_GRID_LICENSE_KEY">;
}
export const meta: V2_MetaFunction = () => {
return [{ name: "description", content: "Master Data Management!" }];
};
export const links: LinksFunction = () => [
...(cssBundleHref
? compact([
{ rel: "stylesheet", href: cssBundleHref },
{
rel: "stylesheet",
href: styles,
},
{
rel: "stylesheet",
href: "https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap",
},
{
rel: "stylesheet",
href: "https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap",
},
rdtStylesheet && process.env.NODE_ENV === "development"
? { rel: "stylesheet", href: rdtStylesheet }
: null,
])
: []),
];
const Document = withEmotionCache(
({ children, title, env }: DocumentProps, emotionCache) => {
let isBot = useIsBot();
const clientStyleData = useContext(ClientStyleContext);
LicenseManager.setLicenseKey(env?.AG_GRID_LICENSE_KEY as string);
// Only executed on client
useEnhancedEffect(() => {
// re-link sheet container
emotionCache.sheet.container = document.head;
// re-inject tags
const tags = emotionCache.sheet.tags;
emotionCache.sheet.flush();
tags.forEach((tag) => {
// eslint-disable-next-line no-underscore-dangle
(emotionCache.sheet as any)._insertTag(tag);
});
// reset cache to reapply global styles
clientStyleData.reset();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="theme-color" content={theme.palette.primary.main} />
<link
rel="icon"
href="https://trinitylifesciences.com/wp-content/uploads/2021/04/cropped-favicon-32x32-1-32x32.png"
sizes="32x32"
/>
<link
rel="icon"
href="https://trinitylifesciences.com/wp-content/uploads/2021/04/cropped-favicon-32x32-1-192x192.png"
sizes="192x192"
/>
<link
rel="apple-touch-icon"
href="https://trinitylifesciences.com/wp-content/uploads/2021/04/cropped-favicon-32x32-1-180x180.png"
/>
{title ? <title>{title}</title> : null}
<Meta />
<Links />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
rel="preconnect"
href="https://fonts.gstatic.com"
crossOrigin=""
/>
<meta
name="emotion-insertion-point"
content="emotion-insertion-point"
/>
</head>
<body>
<PublicEnv {...env} />
{children}
<ToastContainer
position="top-center"
autoClose={5000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
theme="colored"
/>
<ScrollRestoration />
{isBot ? null : <Scripts />}
<LiveReload />
{RemixDevTools && <RemixDevTools position="top-right" defaultOpen />}
</body>
</html>
);
},
);
export function loader() {
return json(getPublicKeys());
}
export default function App() {
const [queryClient] = useState(() => new QueryClient());
const dehydratedState = useDehydratedState();
const { publicKeys } = useLoaderData<typeof loader>();
return (
<QueryClientProvider client={queryClient}>
<Hydrate state={dehydratedState}>
<Document title="Master Data Management" env={publicKeys}>
<Layout>
<Outlet />
</Layout>
</Document>
</Hydrate>
</QueryClientProvider>
);
}
// https://remix.run/docs/en/v1/api/conventions#errorboundary
export function ErrorBoundary({ error }: { error: Error }) {
console.error(error);
return (
<Document title="Error!">
<Layout>
<div>
<h1>There was an error</h1>
<p>{error.message}</p>
<hr />
<p>
Hey, developer, you should replace this with what you want your
users to see.
</p>
</div>
</Layout>
</Document>
);
}
// https://remix.run/docs/en/v1/api/conventions#catchboundary
export function CatchBoundary() {
const caught = useCatch();
let message;
switch (caught.status) {
case 401:
message = (
<p>
Oops! Looks like you tried to visit a page that you do not have access
to.
</p>
);
break;
case 404:
message = (
<p>Oops! Looks like you tried to visit a page that does not exist.</p>
);
break;
default:
throw new Error(caught.data || caught.statusText);
}
return (
<Document title={`${caught.status} ${caught.statusText}`}>
<Layout>
<h1>
{caught.status}: {caught.statusText}
</h1>
{message}
</Layout>
</Document>
);
}
It would be incredibly useful to know how much data (in KB) the server is sending to the client on every request, both for loaders and for actions.
I am using Remix Vite and have followed all the instructions, but I get the following error when running remix vite:dev
[vite] Error when evaluating SSR module /app/root.tsx:
|- SyntaxError: Identifier 'AppExport' has already been declared
at new AsyncFunction (<anonymous>)
at instantiateModule (file:///xxx)
10:24:24 AM [vite] Error when evaluating SSR module virtual:remix/server-build: failed to import "/app/root.tsx"
|- SyntaxError: Identifier 'AppExport' has already been declared
at new AsyncFunction (<anonymous>)
at instantiateModule (file:///xxx)
10:24:24 AM [vite] Internal server error: Identifier 'AppExport' has already been declared
at new AsyncFunction (<anonymous>)
at instantiateModule (file:///xxx)
These are the changes I made in root.tsx
import rdtStylesheet from "remix-development-tools/index.css";
export const links: LinksFunction = () => [
...(process.env.NODE_ENV === "development" ? [{ rel: "stylesheet", href: rdtStylesheet }] : []),
]
function App() {
//
}
let AppExport = App;
if(process.env.NODE_ENV === 'development') {
const { withDevTools } = await import("remix-development-tools");
AppExport = withDevTools(AppExport);
}
export default AppExport;
npm run dev
> [email protected] dev
> remix dev
๐ฟ remix dev
info building...
info built (4.6s)
Error: Dynamic require of "remix-development-tools" is not supported
at file:///Users/sergiydybskiy/src/sea-people-web/build/index.js?t=1695932213829.837:11:9
at file:///Users/sergiydybskiy/src/sea-people-web/build/index.js?t=1695932213829.837:1750:26
at ModuleJob.run (node:internal/modules/esm/module_job:194:25)
let AppExport = App;
if (ENVIRONMENT === 'development') {
const { withDevTools } = require('remix-development-tools');
AppExport = withDevTools(AppExport);
}
export default withSentry(AppExport);
Was working locally with const { withDevTools } = await import("remix-development-tools");
but had to update to require
for Vercel to build.
"@remix-run/react": "2.0.1",
"remix-development-tools": "^3.0.3",
When trying to run with the latest Cloudflare Pages adapter template the wrangler cli won't start due to the following error:
service core:user:worker: Uncaught ReferenceError: global is not defined
at oqu69tjsd1.js:57552:18 in singleton
at oqu69tjsd1.js:57555:5 in node_modules/remix-development-tools/dist/index.cjs
at oqu69tjsd1.js:82:50
at oqu69tjsd1.js:62684:26
X [ERROR] MiniflareCoreError [ERR_RUNTIME_FAILURE]: The Workers runtime failed to start. There is likely additional logging output above.
npx create-remix --template remix-run/remix/templates/cloudflare-pages
yarn add remix-development-tools -D
yarn dev
- node: 20.8.0
- yarn: 1.22.19
- remix: 2.1.0
- remix-development-tools: 3.2.2
- wrangler: 3.1.1
- windows: 11
Since wrangler run in another JavaScript runtime that is not node and since the singleton
function uses the global object that is not available in the Cloudflare runtime so its throws an error.
I use react-select with isMulti
as multiselect
const schema = z.object({
tags: z.string().array(),
})
...
export async function loader() {
return json({ tags: db.tag.findMany({})})
}
export async function action() {
...
console.log(submission.value.tags)
}
export default function Form() {
return (
...
<CreatableSelect name="tags" isMulti options={tags} />
...
)
}
In function action console.log(submission.value.tags)
log [ '1', '4', 'aaa' ]
but in RDT in Active page tab on right side show POST only last value for tags: tags: string "aaa"
Hi, I have an app which uses outletContext to send data to children. If I keep the Remix Devtools in the root, changing routes forces a rerender and outlet state gets reset. Can you please help me out?
This is my code.
`import { cssBundleHref } from "@remix-run/css-bundle";
import type { LinksFunction, LoaderFunctionArgs } from "@remix-run/node";
import { json } from "@remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
import rdtStylesheet from "remix-development-tools/index.css";
import { getUser } from "/session.server";/tailwind.css";
import stylesheet from "
export const links: LinksFunction = () => [
{ rel: "stylesheet", href: stylesheet },
...(cssBundleHref ? [{ rel: "stylesheet", href: cssBundleHref }] : []),
...(process.env.NODE_ENV === "development"
? [{ rel: "stylesheet", href: rdtStylesheet }]
: []),
];
export const loader = async ({ request }: LoaderFunctionArgs) => {
return json({ user: await getUser(request) });
};
function App() {
return (
);
}
let AppExport = App;
if (process.env.NODE_ENV === "development") {
const {
withDevTools,
} = async () => {
await import("remix-development-tools");
};
AppExport = withDevTools(AppExport);
}
export default AppExport;
`
getting the following error
/Users/stelang/projects/remix/remix-app/app/root.tsx:55
AppExport = withDevTools(AppExport);
^
TypeError: withDevTools is not a function
at Object. (/Users/stelang/projects/remix/remix-app/app/root.tsx:55:15)
at Module._compile (node:internal/modules/cjs/loader:1256:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1310:10)
at Module.load (node:internal/modules/cjs/loader:1119:32)
at Function.Module._load (node:internal/modules/cjs/loader:960:12)
at ModuleWrap. (node:internal/modules/esm/translators:169:29)
at ModuleJob.run (node:internal/modules/esm/module_job:194:25)
There are issues with the current way showRouteBoundaries work. we need to fix this by implementing a more bulletproof way of handling this that covers both the server and client
the wsPort
parameter works as expected on my custom server, but it seems is not possible to change it on the client.
Although the parameter can be passed to useDevServerConnection
its always called with no params, so default 8080 is used
The Active Page tab in RDT seems "stuck" (snapshotted) on whatever page you were on when you popped it out into its own window. Future navigations do not update the tab, nor does the Revalidate button.
I am installing the latest dev tools (3.1.0) on a remix v2 app, and I got this error:
Error: Directory import '/Users/+++++/src/exps/+++++/node_modules/.pnpm/[email protected]_@[email protected]_@[email protected]_@types+react@18._k62rikz2xgll26ruaktbuytbpi/node_modules/date-fns/add' is not supported resolving ES modules imported from /Users/+++++/src/exps/+++++/node_modules/.pnpm/[email protected]_@[email protected]_@[email protected]_@types+react@18._k62rikz2xgll26ruaktbuytbpi/node_modules/remix-development-tools/dist/index.js
Did you mean to import [email protected]/node_modules/date-fns/add/index.js?
at new NodeError (node:internal/errors:406:5)
at finalizeResolution (node:internal/modules/esm/resolve:227:11)
at moduleResolve (node:internal/modules/esm/resolve:845:10)
at defaultResolve (node:internal/modules/esm/resolve:1043:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:383:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:352:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:228:38)
at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:85:39)
at link (node:internal/modules/esm/module_job:84:36)
Downgrading to 3.0.0 resolved the issue. Can I provide any more information to help?
We've recently upgraded our app to Remix version 2, and I've just come to update RDT to the latest version. We use a custom server, so have to do the server side set-up as well.
After following the documentation I've found that remix-development-tools/server
doesn't export the functions required by the documentation.
This is with the latest version of RDT.
I want an option where the dev tools icon is hidden unless you mouse over the bottom right.
This looks great, sorry if I'm missing something obvious.
I installed the package and added everything to root.tsx
detailed here. I'm getting an error in the terminal when I run npm run dev
; "remix-development-tools" was not found in your node_modules. Which is odd, cuz it's there.
"@remix-run/node": "^1.14.3",
"@remix-run/react": "^1.14.1",
"@remix-run/dev": "^1.12.0",
"remix-development-tools": "^1.0.4",
node: 18.16.1
npm: 9.5.1
I tried adding the package to remix.config.js
, as suggested here, but getting the same error.
serverDependenciesToBundle: [
/^remix-development-tools.*/,
],
I didn't try upgrading my remix versions, but I'm assuming since you're using 1.18.1 I need to upgrade. If that's the case, I'd be happy to make a PR to add it to the README.
Please advise.
Thank you.
So that one can quickly paste this in github issues
So instead of
{
formData:"{"values":{"2860":[],"2872":[{"text":"2023-08-24T00:00:00.000Z","answerId":2840,"questionId":2872}],"2873":[{"answerId":2843,"questionId":2873}],"2874":[{"answerId":2821,"questionId":2874,"text":"NN"}],"2879":[],"6054":[{"answerId":3391,"questionId":6054}],"6055":[{"answerId":3175,"questionId":6055}],"6056":[{"answerId":2822,"questionId":6056}]},"additionalInfo":{}}"
}
have
{
"formData": {
"values": {
"2860": [],
"2872": [{ "text": "2023-08-24T00:00:00.000Z", "answerId": 2840, "questionId": 2872 }],
"2873": [{ "answerId": 2843, "questionId": 2873 }],
"2874": [{ "answerId": 2821, "questionId": 2874, "text": "NN" }],
"2879": [],
"6054": [{ "answerId": 3391, "questionId": 6054 }],
"6055": [{ "answerId": 3175, "questionId": 6055 }],
"6056": [{ "answerId": 2822, "questionId": 6056 }]
},
"additionalInfo": {}
}
}
also the format the json instead of having one string. That would be nicer to read?
The dist folder contains an index.cjs
, but your package.json says to look for an index.umd.cjs
. Because of this Remix can't find the extension (probably the cause of #4 too)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.