From 4b95cc3ab02835448f7af32b97038e28c64c8673 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Tue, 12 May 2026 14:42:47 +0300 Subject: [PATCH 1/2] fix(pfe-tools): use WDS plugin for TS redirect instead of koa middleware The liveReloadTsChangesMiddleware ran as koa middleware, which executes AFTER WDS static file serving (koa-send). When a .js file didn't exist on disk, koa-send returned 404 before the middleware could redirect to the .ts source. Convert to a WDS plugin with a serve hook, which runs BEFORE static file resolution. This fixes 404 errors for elements that only have .ts source files (no pre-compiled .js). Assisted-By: Claude Opus 4.6 (1M context) --- tools/pfe-tools/dev-server/config.ts | 36 +++++++++++++--------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/tools/pfe-tools/dev-server/config.ts b/tools/pfe-tools/dev-server/config.ts index 806e9a182f..6b19abc97b 100644 --- a/tools/pfe-tools/dev-server/config.ts +++ b/tools/pfe-tools/dev-server/config.ts @@ -1,4 +1,4 @@ -import type { Plugin, Context, Middleware } from '@web/dev-server-core'; +import type { Plugin, Context } from '@web/dev-server-core'; import type { DevServerConfig } from '@web/dev-server'; import { readdir, stat } from 'node:fs/promises'; @@ -85,25 +85,19 @@ async function cacheBusterMiddleware(ctx: Context, next: () => Promise) { } } -function liveReloadTsChangesMiddleware( +function tsRedirectPlugin( config: ReturnType, -): Middleware { - /** - * capture group 1: - * Either config.elementsDir or `pfe-core` - * `/` - * **ANY** (_>= 0x_) - * `.js` - */ - const TYPESCRIPT_SOURCES_RE = new RegExp(`(${config.elementsDir}|pfe-core)/.*\\.js`); - - return function(ctx, next) { - if (!ctx.path.includes('node_modules') && ctx.path - .match(TYPESCRIPT_SOURCES_RE)) { - ctx.redirect(ctx.path.replace('.js', '.ts')); - } else { - return next(); - } +): Plugin { + const TYPESCRIPT_SOURCES_RE = new RegExp(`(${config.elementsDir}|pfe-core)/.*\\.js$`); + return { + name: 'pfe-ts-redirect', + serve(context) { + if (!context.path.includes('node_modules') + && TYPESCRIPT_SOURCES_RE.test(context.path)) { + // Rewrite .js to .ts so esbuild plugin can compile it + context.path = context.path.replace(/\.js$/, '.ts'); + } + }, }; } @@ -124,11 +118,13 @@ export function pfeDevServerConfig(options?: PfeDevServerConfigOptions): DevServ middleware: [ cors, cacheBusterMiddleware, - liveReloadTsChangesMiddleware(config), ...config?.middleware ?? [], ], plugins: [ + // Rewrite .js paths to .ts before static file serving + tsRedirectPlugin(config), + // Dev server app which loads component demo files pfeDevServerPlugin(config), From c0b44f9d2d4fb87b9aafe7142070ba32a476c623 Mon Sep 17 00:00:00 2001 From: Benny Powers Date: Wed, 13 May 2026 09:43:41 +0300 Subject: [PATCH 2/2] fix(pfe-tools): redirect .js to .ts only on 404 The previous approach (serve hook) broke esbuild compilation because returning from serve() prevents other plugins from running. Instead, keep the koa middleware but call next() first, then redirect to .ts only when the .js file doesn't exist (404). This is backwards compatible: when compiled .js exists, it serves normally. Assisted-By: Claude Opus 4.6 (1M context) --- tools/pfe-tools/dev-server/config.ts | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/tools/pfe-tools/dev-server/config.ts b/tools/pfe-tools/dev-server/config.ts index 6b19abc97b..4fc1c0b067 100644 --- a/tools/pfe-tools/dev-server/config.ts +++ b/tools/pfe-tools/dev-server/config.ts @@ -1,4 +1,4 @@ -import type { Plugin, Context } from '@web/dev-server-core'; +import type { Plugin, Context, Middleware } from '@web/dev-server-core'; import type { DevServerConfig } from '@web/dev-server'; import { readdir, stat } from 'node:fs/promises'; @@ -85,19 +85,17 @@ async function cacheBusterMiddleware(ctx: Context, next: () => Promise) { } } -function tsRedirectPlugin( +function liveReloadTsChangesMiddleware( config: ReturnType, -): Plugin { - const TYPESCRIPT_SOURCES_RE = new RegExp(`(${config.elementsDir}|pfe-core)/.*\\.js$`); - return { - name: 'pfe-ts-redirect', - serve(context) { - if (!context.path.includes('node_modules') - && TYPESCRIPT_SOURCES_RE.test(context.path)) { - // Rewrite .js to .ts so esbuild plugin can compile it - context.path = context.path.replace(/\.js$/, '.ts'); - } - }, +): Middleware { + const TYPESCRIPT_SOURCES_RE = new RegExp(`(${config.elementsDir}|pfe-core)/.*\\.js`); + return async function(ctx, next) { + await next(); + if (ctx.status === 404 + && !ctx.path.includes('node_modules') + && TYPESCRIPT_SOURCES_RE.test(ctx.path)) { + ctx.redirect(ctx.path.replace('.js', '.ts')); + } }; } @@ -118,13 +116,11 @@ export function pfeDevServerConfig(options?: PfeDevServerConfigOptions): DevServ middleware: [ cors, cacheBusterMiddleware, + liveReloadTsChangesMiddleware(config), ...config?.middleware ?? [], ], plugins: [ - // Rewrite .js paths to .ts before static file serving - tsRedirectPlugin(config), - // Dev server app which loads component demo files pfeDevServerPlugin(config),