From 09da8a564c0e552f0445266c0cb21304be80b531 Mon Sep 17 00:00:00 2001 From: Jerry_Wu <409187100@qq.com> Date: Mon, 27 Oct 2025 17:54:21 +0800 Subject: [PATCH] chore: update Tailwind CSS packages and improve theme toggle functionality in UI --- .changeset/rude-tomatoes-deny.md | 5 + packages/devtools/package.json | 15 +- packages/playgrounds/src/root.tsx | 2 +- packages/plugin/src/npm/index.ts | 43 +++++- packages/ui/package.json | 8 +- .../DevtoolsContainer/DevtoolsContainer.tsx | 6 +- .../{ThemeToggle.tsx => QwikThemeToggle.tsx} | 2 +- packages/ui/src/devtools.tsx | 135 +++++++++++------- .../ui/src/features/RenderTree/RenderTree.tsx | 48 ++++--- packages/ui/src/global.css | 3 +- packages/ui/tailwind.config.ts | 7 + packages/ui/vite.config.mts | 5 +- pnpm-lock.yaml | 38 +++-- 13 files changed, 208 insertions(+), 109 deletions(-) create mode 100644 .changeset/rude-tomatoes-deny.md rename packages/ui/src/components/ThemeToggle/{ThemeToggle.tsx => QwikThemeToggle.tsx} (97%) create mode 100644 packages/ui/tailwind.config.ts diff --git a/.changeset/rude-tomatoes-deny.md b/.changeset/rude-tomatoes-deny.md new file mode 100644 index 0000000..6e56d04 --- /dev/null +++ b/.changeset/rude-tomatoes-deny.md @@ -0,0 +1,5 @@ +--- +'@qwik.dev/devtools': patch +--- + +chore: update Tailwind CSS packages and improve theme toggle functionality in UI diff --git a/packages/devtools/package.json b/packages/devtools/package.json index c182398..67cfe60 100644 --- a/packages/devtools/package.json +++ b/packages/devtools/package.json @@ -12,8 +12,12 @@ }, "./ui": { "import": "./dist/ui/index.qwik.mjs", - "require": "./dist/ui/index.qwik.cjs", - "types": "./dist/ui/lib-types/ui/src/index.d.ts" + "types": "./dist/ui/lib-types/ui/src/index.d.ts", + "style": "./dist/ui/style.css" + + }, + "./style": { + "import": "./dist/ui/theme.css" } }, "files": [ @@ -23,7 +27,10 @@ "peerDependencies": { "@qwik.dev/core": "2.0.0-beta.11", "@qwik.dev/router": "2.0.0-beta.11", - "vite": "7.1.3" + "vite": "7.1.3", + "@tailwindcss/postcss": "^4.1.14", + "@tailwindcss/vite": "^4.1.14", + "tailwindcss": "^4.1.14" }, "dependencies": { "@qwikest/icons": "^0.0.13", @@ -59,4 +66,4 @@ "url": "https://github.com/QwikDev/devtools/issues" }, "homepage": "https://github.com/QwikDev/devtools#readme" -} +} \ No newline at end of file diff --git a/packages/playgrounds/src/root.tsx b/packages/playgrounds/src/root.tsx index b01d4c7..e9b2724 100644 --- a/packages/playgrounds/src/root.tsx +++ b/packages/playgrounds/src/root.tsx @@ -7,7 +7,7 @@ import { } from '@qwik.dev/router'; import { RouterHead } from './components/router-head/router-head'; import './global.css'; - +import '../../devtools/dist/ui/style.css'; export default component$(() => { /** * The root of a QwikRouter site always start with the component, diff --git a/packages/plugin/src/npm/index.ts b/packages/plugin/src/npm/index.ts index 543250e..e053fbf 100644 --- a/packages/plugin/src/npm/index.ts +++ b/packages/plugin/src/npm/index.ts @@ -34,6 +34,35 @@ function setCachedPackage(name: string, data: any): void { }); } +async function findNearestFileUp(startDir: string, fileName: string): Promise { + try { + let currentDir = path.resolve(startDir); + // Guard against infinite loops by capping directory ascents + for (let i = 0; i < 100; i++) { + const candidate = path.join(currentDir, fileName); + const exists = await fsp + .access(candidate) + .then(() => true) + .catch(() => false); + if (exists) return candidate; + + const parent = path.dirname(currentDir); + if (parent === currentDir) break; + currentDir = parent; + } + return null; + } catch { + return null; + } +} + +function getProjectStartDirFromConfig(config: any): string { + // Prefer Vite's resolved root; fallback to the directory of the config file; finally cwd + if (config?.root) return config.root; + if (config?.configFile) return path.dirname(config.configFile); + return process.cwd(); +} + export async function detectPackageManager( projectRoot: string, ): Promise<'npm' | 'pnpm' | 'yarn'> { @@ -84,9 +113,8 @@ const preloadDependencies = async (config: any): Promise => { console.log('[Qwik DevTools] Starting to preload dependencies...'); preloadPromise = (async () => { - const pathToPackageJson = config.configFileDependencies.find( - (file: string) => file.endsWith('package.json'), - ); + const startDir = getProjectStartDirFromConfig(config); + const pathToPackageJson = await findNearestFileUp(startDir, 'package.json'); if (!pathToPackageJson) { preloadedDependencies = []; @@ -259,9 +287,8 @@ export async function startPreloading({ config }: { config: any }) { export function getNpmFunctions({ config }: ServerContext) { return { async getQwikPackages(): Promise { - const pathToPackageJson = config.configFileDependencies.find( - (file: string) => file.endsWith('package.json'), - ); + const startDir = getProjectStartDirFromConfig(config); + const pathToPackageJson = await findNearestFileUp(startDir, 'package.json'); if (!pathToPackageJson) return []; try { @@ -298,7 +325,9 @@ export function getNpmFunctions({ config }: ServerContext) { isDev = true, ): Promise<{ success: boolean; error?: string }> { try { - const projectRoot = path.dirname(config.configFileDependencies[0]); + const startDir = getProjectStartDirFromConfig(config); + const pathToPackageJson = await findNearestFileUp(startDir, 'package.json'); + const projectRoot = pathToPackageJson ? path.dirname(pathToPackageJson) : startDir; const pm = await detectPackageManager(projectRoot); const devFlag = isDev ? (pm === 'npm' ? '--save-dev' : '-D') : ''; diff --git a/packages/ui/package.json b/packages/ui/package.json index 67005bd..85c7a37 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -34,13 +34,14 @@ }, "peerDependencies": { "@devtools/plugin": "workspace:*", - "@qwik.dev/core": "2.0.0-beta.11" + "@qwik.dev/core": "2.0.0-beta.11", + "@tailwindcss/postcss": "^4.1.14", + "@tailwindcss/vite": "^4.1.14", + "tailwindcss": "^4.1.14" }, "devDependencies": { "@devtools/kit": "workspace:*", "@qwikest/icons": "^0.0.13", - "@tailwindcss/postcss": "^4.0.0", - "@tailwindcss/vite": "^4.0.0", "@types/eslint": "8.56.10", "@types/node": "20.14.11", "@types/react": "^18.2.28", @@ -63,7 +64,6 @@ "react-dom": "18.2.0", "shiki": "^3.8.1", "superjson": "^2.2.2", - "tailwindcss": "^4.0.0", "typescript": "5.4.5", "vite": "7.1.3", "vite-hot-client": "2.0.4", diff --git a/packages/ui/src/components/DevtoolsContainer/DevtoolsContainer.tsx b/packages/ui/src/components/DevtoolsContainer/DevtoolsContainer.tsx index 4f930a2..1f5537f 100644 --- a/packages/ui/src/components/DevtoolsContainer/DevtoolsContainer.tsx +++ b/packages/ui/src/components/DevtoolsContainer/DevtoolsContainer.tsx @@ -2,8 +2,10 @@ import { component$, Slot } from '@qwik.dev/core'; export const DevtoolsContainer = component$(() => { return ( -
- +
+
+ +
); }); diff --git a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx b/packages/ui/src/components/ThemeToggle/QwikThemeToggle.tsx similarity index 97% rename from packages/ui/src/components/ThemeToggle/ThemeToggle.tsx rename to packages/ui/src/components/ThemeToggle/QwikThemeToggle.tsx index 7426032..51e806b 100644 --- a/packages/ui/src/components/ThemeToggle/ThemeToggle.tsx +++ b/packages/ui/src/components/ThemeToggle/QwikThemeToggle.tsx @@ -29,7 +29,7 @@ export const setTheme = (theme: ThemeName) => { localStorage.setItem(themeStorageKey, theme); }; -export const ThemeToggle = component$(() => { +export const QwikThemeToggle = component$(() => { useStyles$(themeTogglecss); const onClick$ = event$(() => { let currentTheme = getTheme(); diff --git a/packages/ui/src/devtools.tsx b/packages/ui/src/devtools.tsx index 3206fe7..21e242f 100644 --- a/packages/ui/src/devtools.tsx +++ b/packages/ui/src/devtools.tsx @@ -38,7 +38,7 @@ import { DevtoolsContainer } from './components/DevtoolsContainer/DevtoolsContai import { DevtoolsPanel } from './components/DevtoolsPanel/DevtoolsPanel'; import { Packages } from './features/Packages/Packages'; import { Inspect } from './features/inspect/Inspect'; -import { ThemeToggle } from './components/ThemeToggle/ThemeToggle'; +import { QwikThemeToggle } from './components/ThemeToggle/QwikThemeToggle'; import { ThemeScript as QwikThemeScript } from './components/ThemeToggle/theme-script'; import { CodeBreack } from './features/CodeBreack/CodeBreack'; function getClientRpcFunctions() { @@ -60,66 +60,97 @@ export const QwikDevtools = component$(() => { isLoadingDependencies: false, }); - useVisibleTask$(async ({ track }) => { - const hot = await tryCreateHotContext(undefined, ['/']); + const clientReady = useSignal(false); + useVisibleTask$(async () => { + const hot = await tryCreateHotContext(undefined, ['/']); if (!hot) { throw new Error('Vite Hot Context not connected'); } setViteClientContext(hot); createClientRpc(getClientRpcFunctions()); + clientReady.value = true; + }); - // Start loading data immediately in background - // Dependencies are already being preloaded on the server side + useVisibleTask$(async ({ track }) => { + track(() => clientReady.value); + if (!clientReady.value) return; const rpc = getViteClientRpc(); - state.isLoadingDependencies = true; + try { + const assets = await rpc.getAssetsFromPublicDir(); + state.assets = assets; + } catch (error) { + console.error('Failed to load assets:', error); + } + }); - // Preload all data in parallel immediately - Promise.all([ - rpc.getAssetsFromPublicDir(), - rpc.getComponents(), - rpc.getRoutes(), - rpc.getQwikPackages(), - rpc.getAllDependencies(), // This returns server-preloaded data instantly - ]) - .then(([assets, components, routes, qwikPackages, allDeps]) => { - state.assets = assets; - state.components = components; - - const children: RoutesInfo[] = routes?.children || []; - const directories: RoutesInfo[] = children.filter( - (child) => child.type === 'directory', - ); - - const values: RoutesInfo[] = [ - { - relativePath: '', - name: 'index', - type: RouteType.DIRECTORY, - path: '', - isSymbolicLink: false, - children: undefined, - }, - ...directories, - ]; - - state.routes = noSerialize(values); - state.npmPackages = qwikPackages; - state.allDependencies = allDeps; - state.isLoadingDependencies = false; - }) - .catch((error) => { - console.error('Failed to load devtools data:', error); - state.isLoadingDependencies = false; - }); - - // Track devtools open state for other purposes if needed - track(() => { - if (state.isOpen.value) { - // Devtools is now open, data should already be loaded or loading - } - }); + useVisibleTask$(async ({ track }) => { + track(() => clientReady.value); + if (!clientReady.value) return; + const rpc = getViteClientRpc(); + try { + const components = await rpc.getComponents(); + state.components = components; + } catch (error) { + console.error('Failed to load components:', error); + } + }); + + useVisibleTask$(async ({ track }) => { + track(() => clientReady.value); + if (!clientReady.value) return; + const rpc = getViteClientRpc(); + try { + const routes = await rpc.getRoutes(); + const children: RoutesInfo[] = routes?.children || []; + const directories: RoutesInfo[] = children.filter( + (child) => child.type === 'directory', + ); + + const values: RoutesInfo[] = [ + { + relativePath: '', + name: 'index', + type: RouteType.DIRECTORY, + path: '', + isSymbolicLink: false, + children: undefined, + }, + ...directories, + ]; + + state.routes = noSerialize(values); + } catch (error) { + console.error('Failed to load routes:', error); + } + }); + + useVisibleTask$(async ({ track }) => { + track(() => clientReady.value); + if (!clientReady.value) return; + const rpc = getViteClientRpc(); + try { + const qwikPackages = await rpc.getQwikPackages(); + state.npmPackages = qwikPackages; + } catch (error) { + console.error('Failed to load Qwik packages:', error); + } + }); + + useVisibleTask$(async ({ track }) => { + track(() => clientReady.value); + if (!clientReady.value) return; + const rpc = getViteClientRpc(); + state.isLoadingDependencies = true; + try { + const allDeps = await rpc.getAllDependencies(); + state.allDependencies = allDeps; + } catch (error) { + console.error('Failed to load all dependencies:', error); + } finally { + state.isLoadingDependencies = false; + } }); return ( @@ -153,7 +184,7 @@ export const QwikDevtools = component$(() => { < HiCodeBracketSolid class="h-5 w-5" />
- +
diff --git a/packages/ui/src/features/RenderTree/RenderTree.tsx b/packages/ui/src/features/RenderTree/RenderTree.tsx index aace17b..aedeea2 100644 --- a/packages/ui/src/features/RenderTree/RenderTree.tsx +++ b/packages/ui/src/features/RenderTree/RenderTree.tsx @@ -5,6 +5,8 @@ import { $, useSignal, useStyles$, + useResource$, + Resource, } from '@qwik.dev/core'; import { Tree, TreeNode } from '../../components/Tree/Tree'; import { vnode_toObject } from '../../components/Tree/filterVnode'; @@ -79,19 +81,16 @@ export const RenderTree = component$(() => { } }); - const highlightedCodes = useSignal([]); - - useVisibleTask$(async ({ track }) => { + const highlightedCodesResource = useResource$(async ({ track }) => { track(() => codes.value); if (!codes.value.length) { - highlightedCodes.value = []; - return; + return [] as string[]; } const highlighter = await createHighlighter({ - themes: ['nord'], // v1+ requires array + themes: ['nord'], langs: ['tsx', 'js', 'ts', 'jsx'], }); - highlightedCodes.value = codes.value.map((item) => { + return codes.value.map((item) => { let lang = 'tsx'; if (item.pathId.endsWith('.js')) lang = 'js'; if (item.pathId.endsWith('.ts')) lang = 'ts'; @@ -147,6 +146,7 @@ export const RenderTree = component$(() => { codes.value = []; const res = await rpc?.getModulesByPathIds(findAllQrl()); + console.log('res', res); codes.value = res.filter((item) => item.modules); stateTree.value = buildTree() as TreeNode[]; hookFilters.value = getHookFilterList(); @@ -309,23 +309,27 @@ export const RenderTree = component$(() => { {currentTab.value === 'code' && (
- {codes.value.map((item, idx) => { - return ( +
Loading code highlights…
} + onResolved={(highlighted) => ( <> -
-
- {item.pathId} -
-
-                    
+ {codes.value.map((item, idx) => ( + <> +
+
+ {item.pathId} +
+
+                        
+ + ))} - ); - })} + )} + />
)} diff --git a/packages/ui/src/global.css b/packages/ui/src/global.css index 9bb8d5b..92c53f1 100644 --- a/packages/ui/src/global.css +++ b/packages/ui/src/global.css @@ -2,10 +2,9 @@ * Tailwind CSS imports (v4) * View the full documentation at https://tailwindcss.com */ +@config "../tailwind.config.ts"; @import "tailwindcss"; -@custom-variant dark (&:where(:root[data-theme="dark"] &)); - @theme { /* default (light) tokens; can be overridden by :root rules below */ --color-background: #ffffff; diff --git a/packages/ui/tailwind.config.ts b/packages/ui/tailwind.config.ts new file mode 100644 index 0000000..bd95a57 --- /dev/null +++ b/packages/ui/tailwind.config.ts @@ -0,0 +1,7 @@ + +export default { + important: '.qwik-devtools', + +}; + + diff --git a/packages/ui/vite.config.mts b/packages/ui/vite.config.mts index 9928045..7d0bea9 100644 --- a/packages/ui/vite.config.mts +++ b/packages/ui/vite.config.mts @@ -25,9 +25,8 @@ export default defineConfig(() => { target: 'es2020', lib: { entry: './src/index.ts', - formats: ['es', 'cjs'], - fileName: (format, entryName) => - `${entryName}.qwik.${format === 'es' ? 'mjs' : 'cjs'}`, + formats: ['es'], + fileName: (format, entryName) => `${entryName}.qwik.mjs`, }, rollupOptions: { output: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 364fc44..47e8a5a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,12 @@ importers: '@qwikest/icons': specifier: ^0.0.13 version: 0.0.13(@builder.io/qwik@1.11.0(vite@7.1.3(@types/node@22.10.5)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)(yaml@2.8.1))) + '@tailwindcss/postcss': + specifier: ^4.1.14 + version: 4.1.14 + '@tailwindcss/vite': + specifier: ^4.1.14 + version: 4.1.14(vite@7.1.3(@types/node@22.10.5)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)(yaml@2.8.1)) birpc: specifier: ^0.2.19 version: 0.2.19 @@ -53,6 +59,9 @@ importers: superjson: specifier: ^2.2.2 version: 2.2.2 + tailwindcss: + specifier: ^4.1.14 + version: 4.1.14 vite: specifier: 7.1.3 version: 7.1.3(@types/node@22.10.5)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)(yaml@2.8.1) @@ -242,6 +251,15 @@ importers: '@qwik.dev/core': specifier: 2.0.0-beta.11 version: 2.0.0-beta.11(prettier@3.3.3)(vite@7.1.3(@types/node@20.14.11)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)(yaml@2.8.1))(vitest@3.2.4) + '@tailwindcss/postcss': + specifier: ^4.1.14 + version: 4.1.14 + '@tailwindcss/vite': + specifier: ^4.1.14 + version: 4.1.14(vite@7.1.3(@types/node@20.14.11)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)(yaml@2.8.1)) + tailwindcss: + specifier: ^4.1.14 + version: 4.1.14 devDependencies: '@devtools/kit': specifier: workspace:* @@ -249,12 +267,6 @@ importers: '@qwikest/icons': specifier: ^0.0.13 version: 0.0.13(@builder.io/qwik@1.11.0(vite@7.1.3(@types/node@20.14.11)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)(yaml@2.8.1))) - '@tailwindcss/postcss': - specifier: ^4.0.0 - version: 4.1.14 - '@tailwindcss/vite': - specifier: ^4.0.0 - version: 4.1.14(vite@7.1.3(@types/node@20.14.11)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)(yaml@2.8.1)) '@types/eslint': specifier: 8.56.10 version: 8.56.10 @@ -321,9 +333,6 @@ importers: superjson: specifier: ^2.2.2 version: 2.2.2 - tailwindcss: - specifier: ^4.0.0 - version: 4.1.14 typescript: specifier: 5.4.5 version: 5.4.5 @@ -6404,7 +6413,7 @@ snapshots: '@jridgewell/gen-mapping@0.3.8': dependencies: '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/remapping@2.3.5': @@ -6423,7 +6432,7 @@ snapshots: '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 '@manypkg/find-root@1.1.0': dependencies: @@ -7128,6 +7137,13 @@ snapshots: tailwindcss: 4.1.14 vite: 7.1.3(@types/node@20.14.11)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)(yaml@2.8.1) + '@tailwindcss/vite@4.1.14(vite@7.1.3(@types/node@22.10.5)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)(yaml@2.8.1))': + dependencies: + '@tailwindcss/node': 4.1.14 + '@tailwindcss/oxide': 4.1.14 + tailwindcss: 4.1.14 + vite: 7.1.3(@types/node@22.10.5)(jiti@2.6.1)(lightningcss@1.30.1)(tsx@4.19.2)(yaml@2.8.1) + '@trysound/sax@0.2.0': {} '@tybys/wasm-util@0.10.0':