Skip to content

Commit 1125c8a

Browse files
committed
fix(vite,nuxt): skip on explicit file extensions
1 parent f54cbe4 commit 1125c8a

File tree

3 files changed

+155
-4
lines changed

3 files changed

+155
-4
lines changed

packages/nuxt/src/runtime/server/middleware/mdream.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,19 @@ export default defineEventHandler(async (event) => {
9090
let path = event.path
9191
const config = useRuntimeConfig(event).mdream as ModuleRuntimeConfig
9292

93-
// never run on API routes, internal routes or explicit html requests
94-
if (path.startsWith('/api') || path.startsWith('/_') || path.endsWith('.html')) {
93+
// never run on API routes or internal routes
94+
if (path.startsWith('/api') || path.startsWith('/_') || path.startsWith('/@')) {
95+
return
96+
}
97+
98+
// Extract file extension from path (e.g., /file.js -> .js, /path/to/file.css -> .css)
99+
const lastSegment = path.split('/').pop() || ''
100+
const hasExtension = lastSegment.includes('.')
101+
const extension = hasExtension ? lastSegment.substring(lastSegment.lastIndexOf('.')) : ''
102+
103+
// Only run on .md extension or no extension at all
104+
// Skip all other file extensions (.js, .css, .html, .json, etc.)
105+
if (hasExtension && extension !== '.md') {
95106
return
96107
}
97108

packages/vite/src/plugin.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,19 @@ export function viteHtmlToMarkdownPlugin(userOptions: ViteHtmlToMarkdownOptions
192192
req.headers['sec-fetch-dest'] as string | undefined,
193193
)
194194

195-
// never run on API routes, internal routes or explicit html requests
196-
if (path.startsWith('/api') || path.startsWith('/_') || path.endsWith('.html')) {
195+
// never run on API routes or internal routes
196+
if (path.startsWith('/api') || path.startsWith('/_') || path.startsWith('/@')) {
197+
return next()
198+
}
199+
200+
// Extract file extension from path (e.g., /file.js -> .js, /path/to/file.css -> .css)
201+
const lastSegment = path.split('/').pop() || ''
202+
const hasExtension = lastSegment.includes('.')
203+
const extension = hasExtension ? lastSegment.substring(lastSegment.lastIndexOf('.')) : ''
204+
205+
// Only run on .md extension or no extension at all
206+
// Skip all other file extensions (.js, .css, .html, .json, etc.)
207+
if (hasExtension && extension !== '.md') {
197208
return next()
198209
}
199210

packages/vite/test/unit/plugin-route-filtering.test.ts

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,30 @@ describe('viteHtmlToMarkdownPlugin - Route Filtering', () => {
7575
expect(mockRes.setHeader).not.toHaveBeenCalled()
7676
})
7777

78+
it('should skip /@ Vite internal routes', async () => {
79+
const plugin = viteHtmlToMarkdownPlugin({ verbose: false }) as Plugin & { configureServer: Function }
80+
81+
const mockServer = {
82+
transformRequest: vi.fn(),
83+
middlewares: { use: vi.fn() },
84+
} as unknown as ViteDevServer
85+
86+
plugin.configureServer(mockServer)
87+
const middleware = (mockServer.middlewares.use as ReturnType<typeof vi.fn>).mock.calls[0][0]
88+
89+
const mockReq = {
90+
url: '/@vite/client',
91+
headers: { accept: '*/*' },
92+
}
93+
const mockRes = { setHeader: vi.fn(), end: vi.fn() }
94+
const mockNext = vi.fn()
95+
96+
await middleware(mockReq, mockRes, mockNext)
97+
98+
expect(mockNext).toHaveBeenCalled()
99+
expect(mockRes.setHeader).not.toHaveBeenCalled()
100+
})
101+
78102
it('should skip explicit .html requests', async () => {
79103
const plugin = viteHtmlToMarkdownPlugin({ verbose: false }) as Plugin & { configureServer: Function }
80104

@@ -131,4 +155,109 @@ describe('viteHtmlToMarkdownPlugin - Route Filtering', () => {
131155
expect(mockRes.setHeader).toHaveBeenCalledWith('Content-Type', 'text/markdown; charset=utf-8')
132156
expect(mockNext).not.toHaveBeenCalled()
133157
})
158+
159+
it('should skip .js files', async () => {
160+
const plugin = viteHtmlToMarkdownPlugin({ verbose: false }) as Plugin & { configureServer: Function }
161+
162+
const mockServer = {
163+
transformRequest: vi.fn(),
164+
middlewares: { use: vi.fn() },
165+
} as unknown as ViteDevServer
166+
167+
plugin.configureServer(mockServer)
168+
const middleware = (mockServer.middlewares.use as ReturnType<typeof vi.fn>).mock.calls[0][0]
169+
170+
const mockReq = {
171+
url: '/app.js',
172+
headers: { accept: '*/*' },
173+
}
174+
const mockRes = { setHeader: vi.fn(), end: vi.fn() }
175+
const mockNext = vi.fn()
176+
177+
await middleware(mockReq, mockRes, mockNext)
178+
179+
expect(mockNext).toHaveBeenCalled()
180+
expect(mockRes.setHeader).not.toHaveBeenCalled()
181+
})
182+
183+
it('should skip .css files', async () => {
184+
const plugin = viteHtmlToMarkdownPlugin({ verbose: false }) as Plugin & { configureServer: Function }
185+
186+
const mockServer = {
187+
transformRequest: vi.fn(),
188+
middlewares: { use: vi.fn() },
189+
} as unknown as ViteDevServer
190+
191+
plugin.configureServer(mockServer)
192+
const middleware = (mockServer.middlewares.use as ReturnType<typeof vi.fn>).mock.calls[0][0]
193+
194+
const mockReq = {
195+
url: '/styles.css',
196+
headers: { accept: '*/*' },
197+
}
198+
const mockRes = { setHeader: vi.fn(), end: vi.fn() }
199+
const mockNext = vi.fn()
200+
201+
await middleware(mockReq, mockRes, mockNext)
202+
203+
expect(mockNext).toHaveBeenCalled()
204+
expect(mockRes.setHeader).not.toHaveBeenCalled()
205+
})
206+
207+
it('should skip .json files', async () => {
208+
const plugin = viteHtmlToMarkdownPlugin({ verbose: false }) as Plugin & { configureServer: Function }
209+
210+
const mockServer = {
211+
transformRequest: vi.fn(),
212+
middlewares: { use: vi.fn() },
213+
} as unknown as ViteDevServer
214+
215+
plugin.configureServer(mockServer)
216+
const middleware = (mockServer.middlewares.use as ReturnType<typeof vi.fn>).mock.calls[0][0]
217+
218+
const mockReq = {
219+
url: '/data.json',
220+
headers: { accept: '*/*' },
221+
}
222+
const mockRes = { setHeader: vi.fn(), end: vi.fn() }
223+
const mockNext = vi.fn()
224+
225+
await middleware(mockReq, mockRes, mockNext)
226+
227+
expect(mockNext).toHaveBeenCalled()
228+
expect(mockRes.setHeader).not.toHaveBeenCalled()
229+
})
230+
231+
it('should allow routes with no extension when client prefers markdown', async () => {
232+
const plugin = viteHtmlToMarkdownPlugin({ verbose: false }) as Plugin & { configureServer: Function }
233+
234+
const mockTransformRequest = vi.fn().mockResolvedValue({
235+
code: '<html><body>Content</body></html>',
236+
})
237+
238+
const mockServer = {
239+
transformRequest: mockTransformRequest,
240+
middlewares: { use: vi.fn() },
241+
} as unknown as ViteDevServer
242+
243+
plugin.configureServer(mockServer)
244+
const middleware = (mockServer.middlewares.use as ReturnType<typeof vi.fn>).mock.calls[0][0]
245+
246+
const mockReq = {
247+
url: '/about',
248+
headers: { accept: '*/*' },
249+
}
250+
const mockRes = {
251+
setHeader: vi.fn(),
252+
end: vi.fn(),
253+
statusCode: 200,
254+
}
255+
const mockNext = vi.fn()
256+
257+
await middleware(mockReq, mockRes, mockNext)
258+
259+
expect(mockTransformRequest).toHaveBeenCalled()
260+
expect(mockRes.setHeader).toHaveBeenCalledWith('Content-Type', 'text/markdown; charset=utf-8')
261+
expect(mockNext).not.toHaveBeenCalled()
262+
})
134263
})

0 commit comments

Comments
 (0)