Skip to content

Commit

Permalink
feat: support initially opened overlay for errors (#259)
Browse files Browse the repository at this point in the history
  • Loading branch information
jfairley committed Aug 21, 2023
1 parent e2ed493 commit e5a26d6
Show file tree
Hide file tree
Showing 35 changed files with 511 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/clean-bottles-swim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'vite-plugin-checker': patch
---

feat: support initially open overlay for errors
8 changes: 5 additions & 3 deletions docs/configuration/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ Shared configuration to control the checker behaviors of the plugin.
| boolean
| {
/**
* Set this true if you want the overlay to default to being open if
* errors/warnings are found
* Whether to default the overlay to being open
* - Set `true` to initially open if errors/warnings are found
* - Set `error` to initially open if errors are found
* - Set `false` to initially collapse
* @defaultValue `true`
*/
initialIsOpen?: boolean
initialIsOpen?: boolean | 'error'
/**
* The position of the vite-plugin-checker badge to open and close
* the diagnostics panel
Expand Down
27 changes: 24 additions & 3 deletions packages/runtime/src/App.ce.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts" setup>
import { ref, computed } from 'vue'
import { ref, computed, watch } from 'vue'
import Badge from './components/Badge.ce.vue'
import List from './components/List.ce.vue'
import { useChecker } from './useChecker'
Expand All @@ -21,11 +21,32 @@ const shouldRender = computed(() => {
return checkerResults.value.some((p) => p.diagnostics.length > 0)
})
const collapsed = ref<boolean>(!(props?.overlayConfig?.initialIsOpen ?? true))
// collapsed state if requested (otherwise initially open)
const initialCollapsed = ref<boolean>(
props?.overlayConfig?.initialIsOpen === false || props?.overlayConfig?.initialIsOpen === 'error'
)
// if initialIsOpen is 'error': watch for results and open if there are errors
if (props?.overlayConfig?.initialIsOpen === 'error') {
// checker result is always initially empty, so need to watch for changes
const unwatch = watch(checkerResults, () => {
if (!checkerResults.value.length) return
// non-zero results length means the badge will appear. decide whether to open the overlay.
if (checkerResults.value.some((p) => p.diagnostics.some((d: any) => d.level === 1))) {
initialCollapsed.value = false
}
// stop watching and let the user control the overlay state
unwatch()
})
}
const userCollapsed = ref<boolean | undefined>(undefined)
const toggle = () => {
collapsed.value = !collapsed.value
userCollapsed.value = !(userCollapsed.value ?? initialCollapsed.value)
}
const collapsed = computed<boolean>(() => userCollapsed.value ?? initialCollapsed.value)
</script>

<template>
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/src/components/Badge.ce.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { computed } from 'vue'
const props = withDefaults(
defineProps<{
checkerResults: any
checkerResults: any[]
collapsed: boolean
position?: string
badgeStyle?: string
Expand Down
4 changes: 2 additions & 2 deletions packages/runtime/src/useChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ function resumeErrorOverlay(data: any) {

export function useChecker() {
const ws = prepareListen()
listenToCustomMessage(updateErrorOverlay as any)
listenToReconnectMessage(resumeErrorOverlay as any)
listenToCustomMessage(updateErrorOverlay)
listenToReconnectMessage(resumeErrorOverlay)
ws.startListening()

return {
Expand Down
4 changes: 2 additions & 2 deletions packages/runtime/src/ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ export function listenToConfigMessage(cb: () => any) {
onConfigMessage.push(cb)
}

export function listenToCustomMessage(cb: () => any) {
export function listenToCustomMessage(cb: (data: any) => any) {
onCustomMessage.push(cb)
}

export function listenToReconnectMessage(cb: () => any) {
export function listenToReconnectMessage(cb: (data: any) => any) {
onReconnectMessage.push(cb)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Vitest Snapshot v1
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`logger > diagnosticToTerminalLog > get error 1`] = `
" ERROR(ESLint) Unexpected var, use let or const instead.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Vitest Snapshot v1
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`VLS config > customized config 1`] = `
{
Expand Down
2 changes: 1 addition & 1 deletion packages/vite-plugin-checker/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export interface SharedConfig {
* errors/warnings are found
* @defaultValue `true`
*/
initialIsOpen?: boolean
initialIsOpen?: boolean | 'error'
/**
* The position of the vite-plugin-checker badge to open and close
* the diagnostics panel
Expand Down
4 changes: 4 additions & 0 deletions playground/config-initialIsOpen-error-clean/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"root": true,
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"]
}
44 changes: 44 additions & 0 deletions playground/config-initialIsOpen-error-clean/__tests__/test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { describe, expect, it } from 'vitest'

import {
editFile,
getHmrOverlayText,
isServe,
sleepForEdit,
sleepForServerReady,
} from '../../testUtils'

describe('config-initialIsOpen-error-clean', () => {
describe.runIf(isServe)('serve', () => {
it('should not find overlay', async () => {
if (isServe) {
await sleepForServerReady()
await expect(getHmrOverlayText()).rejects.toThrow(
'Invariant failed: .message-body is expected in shadow root'
)

console.log('-- badge appears, but overlay remains collapsed after error introduced --')
editFile('src/main.ts', (code) => code.replace('const hello', 'var hello'))
await sleepForEdit()
try {
await getHmrOverlayText()
} catch (e) {
expect((e as any).toString()).toContain(
'Invariant failed: <vite-plugin-checker-error-overlay> shadow dom is expected to be found, but got null'
)
}

console.log('-- badge remains, overlay remains collapsed after warning introduced --')
editFile('src/main.ts', (code) => code.replace(' as', '! as'))
await sleepForEdit()
try {
await getHmrOverlayText()
} catch (e) {
expect((e as any).toString()).toContain(
'Invariant failed: <vite-plugin-checker-error-overlay> shadow dom is expected to be found, but got null'
)
}
}
})
})
})
13 changes: 13 additions & 0 deletions playground/config-initialIsOpen-error-clean/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
26 changes: 26 additions & 0 deletions playground/config-initialIsOpen-error-clean/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"private": true,
"name": "@playground/config-initial-is-open-error-clean",
"type": "module",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"lint": "eslint --ext .js,.ts ./src/**"
},
"dependencies": {
"react": "^17.0.0",
"react-dom": "^17.0.0"
},
"devDependencies": {
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^5.59.0",
"@typescript-eslint/parser": "^5.59.0",
"eslint": "^8.11.0",
"typescript": "^5.0.4",
"vite": "^4.3.0",
"vite-plugin-checker": "workspace:*"
}
}
8 changes: 8 additions & 0 deletions playground/config-initialIsOpen-error-clean/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { text } from './text'

const hello = 'Hello'

const rootDom = document.querySelector('#root') as HTMLElement
rootDom.innerHTML = hello + text

export {}
1 change: 1 addition & 0 deletions playground/config-initialIsOpen-error-clean/src/text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const text = 'Vanilla JS/TS'
19 changes: 19 additions & 0 deletions playground/config-initialIsOpen-error-clean/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"types": ["vite/client"],
"allowJs": false,
"skipLibCheck": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
},
"include": ["./src"]
}
15 changes: 15 additions & 0 deletions playground/config-initialIsOpen-error-clean/vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { defineConfig } from 'vite'
import checker from 'vite-plugin-checker'

export default defineConfig({
plugins: [
checker({
overlay: {
initialIsOpen: 'error',
},
eslint: {
lintCommand: 'eslint ./src --ext .ts',
},
}),
],
})
4 changes: 4 additions & 0 deletions playground/config-initialIsOpen-error-warnings/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"root": true,
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { describe, expect, it } from 'vitest'

import { editFile, getHmrOverlayText, isServe, sleepForEdit, sleepForServerReady } from '../../testUtils'

describe('config-initialIsOpen-error-warnings', () => {
describe.runIf(isServe)('serve', () => {
it('should not find overlay', async () => {
if (isServe) {
await sleepForServerReady()
try {
await getHmrOverlayText()
} catch (e) {
expect((e as any).toString()).toContain(
'Invariant failed: <vite-plugin-checker-error-overlay> shadow dom is expected to be found, but got null'
)
}

console.log('-- overlay remains closed after introduced error --')
editFile('src/main.ts', (code) => code.replace('! as', '! is'))
await sleepForEdit()
try {
await getHmrOverlayText()
} catch (e) {
expect((e as any).toString()).toContain(
'Invariant failed: <vite-plugin-checker-error-overlay> shadow dom is expected to be found, but got null'
)
}
}
})
})
})
13 changes: 13 additions & 0 deletions playground/config-initialIsOpen-error-warnings/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="src/favicon.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
26 changes: 26 additions & 0 deletions playground/config-initialIsOpen-error-warnings/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"private": true,
"name": "@playground/config-initial-is-open-error-warnings",
"type": "module",
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"lint": "eslint --ext .js,.ts ./src/**"
},
"dependencies": {
"react": "^17.0.0",
"react-dom": "^17.0.0"
},
"devDependencies": {
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@typescript-eslint/eslint-plugin": "^5.59.0",
"@typescript-eslint/parser": "^5.59.0",
"eslint": "^8.11.0",
"typescript": "^5.0.4",
"vite": "^4.3.0",
"vite-plugin-checker": "workspace:*"
}
}
6 changes: 6 additions & 0 deletions playground/config-initialIsOpen-error-warnings/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { text } from './text'

const rootDom = document.querySelector('#root')! as HTMLElement
rootDom.innerHTML = text

export {}
1 change: 1 addition & 0 deletions playground/config-initialIsOpen-error-warnings/src/text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const text = 'Vanilla JS/TS'
19 changes: 19 additions & 0 deletions playground/config-initialIsOpen-error-warnings/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ESNext",
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"types": ["vite/client"],
"allowJs": false,
"skipLibCheck": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true
},
"include": ["./src"]
}
15 changes: 15 additions & 0 deletions playground/config-initialIsOpen-error-warnings/vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { defineConfig } from 'vite'
import checker from 'vite-plugin-checker'

export default defineConfig({
plugins: [
checker({
overlay: {
initialIsOpen: 'error',
},
eslint: {
lintCommand: 'eslint ./src --ext .ts',
},
}),
],
})
4 changes: 4 additions & 0 deletions playground/config-initialIsOpen-error/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"root": true,
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"]
}

0 comments on commit e5a26d6

Please sign in to comment.