From dfefcb7cbdc485e13d57cdc8dd54b1e4f2975177 Mon Sep 17 00:00:00 2001 From: Brandon Pittman Date: Mon, 7 Oct 2024 21:06:38 +0900 Subject: [PATCH 01/28] Fix action redirect searchParam regression (#6927) * Add test routes * Fix action redirect regression * add changeset * fixup --------- Co-authored-by: Wout Mertens --- .changeset/many-turtles-cough.md | 5 +++++ .../src/runtime/src/qwik-city-component.tsx | 9 ++++++--- .../index.tsx | 15 ++++++++++++++ .../index.tsx | 20 +++++++++++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 .changeset/many-turtles-cough.md create mode 100644 starters/apps/qwikcity-test/src/routes/action-redirect-without-search-params-target/index.tsx create mode 100644 starters/apps/qwikcity-test/src/routes/action-redirect-without-search-params/index.tsx diff --git a/.changeset/many-turtles-cough.md b/.changeset/many-turtles-cough.md new file mode 100644 index 00000000000..18c13ce2ac6 --- /dev/null +++ b/.changeset/many-turtles-cough.md @@ -0,0 +1,5 @@ +--- +'@builder.io/qwik-city': patch +--- + +Fix action redirect regression where searchParams were appended diff --git a/packages/qwik-city/src/runtime/src/qwik-city-component.tsx b/packages/qwik-city/src/runtime/src/qwik-city-component.tsx index fc2f975e646..692e55869fa 100644 --- a/packages/qwik-city/src/runtime/src/qwik-city-component.tsx +++ b/packages/qwik-city/src/runtime/src/qwik-city-component.tsx @@ -367,9 +367,13 @@ export const QwikCityProvider = component$((props) => { const [routeName, params, mods, menu] = loadedRoute; const contentModules = mods as ContentModule[]; const pageModule = contentModules[contentModules.length - 1] as PageModule; - if (navigation.dest.search) { + + // Restore search params unless it's a redirect + const isRedirect = navType === 'form' && !isSamePath(trackUrl, prevUrl); + if (navigation.dest.search && !isRedirect) { trackUrl.search = navigation.dest.search; } + // Update route location routeLocation.prevUrl = prevUrl; routeLocation.url = trackUrl; @@ -409,8 +413,7 @@ export const QwikCityProvider = component$((props) => { (navigation.scroll && (!navigation.forceReload || !isSamePath(trackUrl, prevUrl)) && (navType === 'link' || navType === 'popstate')) || - // Action might have responded with a redirect. - (navType === 'form' && !isSamePath(trackUrl, prevUrl)) + isRedirect ) { // Mark next DOM render to scroll. (document as any).__q_scroll_restore__ = () => diff --git a/starters/apps/qwikcity-test/src/routes/action-redirect-without-search-params-target/index.tsx b/starters/apps/qwikcity-test/src/routes/action-redirect-without-search-params-target/index.tsx new file mode 100644 index 00000000000..fa99e00605c --- /dev/null +++ b/starters/apps/qwikcity-test/src/routes/action-redirect-without-search-params-target/index.tsx @@ -0,0 +1,15 @@ +import { useLocation } from "@builder.io/qwik-city"; +import { component$ } from "@builder.io/qwik"; + +export default component$(() => { + const location = useLocation(); + + return ( +
+

+ Should not have searchParams +

+
{JSON.stringify(location.url.searchParams.get("id"))}
+
+ ); +}); diff --git a/starters/apps/qwikcity-test/src/routes/action-redirect-without-search-params/index.tsx b/starters/apps/qwikcity-test/src/routes/action-redirect-without-search-params/index.tsx new file mode 100644 index 00000000000..68f1601ffa2 --- /dev/null +++ b/starters/apps/qwikcity-test/src/routes/action-redirect-without-search-params/index.tsx @@ -0,0 +1,20 @@ +import { routeAction$, Form } from "@builder.io/qwik-city"; +import { component$ } from "@builder.io/qwik"; + +export const useAction = routeAction$((_, context) => { + throw context.redirect( + 302, + "/qwikcity-test/action-redirect-without-search-params-target/", + ); +}); + +export default component$(() => { + const action = useAction(); + + return ( +
+

Should have searchParams

+ +
+ ); +}); From 3c2163ff8591108c4c63540e6353d400598a930b Mon Sep 17 00:00:00 2001 From: Shai Reznik Date: Mon, 7 Oct 2024 16:38:43 +0300 Subject: [PATCH 02/28] fixed cli build "hangs" --- .changeset/thick-dodos-promise.md | 5 + .../qwik/src/cli/utils/run-build-command.ts | 105 ++++++++++-------- 2 files changed, 63 insertions(+), 47 deletions(-) create mode 100644 .changeset/thick-dodos-promise.md diff --git a/.changeset/thick-dodos-promise.md b/.changeset/thick-dodos-promise.md new file mode 100644 index 00000000000..053ae8f368e --- /dev/null +++ b/.changeset/thick-dodos-promise.md @@ -0,0 +1,5 @@ +--- +'@builder.io/qwik': patch +--- + +FIX: cli build command appearing to "hang" on errors diff --git a/packages/qwik/src/cli/utils/run-build-command.ts b/packages/qwik/src/cli/utils/run-build-command.ts index 3ecb7ecb105..8d1ea44a7c8 100644 --- a/packages/qwik/src/cli/utils/run-build-command.ts +++ b/packages/qwik/src/cli/utils/run-build-command.ts @@ -1,7 +1,7 @@ /* eslint-disable no-console */ -import { dim, cyan, bgMagenta, magenta } from 'kleur/colors'; -import type { AppCommand } from './app-command'; import { execaCommand } from 'execa'; +import { bgMagenta, cyan, dim, magenta, red } from 'kleur/colors'; +import type { AppCommand } from './app-command'; import { getPackageManager, pmRunCmd } from './utils'; interface Step { title: string; @@ -90,7 +90,8 @@ export async function runBuildCommand(app: AppCommand) { }); } catch (e) { console.error(script, 'failed'); - process.exit(1); + process.exitCode = 1; + throw e; } } @@ -114,7 +115,8 @@ export async function runBuildCommand(app: AppCommand) { out = out.slice(3); } console.log('\n' + out); - process.exit(1); + process.exitCode = 1; + throw new Error(`Type check failed: ${out}`); }); } @@ -124,8 +126,9 @@ export async function runBuildCommand(app: AppCommand) { stdout: 'inherit', stderr: 'inherit', cwd: app.rootDir, - }).catch(() => { - process.exit(1); + }).catch((error) => { + process.exitCode = 1; + throw new Error(`Client build failed: ${error}`); }); console.log(``); @@ -156,7 +159,8 @@ export async function runBuildCommand(app: AppCommand) { console.log(e.stdout); } console.log(``); - process.exit(1); + process.exitCode = 1; + throw e; }); step2.push(libBuild); } @@ -183,7 +187,8 @@ export async function runBuildCommand(app: AppCommand) { console.log(e.stdout); } console.log(``); - process.exit(1); + process.exitCode = 1; + throw e; }); step2.push(previewBuild); } @@ -210,7 +215,8 @@ export async function runBuildCommand(app: AppCommand) { console.log(e.stdout); } console.log(``); - process.exit(1); + process.exitCode = 1; + throw e; }); step2.push(serverBuild); } @@ -236,7 +242,8 @@ export async function runBuildCommand(app: AppCommand) { console.log(e.stdout); } console.log(``); - process.exit(1); + process.exitCode = 1; + throw e; }); step2.push(staticBuild); } @@ -262,50 +269,53 @@ export async function runBuildCommand(app: AppCommand) { console.log(e.stdout); console.error(e.stderr); console.log(``); - process.exit(1); + process.exitCode = 1; + throw e; }); step2.push(lintBuild); } if (step2.length > 0) { - await Promise.all(step2).then((steps) => { - steps.forEach((step) => { - if (step.stdout) { - console.log(''); - console.log(step.stdout); - } - console.log(`${cyan('✓')} ${step.title}`); - }); - - if (!isPreviewBuild && !buildServerScript && !buildStaticScript && !isLibraryBuild) { - const pmRun = pmRunCmd(); - console.log(``); - console.log(`${bgMagenta(' Missing an integration ')}`); - console.log(``); - console.log(`${magenta('・')} Use ${magenta(pmRun + ' qwik add')} to add an integration`); - console.log(`${magenta('・')} Use ${magenta(pmRun + ' preview')} to preview the build`); - } + await Promise.all(step2) + .then((steps) => { + steps.forEach((step) => { + if (step.stdout) { + console.log(''); + console.log(step.stdout); + } + console.log(`${cyan('✓')} ${step.title}`); + }); - if (isPreviewBuild && buildStaticScript && runSsgScript) { - return execaCommand(buildStaticScript, { - stdout: 'inherit', - stderr: 'inherit', - cwd: app.rootDir, - env: { - FORCE_COLOR: 'true', - }, - }).catch((e) => { + if (!isPreviewBuild && !buildServerScript && !buildStaticScript && !isLibraryBuild) { + const pmRun = pmRunCmd(); console.log(``); - if (e.stderr) { - console.log(e.stderr); - } else { - console.log(e.stdout); - } + console.log(`${bgMagenta(' Missing an integration ')}`); console.log(``); - process.exit(1); - }); - } - }); + console.log(`${magenta('・')} Use ${magenta(pmRun + ' qwik add')} to add an integration`); + console.log(`${magenta('・')} Use ${magenta(pmRun + ' preview')} to preview the build`); + } + + if (isPreviewBuild && buildStaticScript && runSsgScript) { + return execaCommand(buildStaticScript, { + stdout: 'inherit', + stderr: 'inherit', + cwd: app.rootDir, + env: { + FORCE_COLOR: 'true', + }, + }).catch((e) => { + console.log(``); + if (e.stderr) { + console.log(e.stderr); + } else { + console.log(e.stdout); + } + console.log(``); + process.exitCode = 1; + }); + } + }) + .catch((error) => console.log(red(error))); } for (const script of postbuildScripts) { @@ -320,7 +330,8 @@ export async function runBuildCommand(app: AppCommand) { }); } catch (e) { console.error(script, 'failed'); - process.exit(1); + process.exitCode = 1; + throw e; } } From 9d4a6618f85e6c7d3bdb85698fd31718b9dc5b51 Mon Sep 17 00:00:00 2001 From: Wout Mertens Date: Mon, 7 Oct 2024 23:53:46 +0200 Subject: [PATCH 03/28] fix(sync$): serialize "minified" function (#6944) --- .changeset/shaggy-apes-kneel.md | 5 +++++ .changeset/silver-countries-kiss.md | 2 +- .../src/runtime/src/router-outlet-component.tsx | 15 +++++++++------ packages/qwik/src/core/qrl/qrl.public.ts | 1 + packages/qwik/src/core/qrl/qrl.ts | 2 +- 5 files changed, 17 insertions(+), 8 deletions(-) create mode 100644 .changeset/shaggy-apes-kneel.md diff --git a/.changeset/shaggy-apes-kneel.md b/.changeset/shaggy-apes-kneel.md new file mode 100644 index 00000000000..3330fd795e9 --- /dev/null +++ b/.changeset/shaggy-apes-kneel.md @@ -0,0 +1,5 @@ +--- +'@builder.io/qwik': patch +--- + +sync$ QRLs will now be serialized into the HTML in a shorter form diff --git a/.changeset/silver-countries-kiss.md b/.changeset/silver-countries-kiss.md index 4c9e7524e0e..e83044e5f1b 100644 --- a/.changeset/silver-countries-kiss.md +++ b/.changeset/silver-countries-kiss.md @@ -1,5 +1,5 @@ --- -'@builder.io/qwik-city': minor +'@builder.io/qwik-city': patch --- Prevent unexpected caching for q-data.json diff --git a/packages/qwik-city/src/runtime/src/router-outlet-component.tsx b/packages/qwik-city/src/runtime/src/router-outlet-component.tsx index 5d2c789d221..dfb22fe3697 100644 --- a/packages/qwik-city/src/runtime/src/router-outlet-component.tsx +++ b/packages/qwik-city/src/runtime/src/router-outlet-component.tsx @@ -41,13 +41,16 @@ export const RouterOutlet = component$(() => { document:onQCInit$={spaInit} document:onQInit$={sync$(() => { // Minify window and history - ((window: ClientSPAWindow, history: History & { state?: ScrollHistoryState }) => { - if (!window._qcs && history.scrollRestoration === 'manual') { - window._qcs = true; + // Write this as minified as possible, the optimizer does not really minify this code. + ((w: ClientSPAWindow, h: History & { state?: ScrollHistoryState }) => { + if (!w._qcs && h.scrollRestoration === 'manual') { + // true + w._qcs = !0; - const scrollState = history.state?._qCityScroll; - if (scrollState) { - window.scrollTo(scrollState.x, scrollState.y); + // scrollState + const s = h.state?._qCityScroll; + if (s) { + w.scrollTo(s.x, s.y); } document.dispatchEvent(new Event('qcinit')); } diff --git a/packages/qwik/src/core/qrl/qrl.public.ts b/packages/qwik/src/core/qrl/qrl.public.ts index a8024270766..2d3aa303dc8 100644 --- a/packages/qwik/src/core/qrl/qrl.public.ts +++ b/packages/qwik/src/core/qrl/qrl.public.ts @@ -332,5 +332,6 @@ export const _qrlSync = function ( if (serializedFn === undefined) { serializedFn = fn.toString(); } + (fn as any).serialized = serializedFn; return createQRL('', SYNC_QRL, fn, null, null, null, null) as any; }; diff --git a/packages/qwik/src/core/qrl/qrl.ts b/packages/qwik/src/core/qrl/qrl.ts index 5e12afd3804..fbb7b00217b 100644 --- a/packages/qwik/src/core/qrl/qrl.ts +++ b/packages/qwik/src/core/qrl/qrl.ts @@ -199,7 +199,7 @@ export const serializeQRL = (qrl: QRLInternal, opts: QRLSerializeOptions = {}) = if (opts.$containerState$) { const fn = qrl.resolved as Function; const containerState = opts.$containerState$; - const fnStrKey = fn.toString(); + const fnStrKey = ((fn as any).serialized as string) || fn.toString(); let id = containerState.$inlineFns$.get(fnStrKey); if (id === undefined) { id = containerState.$inlineFns$.size; From 30721d0b2702b4fb1e2578abce69800749d13216 Mon Sep 17 00:00:00 2001 From: Wout Mertens Date: Tue, 8 Oct 2024 15:44:41 +0200 Subject: [PATCH 04/28] fix(docs): actually load insights information --- packages/docs/vite.config.mts | 4 +-- packages/qwik-labs/src-vite/insights/index.ts | 29 ++++++++----------- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/packages/docs/vite.config.mts b/packages/docs/vite.config.mts index a66ba855cb0..62a6a72544b 100644 --- a/packages/docs/vite.config.mts +++ b/packages/docs/vite.config.mts @@ -9,7 +9,7 @@ import Inspect from 'vite-plugin-inspect'; import { examplesData, playgroundData, rawSource, tutorialData } from './vite.repl-apps'; import { sourceResolver } from './vite.source-resolver'; -export const PUBLIC_QWIK_INSIGHT_KEY = loadEnv('', '.', 'PUBLIC').PUBLIC_QWIK_INSIGHTS_KEY; +const PUBLIC_QWIK_INSIGHTS_KEY = loadEnv('', '.', 'PUBLIC').PUBLIC_QWIK_INSIGHTS_KEY; const docsDir = new URL(import.meta.url).pathname; // https://github.com/vitejs/vite/issues/15012#issuecomment-1825035992 @@ -168,7 +168,7 @@ export default defineConfig(async () => { sourceResolver(docsDir), qwikReact(), Inspect(), - qwikInsights({ publicApiKey: loadEnv('', docsDir, '').PUBLIC_QWIK_INSIGHTS_KEY }), + qwikInsights({ publicApiKey: PUBLIC_QWIK_INSIGHTS_KEY }), ], build: { sourcemap: true, diff --git a/packages/qwik-labs/src-vite/insights/index.ts b/packages/qwik-labs/src-vite/insights/index.ts index a3425ac0a84..b156017919c 100644 --- a/packages/qwik-labs/src-vite/insights/index.ts +++ b/packages/qwik-labs/src-vite/insights/index.ts @@ -2,11 +2,12 @@ import { type QwikVitePluginOptions } from '@builder.io/qwik/optimizer'; import { existsSync, mkdirSync } from 'fs'; import { readFile, writeFile } from 'fs/promises'; import { join } from 'node:path'; +import { resolve } from 'path'; import { type PluginOption } from 'vite'; -const logWarn = (message?: any) => { +const logWarn = (message?: any, ...rest) => { // eslint-disable-next-line no-console - console.warn('\x1b[33m%s\x1b[0m', `qwikInsight()[WARN]: ${message}`); + console.warn('\x1b[33m%s\x1b[0m', `qwikInsight()[WARN]: ${message}`, ...rest); }; const log = (message?: any) => { @@ -19,11 +20,7 @@ export async function qwikInsights(qwikInsightsOpts: { baseUrl?: string; outDir?: string; }): Promise { - const { - publicApiKey, - baseUrl = 'https://qwik-insights.builder.io', - outDir = 'dist', - } = qwikInsightsOpts; + const { publicApiKey, baseUrl = 'https://insights.qwik.dev', outDir = 'dist' } = qwikInsightsOpts; let isProd = false; const vitePlugin: PluginOption = { name: 'vite-plugin-qwik-insights', @@ -37,20 +34,18 @@ export async function qwikInsights(qwikInsightsOpts: { const response = await fetch(`${baseUrl}/api/v1/${publicApiKey}/bundles/strategy/`); const strategy = await response.json(); Object.assign(qManifest, strategy); + const path = resolve(viteConfig.root || '.', outDir); + const pathJson = join(path, 'q-insights.json'); + mkdirSync(path, { recursive: true }); + log('Fetched latest Qwik Insight data into: ' + pathJson); + await writeFile(pathJson, JSON.stringify(qManifest)); } catch (e) { - logWarn('fail to fetch manifest from Insights DB'); + logWarn('Failed to fetch manifest from Insights DB', e); } - const cwdRelativePath = join(viteConfig.root || '.', outDir); - const cwdRelativePathJson = join(cwdRelativePath, 'q-insights.json'); - if (!existsSync(join(process.cwd(), cwdRelativePath))) { - mkdirSync(join(process.cwd(), cwdRelativePath), { recursive: true }); - } - log('Fetched latest Qwik Insight data into: ' + cwdRelativePathJson); - await writeFile(join(process.cwd(), cwdRelativePathJson), JSON.stringify(qManifest)); } }, closeBundle: async () => { - const path = join(process.cwd(), outDir, 'q-manifest.json'); + const path = resolve(outDir, 'q-manifest.json'); if (isProd && existsSync(path)) { const qManifest = await readFile(path, 'utf-8'); @@ -60,7 +55,7 @@ export async function qwikInsights(qwikInsightsOpts: { body: qManifest, }); } catch (e) { - logWarn('fail to post manifest to Insights DB'); + logWarn('Failed to post manifest to Insights DB', e); } } }, From d937f848c9797db89131b947cf7b3e88ffed29dc Mon Sep 17 00:00:00 2001 From: Wout Mertens Date: Tue, 8 Oct 2024 16:00:28 +0200 Subject: [PATCH 05/28] fix(insights): move default location to root so it doesn't get clobbered by builds --- packages/docs/.gitignore | 1 + packages/qwik-labs/src-vite/insights/index.ts | 2 +- packages/qwik/src/optimizer/src/plugins/vite.ts | 10 +++++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/docs/.gitignore b/packages/docs/.gitignore index 2f759a2e1db..d01d4c6e05a 100644 --- a/packages/docs/.gitignore +++ b/packages/docs/.gitignore @@ -18,6 +18,7 @@ node_modules .vscode .rollup.cache tsconfig.tsbuildinfo +q-insights.json # Logs logs diff --git a/packages/qwik-labs/src-vite/insights/index.ts b/packages/qwik-labs/src-vite/insights/index.ts index b156017919c..ca1cfbfed6c 100644 --- a/packages/qwik-labs/src-vite/insights/index.ts +++ b/packages/qwik-labs/src-vite/insights/index.ts @@ -20,7 +20,7 @@ export async function qwikInsights(qwikInsightsOpts: { baseUrl?: string; outDir?: string; }): Promise { - const { publicApiKey, baseUrl = 'https://insights.qwik.dev', outDir = 'dist' } = qwikInsightsOpts; + const { publicApiKey, baseUrl = 'https://insights.qwik.dev', outDir = '' } = qwikInsightsOpts; let isProd = false; const vitePlugin: PluginOption = { name: 'vite-plugin-qwik-insights', diff --git a/packages/qwik/src/optimizer/src/plugins/vite.ts b/packages/qwik/src/optimizer/src/plugins/vite.ts index 85e759deb22..d5c809b42cd 100644 --- a/packages/qwik/src/optimizer/src/plugins/vite.ts +++ b/packages/qwik/src/optimizer/src/plugins/vite.ts @@ -76,12 +76,12 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { const injections: GlobalInjections[] = []; const qwikPlugin = createPlugin(qwikViteOpts.optimizerOptions); - async function loadQwikInsights(clientOutDir?: string | null): Promise { + async function loadQwikInsights(clientOutDir = ''): Promise { const sys = qwikPlugin.getSys(); const cwdRelativePath = absolutePathAwareJoin( sys.path, rootDir || '.', - clientOutDir ?? 'dist', + clientOutDir, 'q-insights.json' ); const path = absolutePathAwareJoin(sys.path, process.cwd(), cwdRelativePath); @@ -97,7 +97,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { getOptimizer: () => qwikPlugin.getOptimizer(), getOptions: () => qwikPlugin.getOptions(), getManifest: () => manifestInput, - getInsightsManifest: (clientOutDir?: string | null) => loadQwikInsights(clientOutDir), + getInsightsManifest: (clientOutDir = '') => loadQwikInsights(clientOutDir!), getRootDir: () => qwikPlugin.getOptions().rootDir, getClientOutDir: () => clientOutDir, getClientPublicOutDir: () => clientPublicOutDir, @@ -225,7 +225,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { } catch (e) { console.error(e); } - } catch (e) { + } catch { // error reading package.json from Node.js fs, ok to ignore } @@ -429,7 +429,7 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { if (entryStrategy) { qwikViteOpts.entryStrategy = entryStrategy; } - } catch (e) { + } catch { // ok to ignore } } From 96fb940648c955a436aaed23b7c5f6acd0b4234b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=AFeul?= <45822175+maiieul@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:07:54 +0200 Subject: [PATCH 06/28] chore: update modulepreload experiment date (#6941) --- packages/docs/src/entry.ssr.tsx | 4 ++-- packages/docs/src/root.tsx | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/docs/src/entry.ssr.tsx b/packages/docs/src/entry.ssr.tsx index e254ceadc48..e2795f44399 100644 --- a/packages/docs/src/entry.ssr.tsx +++ b/packages/docs/src/entry.ssr.tsx @@ -14,14 +14,14 @@ export default function (opts: RenderToStreamOptions) { lang: 'en', ...opts.containerAttributes, }, - // Core Web Vitals experiment until October 9: Do not remove! Reach out to @maiieul first if you believe you have a good reason to change this. + // Core Web Vitals experiment until October 23: Do not remove! Reach out to @maiieul first if you believe you have a good reason to change this. prefetchStrategy: { implementation: { linkInsert: 'html-append', linkRel: 'modulepreload', }, }, - // Core Web Vitals experiment until October 9: Do not remove! Reach out to @maiieul first if you believe you have a good reason to change this. + // Core Web Vitals experiment until October 23: Do not remove! Reach out to @maiieul first if you believe you have a good reason to change this. qwikPrefetchServiceWorker: { include: false, }, diff --git a/packages/docs/src/root.tsx b/packages/docs/src/root.tsx index 2afe1a26381..4d959c566a1 100644 --- a/packages/docs/src/root.tsx +++ b/packages/docs/src/root.tsx @@ -71,7 +71,7 @@ export default component$(() => { \n```\nBy default, the `prefetchEvent` implementation will be set to `always`.\n\n\n\n\n\n[workerFetchInsert?](#)\n\n\n\n\n\n\n\n'always' \\| 'no-link-support' \\| null\n\n\n\n\n_(Optional)_ `always`: Always include the worker fetch JS runtime.\n\n`no-link-support`: Only include the worker fetch JS runtime when the browser doesn't support `` prefetch/preload/modulepreload.\n\n\n\n", + "content": "```typescript\nexport interface PrefetchImplementation \n```\n\n\n\n\n\n\n\n\n
\n\nProperty\n\n\n\n\nModifiers\n\n\n\n\nType\n\n\n\n\nDescription\n\n\n
\n\n[linkFetchPriority?](#)\n\n\n\n\n\n\n\n'auto' \\| 'low' \\| 'high' \\| null\n\n\n\n\n_(Optional)_ Value of the `` attribute when link is used. Defaults to `null` if links are inserted.\n\n\n
\n\n[linkInsert?](#)\n\n\n\n\n\n\n\n'js-append' \\| 'html-append' \\| null\n\n\n\n\n_(Optional)_ `js-append`: Use JS runtime to create each `` and append to the body.\n\n`html-append`: Render each `` within html, appended at the end of the body.\n\n\n
\n\n[linkRel?](#)\n\n\n\n\n\n\n\n'prefetch' \\| 'preload' \\| 'modulepreload' \\| null\n\n\n\n\n_(Optional)_ Value of the `` attribute when link is used. Defaults to `prefetch` if links are inserted.\n\n\n
\n\n[prefetchEvent?](#)\n\n\n\n\n\n\n\n'always' \\| null\n\n\n\n\n_(Optional)_ Dispatch a `qprefetch` event with detail data containing the bundles that should be prefetched. The event dispatch script will be inlined into the document's HTML so any listeners of this event should already be ready to handle the event.\n\nThis implementation will inject a script similar to:\n\n```\n\n```\nBy default, the `prefetchEvent` implementation will be set to `always`.\n\n\n
\n\n[workerFetchInsert?](#)\n\n\n\n\n\n\n\n'always' \\| 'no-link-support' \\| null\n\n\n\n\n_(Optional)_ `always`: Always include the worker fetch JS runtime.\n\n`no-link-support`: Only include the worker fetch JS runtime when the browser doesn't support `` prefetch/preload/modulepreload.\n\n\n
", "editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/server/types.ts", "mdFile": "qwik.prefetchimplementation.md" }, diff --git a/packages/docs/src/routes/api/qwik-server/index.md b/packages/docs/src/routes/api/qwik-server/index.md index a20bdbca343..819658c38ec 100644 --- a/packages/docs/src/routes/api/qwik-server/index.md +++ b/packages/docs/src/routes/api/qwik-server/index.md @@ -233,6 +233,21 @@ Description +[linkFetchPriority?](#) + + + + + +'auto' \| 'low' \| 'high' \| null + + + +_(Optional)_ Value of the `` attribute when link is used. Defaults to `null` if links are inserted. + + + + [linkInsert?](#) diff --git a/packages/docs/src/routes/docs/(qwik)/advanced/modules-prefetching/index.mdx b/packages/docs/src/routes/docs/(qwik)/advanced/modules-prefetching/index.mdx index 41fa22c0153..5397a75392b 100644 --- a/packages/docs/src/routes/docs/(qwik)/advanced/modules-prefetching/index.mdx +++ b/packages/docs/src/routes/docs/(qwik)/advanced/modules-prefetching/index.mdx @@ -78,6 +78,7 @@ export default function (opts: RenderToStreamOptions) { | `prefetchEvent` | Dispatch a `qprefetch` event with `detail` data containing the urls that should be prefetched. The event dispatch script will be inlined into the document's HTML. By default, the `prefetchEvent` implementation will be set to `always`. | | `linkInsert` | Insert the `` element into the document. When using `html-append`, it will render each `` directly within the html, appended at the end of the body. Using the `js-append` option, it will instead insert some JavaScript, which creates the elements at runtime and appends them at the end of the body. | | `linkRel` | This option is used to define the [`rel` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types) of the `` element. When the `linkInsert` option is used, the default is `prefetch`. Other options include `preload` and `modulepreload`. | +| `linkFetchPriority` | This option is used to define the [`fetchpriority` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#fetchpriority) of the `` element. When the `linkInsert` option is used, the default is `null`. Other options include `low`, `high` and `auto`. | `workerFetchInsert` | Prefetch urls by calling a `fetch()` for each module, with the goal of populating the network cache. | #### Dispatched Prefetch Event diff --git a/packages/qwik/src/server/api.md b/packages/qwik/src/server/api.md index 3de7e517668..4e0a9fbb0a3 100644 --- a/packages/qwik/src/server/api.md +++ b/packages/qwik/src/server/api.md @@ -43,6 +43,7 @@ export type InOrderStreaming = InOrderAuto | InOrderDisabled | InOrderDirect; // @public (undocumented) export interface PrefetchImplementation { + linkFetchPriority?: 'auto' | 'low' | 'high' | null; linkInsert?: 'js-append' | 'html-append' | null; linkRel?: 'prefetch' | 'preload' | 'modulepreload' | null; prefetchEvent?: 'always' | null; diff --git a/packages/qwik/src/server/prefetch-implementation.ts b/packages/qwik/src/server/prefetch-implementation.ts index 1a159f1cdab..ac401c10405 100644 --- a/packages/qwik/src/server/prefetch-implementation.ts +++ b/packages/qwik/src/server/prefetch-implementation.ts @@ -75,11 +75,15 @@ function linkHtmlImplementation( ) { const urls = flattenPrefetchResources(prefetchResources); const rel = prefetchImpl.linkRel || 'prefetch'; + const priority = prefetchImpl.linkFetchPriority; for (const url of urls) { const attributes: Record = {}; attributes['href'] = url; attributes['rel'] = rel; + if (priority) { + attributes['fetchpriority'] = priority; + } if (rel === 'prefetch' || rel === 'preload') { if (url.endsWith('.js')) { attributes['as'] = 'script'; @@ -101,6 +105,7 @@ function linkJsImplementation( nonce?: string ) { const rel = prefetchImpl.linkRel || 'prefetch'; + const priority = prefetchImpl.linkFetchPriority; let s = ``; if (prefetchImpl.workerFetchInsert === 'no-link-support') { @@ -113,6 +118,9 @@ function linkJsImplementation( s += `const l=document.createElement('link');`; s += `l.setAttribute("href",u);`; s += `l.setAttribute("rel","${rel}");`; + if (priority) { + s += `l.setAttribute("fetchpriority","${priority}");`; + } if (prefetchImpl.workerFetchInsert === 'no-link-support') { s += `if(i===0){`; @@ -173,6 +181,7 @@ function normalizePrefetchImplementation( const PrefetchImplementationDefault: Required = { linkInsert: null, linkRel: null, + linkFetchPriority: null, workerFetchInsert: null, prefetchEvent: 'always', }; diff --git a/packages/qwik/src/server/prefetch-strategy.ts b/packages/qwik/src/server/prefetch-strategy.ts index cc6359bb417..3eb15339635 100644 --- a/packages/qwik/src/server/prefetch-strategy.ts +++ b/packages/qwik/src/server/prefetch-strategy.ts @@ -5,6 +5,7 @@ import type { SnapshotResult, } from './types'; import { getBuildBase } from './utils'; +import { qDev } from '../core/util/qdev'; import type { ResolvedManifest } from '@builder.io/qwik/optimizer'; import type { QRLInternal } from '../core/qrl/qrl-class'; @@ -78,7 +79,7 @@ function addBundle( buildBase: string, bundleFileName: string ) { - const url = buildBase + bundleFileName; + const url = qDev ? bundleFileName : buildBase + bundleFileName; let prefetchResource = urls.get(url); if (!prefetchResource) { prefetchResource = { diff --git a/packages/qwik/src/server/types.ts b/packages/qwik/src/server/types.ts index cd8acfd5561..c9158054cb6 100644 --- a/packages/qwik/src/server/types.ts +++ b/packages/qwik/src/server/types.ts @@ -32,6 +32,11 @@ export interface PrefetchImplementation { * are inserted. */ linkRel?: 'prefetch' | 'preload' | 'modulepreload' | null; + /** + * Value of the `` attribute when link is used. Defaults to `null` if + * links are inserted. + */ + linkFetchPriority?: 'auto' | 'low' | 'high' | null; /** * `always`: Always include the worker fetch JS runtime. * diff --git a/starters/dev-server.ts b/starters/dev-server.ts index 1e05e528ede..f1021cbc46f 100644 --- a/starters/dev-server.ts +++ b/starters/dev-server.ts @@ -88,8 +88,11 @@ async function handleApp(req: Request, res: Response, next: NextFunction) { } const resolved = await clientManifest; - - res.set("Content-Type", "text/html"); + if (url.pathname.endsWith(".js")) { + res.set("Content-Type", "text/javascript"); + } else { + res.set("Content-Type", "text/html"); + } if (enableCityServer) { await cityApp(req, res, next, appDir); } else { From 03689b7b042f5cfaa76105dfff52fa1d43ede581 Mon Sep 17 00:00:00 2001 From: Jean-philippe Martel <41765025+Kampouse@users.noreply.github.com> Date: Mon, 14 Oct 2024 19:37:36 -0400 Subject: [PATCH 19/28] docs: Brand page (#6798) * fix a tsc issue * initial version of the brand page * remove the local change for the repl * second iteration * updated press page with the correction * another iteration --------- Co-authored-by: jean-philippe Co-authored-by: PatrickJS --- .../docs/src/components/footer/footer.tsx | 1 + packages/docs/src/routes/press/index.tsx | 196 ++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 packages/docs/src/routes/press/index.tsx diff --git a/packages/docs/src/components/footer/footer.tsx b/packages/docs/src/components/footer/footer.tsx index 056af96a596..e74e9c2b86d 100644 --- a/packages/docs/src/components/footer/footer.tsx +++ b/packages/docs/src/components/footer/footer.tsx @@ -22,6 +22,7 @@ const linkColumns = [ { title: 'Tutorial', href: `${baseUrl}/ecosystem/#courses` }, { title: 'Presentations', href: `${baseUrl}/ecosystem/#presentations` }, { title: 'Community', href: `${baseUrl}/ecosystem/#community` }, + { title: 'Press', href: `${baseUrl}/press` }, ], ]; diff --git a/packages/docs/src/routes/press/index.tsx b/packages/docs/src/routes/press/index.tsx new file mode 100644 index 00000000000..8f8b3ff3a09 --- /dev/null +++ b/packages/docs/src/routes/press/index.tsx @@ -0,0 +1,196 @@ +import { component$, $, useSignal } from '@builder.io/qwik'; +import QwikLogo from '/public/logos/qwik.png?jsx'; +import QwikLogouwu from '/public/logos/qwik-uwu.webp?jsx'; +import QwikSocial from '/public/logos/social-card.png?jsx'; +import QwikSocial2 from '/public/logos/social-card.jpg?jsx'; +import { Header } from '~/components/header/header'; +import { Footer } from '~/components/footer/footer'; +import { Slot } from '@builder.io/qwik'; +const DownloadButton = component$((props: { href: string | undefined }) => { + return ( + +

Download

{' '} +
+ ); +}); + +export default component$(() => { + const activeColor = useSignal(''); + + const color = { + qwikBlue: '#009dfd', + qwikDarkBlue: '#006ce9', + qwikLightBlue: '#daf0ff', + qwikPurple: '#ac7ef4', + qwikDarkPurple: '#6000ff', + qwikDarkPurpleBg: '#151934', + } as const; + + const copyToClipboard = $(async (text: string) => { + try { + if (!navigator.clipboard) { + activeColor.value = text; + return; + } + await navigator.clipboard.writeText(text); + activeColor.value = text; + const rs = setTimeout(() => { + const old = activeColor.value; + if (old === text) { + activeColor.value = ''; + } + }, 1500); + return () => clearTimeout(rs); + } catch (err) { + console.error('Failed to copy: ', err); + } + }); + + const logos = [ + { + title: 'Qwik Logo (png)', + alt: 'Qwik Logo in PNG format', + downloadHref: '/logos/qwik.png', + Logo: QwikLogo, + }, + { + title: 'Qwik Logo (svg)', + alt: 'Qwik Logo in SVG format', + downloadHref: '/logos/qwik.svg', + Logo: 'img', + src: '/logos/qwik.svg', + }, + { + title: 'Qwik Logo (uwu)', + alt: 'Qwik Logo in UWU format', + downloadHref: '/logos/qwik-uwu.webp', + Logo: QwikLogouwu, + className: 'h-auto w-auto object-contain', + }, + { + title: 'Qwik social card Light', + alt: 'Qwik Social Card in Light theme', + downloadHref: '/logos/social-card.png', + Logo: QwikSocial, + }, + { + title: 'Qwik social card Dark', + alt: 'Qwik Social Card in Dark theme', + downloadHref: '/logos/social-card.jpg', + Logo: QwikSocial2, + }, + ]; + const downloadAllAssets = $(() => { + const links = [ + '/logos/qwik.png', + '/logos/qwik.svg', + '/logos/qwik-uwu.webp', + '/logos/social-card.png', + '/logos/social-card.jpg', + ]; + + links.forEach((link) => { + const anchor = document.createElement('a'); + anchor.href = link; + anchor.download = link.split('/').pop() as string; + document.body.appendChild(anchor); + anchor.click(); + document.body.removeChild(anchor); + }); + }); + + const Logo = component$((props: { title: string; alt: string; downloadHref: string }) => { + return ( +
+

{props.title}

+
+ +
+
+ +
+
+ ); + }); + + const ColorButton = component$( + (props: { color: string; name: string; hexCode: string; text: string | undefined }) => { + return ( + + ); + } + ); + + const qwikColors = [ + { color: 'var(--qwik-blue)', name: 'Qwik Blue', hexCode: color.qwikBlue }, + { color: 'var(--qwik-dark-blue)', name: 'Qwik Dark Blue', hexCode: color.qwikDarkBlue }, + { color: 'var(--qwik-light-blue)', name: 'Qwik Light Blue', hexCode: color.qwikLightBlue }, + { color: 'var(--qwik-purple)', name: 'Qwik Purple', hexCode: color.qwikPurple }, + { color: 'var(--qwik-dark-purple)', name: 'Qwik Dark Purple', hexCode: color.qwikDarkPurple }, + { + color: 'var(--qwik-dark-purple-bg)', + name: 'Qwik Dark Purple Bg', + text: 'var(--qwik-light-blue)', + hexCode: color.qwikDarkPurpleBg, + }, + ]; + + return ( +
+
+
+ {logos.map((item) => ( + + {item.Logo === 'img' ? ( + {item.alt} + ) : ( + + )} + + ))} +
+
+ {qwikColors.map((colorItem) => ( + + ))} +
+
+
+ +
+
+ ); +}); From 80f75acc16f5d7e7389118d70c02b8d05d468716 Mon Sep 17 00:00:00 2001 From: Wout Mertens Date: Tue, 15 Oct 2024 12:11:54 +0200 Subject: [PATCH 20/28] fix(qwik+city): make vite a peer dependency this prevents duplicate vite versions --- .changeset/ninety-planets-search.md | 6 ++++++ packages/qwik-city/package.json | 4 +++- packages/qwik/package.json | 11 +++++++++-- pnpm-lock.yaml | 14 ++++---------- 4 files changed, 22 insertions(+), 13 deletions(-) create mode 100644 .changeset/ninety-planets-search.md diff --git a/.changeset/ninety-planets-search.md b/.changeset/ninety-planets-search.md new file mode 100644 index 00000000000..77a35dd0e1a --- /dev/null +++ b/.changeset/ninety-planets-search.md @@ -0,0 +1,6 @@ +--- +'@builder.io/qwik-city': patch +'@builder.io/qwik': patch +--- + +FIX: `vite` is now a peer dependency of `qwik` and `qwik-city`, so that there can be no duplicate imports. This should not have consequences, since all apps also directly depend on `vite`. diff --git a/packages/qwik-city/package.json b/packages/qwik-city/package.json index 2c487321dde..c176ca6d5bf 100644 --- a/packages/qwik-city/package.json +++ b/packages/qwik-city/package.json @@ -11,7 +11,6 @@ "undici": "*", "valibot": ">=0.36.0 <2", "vfile": "6.0.1", - "vite": "^5", "vite-imagetools": "^7", "zod": "3.22.4" }, @@ -174,6 +173,9 @@ "homepage": "https://qwik.dev/", "license": "MIT", "main": "./lib/index.qwik.mjs", + "peerDependencies": { + "vite": "^5" + }, "publishConfig": { "access": "public" }, diff --git a/packages/qwik/package.json b/packages/qwik/package.json index f913a5b3139..5df5d129eb6 100644 --- a/packages/qwik/package.json +++ b/packages/qwik/package.json @@ -25,8 +25,7 @@ } ], "dependencies": { - "csstype": "^3.1", - "vite": "^5" + "csstype": "^3.1" }, "devDependencies": { "@builder.io/qwik": "workspace:^", @@ -156,6 +155,14 @@ ], "license": "MIT", "main": "./dist/core.mjs", + "peerDependencies": { + "vite": "^5" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + }, "repository": { "type": "git", "url": "https://github.com/QwikDev/qwik.git", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cf3e9732ad4..fe46a781c5c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -558,9 +558,6 @@ importers: csstype: specifier: ^3.1 version: 3.1.3 - vite: - specifier: ^5 - version: 5.3.5(@types/node@20.14.11)(terser@5.31.3) devDependencies: '@builder.io/qwik': specifier: workspace:^ @@ -613,13 +610,10 @@ importers: version: 6.6.2 valibot: specifier: '>=0.36.0 <2' - version: 0.39.0(typescript@5.4.5) + version: 0.42.1(typescript@5.4.5) vfile: specifier: 6.0.1 version: 6.0.1 - vite: - specifier: ^5 - version: 5.3.5(@types/node@20.14.11)(terser@5.31.3) vite-imagetools: specifier: ^7 version: 7.0.4(rollup@4.19.0) @@ -9358,8 +9352,8 @@ packages: valibot@0.33.3: resolution: {integrity: sha512-/fuY1DlX8uiQ7aphlzrrI2DbG0YJk84JMgvz2qKpUIdXRNsS53varfo4voPjSrjUr5BSV2K0miSEJUOlA5fQFg==} - valibot@0.39.0: - resolution: {integrity: sha512-d+vE8SDRNy9zKg6No5MHz2tdz8H6CW8X3OdqYdmlhnoqQmEoM6Hu0hJUrZv3tPSVrzZkIIMCtdCQtMzcM6NCWw==} + valibot@0.42.1: + resolution: {integrity: sha512-3keXV29Ar5b//Hqi4MbSdV7lfVp6zuYLZuA9V1PvQUsXqogr+u5lvLPLk3A4f74VUXDnf/JfWMN6sB+koJ/FFw==} peerDependencies: typescript: 5.4.5 peerDependenciesMeta: @@ -19446,7 +19440,7 @@ snapshots: valibot@0.33.3: {} - valibot@0.39.0(typescript@5.4.5): + valibot@0.42.1(typescript@5.4.5): optionalDependencies: typescript: 5.4.5 From 1d13508cd0a0e81498909c9b1cd9a39a212cb407 Mon Sep 17 00:00:00 2001 From: Wout Mertens Date: Tue, 15 Oct 2024 12:16:52 +0200 Subject: [PATCH 21/28] fix(repl): don't cache stale builds --- packages/docs/src/repl/repl-console.tsx | 2 +- .../docs/src/repl/repl-output-modules.tsx | 1 + packages/docs/src/repl/repl-output-panel.tsx | 8 +++-- .../docs/src/repl/repl-output-symbols.tsx | 1 + packages/docs/src/repl/repl-output-update.ts | 7 ++++- .../docs/src/repl/worker/app-bundle-client.ts | 5 +--- packages/docs/src/repl/worker/repl-plugins.ts | 29 +++++-------------- 7 files changed, 23 insertions(+), 30 deletions(-) diff --git a/packages/docs/src/repl/repl-console.tsx b/packages/docs/src/repl/repl-console.tsx index a733cf791b9..a61d5e44ac4 100644 --- a/packages/docs/src/repl/repl-console.tsx +++ b/packages/docs/src/repl/repl-console.tsx @@ -7,7 +7,7 @@ export interface ReplConsoleProps { export const ReplConsole = component$(({ store }: ReplConsoleProps) => { return (
- {store.events.map((ev) => ( + {store.events.filter(Boolean).map((ev) => ( ))}
diff --git a/packages/docs/src/repl/repl-output-modules.tsx b/packages/docs/src/repl/repl-output-modules.tsx index 7c1468358fc..4cdf156fba0 100644 --- a/packages/docs/src/repl/repl-output-modules.tsx +++ b/packages/docs/src/repl/repl-output-modules.tsx @@ -26,6 +26,7 @@ export const ReplOutputModules = component$(({ outputs, headerText }: ReplOutput class={{ 'in-view': selectedPath.value === o.path }} preventdefault:click key={o.path} + title={o.path} > {o.path} diff --git a/packages/docs/src/repl/repl-output-panel.tsx b/packages/docs/src/repl/repl-output-panel.tsx index 06385eb677f..5c2ba35c156 100644 --- a/packages/docs/src/repl/repl-output-panel.tsx +++ b/packages/docs/src/repl/repl-output-panel.tsx @@ -1,4 +1,4 @@ -import { component$ } from '@builder.io/qwik'; +import { component$, useComputed$ } from '@builder.io/qwik'; import { CodeBlock } from '../components/code-block/code-block'; import { ReplOutputModules } from './repl-output-modules'; import { ReplOutputSymbols } from './repl-output-symbols'; @@ -8,6 +8,10 @@ import type { ReplAppInput, ReplStore } from './types'; export const ReplOutputPanel = component$(({ input, store }: ReplOutputPanelProps) => { const diagnosticsLen = store.diagnostics.length + store.monacoDiagnostics.length; + const clientBundlesNoCore = useComputed$(() => + // Qwik Core is not interesting and is large, slowing down the UI + store.clientBundles.filter((b) => !b.path.endsWith('qwikCore.js')) + ); return (
@@ -111,7 +115,7 @@ export const ReplOutputPanel = component$(({ input, store }: ReplOutputPanelProp ) : null} {store.selectedOutputPanel === 'clientBundles' ? ( - + ) : null} {store.selectedOutputPanel === 'serverModules' ? ( diff --git a/packages/docs/src/repl/repl-output-symbols.tsx b/packages/docs/src/repl/repl-output-symbols.tsx index 0457c21a2a7..47846d85e6e 100644 --- a/packages/docs/src/repl/repl-output-symbols.tsx +++ b/packages/docs/src/repl/repl-output-symbols.tsx @@ -27,6 +27,7 @@ export const ReplOutputSymbols = component$(({ outputs }: ReplOutputSymbolsProps }} class={{ 'in-view': selectedPath.value === o.path }} preventdefault:click + title={o.segment?.canonicalFilename} > {o.segment?.canonicalFilename} diff --git a/packages/docs/src/repl/repl-output-update.ts b/packages/docs/src/repl/repl-output-update.ts index 4cc4f38039c..1fe666a0dc6 100644 --- a/packages/docs/src/repl/repl-output-update.ts +++ b/packages/docs/src/repl/repl-output-update.ts @@ -24,7 +24,12 @@ export const updateReplOutput = async (store: ReplStore, result: ReplResult) => deepUpdate(store.transformedModules, result.transformedModules); deepUpdate(store.clientBundles, result.clientBundles); deepUpdate(store.ssrModules, result.ssrModules); - deepUpdate(store.events, result.events); + if ( + result.events.length !== store.events.length || + result.events.some((ev, i) => ev?.start !== store.events[i]?.start) + ) { + store.events = result.events; + } if (store.selectedOutputPanel === 'diagnostics' && store.monacoDiagnostics.length === 0) { store.selectedOutputPanel = 'app'; diff --git a/packages/docs/src/repl/worker/app-bundle-client.ts b/packages/docs/src/repl/worker/app-bundle-client.ts index 7c8cbf4befd..6bc1dcbd5a1 100644 --- a/packages/docs/src/repl/worker/app-bundle-client.ts +++ b/packages/docs/src/repl/worker/app-bundle-client.ts @@ -36,7 +36,6 @@ export const appBundleClient = async ( const rollupInputOpts: InputOptions = { input: entry.path, - cache: self.rollupCache, plugins: [ replCss(options), self.qwikOptimizer?.qwikRollup(qwikRollupClientOpts), @@ -71,8 +70,6 @@ export const appBundleClient = async ( const bundle = await self.rollup?.rollup(rollupInputOpts); if (bundle) { - self.rollupCache = bundle.cache; - const generated = await bundle.generate({ sourcemap: false, }); @@ -96,7 +93,7 @@ export const appBundleClient = async ( }) ); - // clear out old cache + // clear out old results cache // no need to wait cache.keys().then((keys) => { if (keys.length > 500) { diff --git a/packages/docs/src/repl/worker/repl-plugins.ts b/packages/docs/src/repl/worker/repl-plugins.ts index a4e8a8fa9f6..2e9cd574f9a 100644 --- a/packages/docs/src/repl/worker/repl-plugins.ts +++ b/packages/docs/src/repl/worker/repl-plugins.ts @@ -15,6 +15,7 @@ export const replResolver = (options: ReplInputOptions, buildMode: 'client' | 's name: 'repl-resolver', resolveId(id, importer) { + // Entry point if (!importer) { return id; } @@ -25,12 +26,10 @@ export const replResolver = (options: ReplInputOptions, buildMode: 'client' | 's ) { return '\0qwikCore'; } - if (id === '@builder.io/qwik/build') { - return '\0qwikBuild'; - } if (id === '@builder.io/qwik/server') { return '\0qwikServer'; } + // Simple relative file resolution if (id.startsWith('./')) { const extensions = ['', '.tsx', '.ts']; id = id.slice(1); @@ -41,10 +40,6 @@ export const replResolver = (options: ReplInputOptions, buildMode: 'client' | 's } } } - return { - id, - external: true, - }; }, async load(id) { @@ -59,20 +54,6 @@ export const replResolver = (options: ReplInputOptions, buildMode: 'client' | 's if (id === '\0qwikServer') { return getRuntimeBundle('qwikServer'); } - if (id === '\0qwikBuild') { - return ` - export const isServer = true; - export const isBrowser = false; - export const isDev = false; - `; - } - } - if (id === '\0qwikBuild') { - return ` - export const isServer = false; - export const isBrowser = true; - export const isDev = false; - `; } if (id === '\0qwikCore') { if (options.buildMode === 'production') { @@ -88,7 +69,11 @@ export const replResolver = (options: ReplInputOptions, buildMode: 'client' | 's } throw new Error(`Unable to load Qwik core`); } - return null; + + // We're the fallback, we know all the files + if (/\.[jt]sx?$/.test(id)) { + throw new Error(`load: unknown module ${id}`); + } }, }; }; From bf1358ee4a821265ce4954d3dd4148a0b72949f2 Mon Sep 17 00:00:00 2001 From: Wout Mertens Date: Tue, 15 Oct 2024 12:17:23 +0200 Subject: [PATCH 22/28] fix(qrl): don't cache import failures this is especially problematic in dev --- packages/qwik/src/core/qrl/qrl-class.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/qwik/src/core/qrl/qrl-class.ts b/packages/qwik/src/core/qrl/qrl-class.ts index 870cfa12a70..228226dd8d8 100644 --- a/packages/qwik/src/core/qrl/qrl-class.ts +++ b/packages/qwik/src/core/qrl/qrl-class.ts @@ -12,7 +12,7 @@ import { type InvokeTuple, } from '../use/use-core'; import { getQFuncs, QInstance } from '../util/markers'; -import { maybeThen } from '../util/promises'; +import { isPromise, maybeThen } from '../util/promises'; import { qDev, qSerialize, qTest, seal } from '../util/qdev'; import { isArray, isFunction, type ValueOrPromise } from '../util/types'; import type { QRLDev } from './qrl'; @@ -106,7 +106,6 @@ export const createQRL = ( if (context.$event$ === undefined) { context.$event$ = this as Event; } - // const result = invoke.call(this, context, f, ...(args as Parameters)); try { return fn.apply(this, args); } finally { @@ -147,7 +146,17 @@ export const createQRL = ( const imported = getPlatform().importSymbol(_containerEl, chunk, symbol); symbolRef = maybeThen(imported, (ref) => (qrl.resolved = symbolRef = wrapFn(ref))); } - (symbolRef as Promise).finally(() => emitUsedSymbol(symbol, ctx?.$element$, start)); + if (typeof symbolRef === 'object' && isPromise(symbolRef)) { + symbolRef.then( + () => emitUsedSymbol(symbol, ctx?.$element$, start), + (err) => { + console.error(`qrl ${symbol} failed to load`, err); + // We shouldn't cache rejections, we can try again later + symbolRef = null; + throw err; + } + ); + } return symbolRef; }; From 8615302729faa3018c74c60c4212535e38d01e55 Mon Sep 17 00:00:00 2001 From: Wout Mertens Date: Tue, 15 Oct 2024 17:01:05 +0200 Subject: [PATCH 23/28] refactor(qwikVite): simplify dev handling - more robust dev server URL handling in resolveId - remove ?_qrl_parent query and rely only on path - remove foundQrls export, instead only keep track of generated segments' parents in parentIds - enforce externals while building libraries, this is suddenly needed because of these changes - better hot update invalidation - more robust getSymbolHash --- .../qwik/src/optimizer/src/plugins/plugin.ts | 356 ++++++++---------- .../src/optimizer/src/plugins/plugin.unit.ts | 74 +++- .../optimizer/src/plugins/vite-dev-server.ts | 33 +- .../qwik/src/optimizer/src/plugins/vite.ts | 8 + 4 files changed, 251 insertions(+), 220 deletions(-) diff --git a/packages/qwik/src/optimizer/src/plugins/plugin.ts b/packages/qwik/src/optimizer/src/plugins/plugin.ts index 9f4bda68335..5a89109b640 100644 --- a/packages/qwik/src/optimizer/src/plugins/plugin.ts +++ b/packages/qwik/src/optimizer/src/plugins/plugin.ts @@ -18,7 +18,7 @@ import type { TransformOutput, } from '../types'; import { createLinter, type QwikLinter } from './eslint-plugin'; -import type { LoadResult, OutputBundle, TransformResult } from 'rollup'; +import type { LoadResult, OutputBundle, ResolveIdResult, TransformResult } from 'rollup'; import { isWin } from './vite-utils'; const REG_CTX_NAME = ['server']; @@ -84,7 +84,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { const serverResults = new Map(); const serverTransformedOutputs = new Map(); - const foundQrls = new Map(); + const parentIds = new Map(); let internalOptimizer: Optimizer | null = null; let linter: QwikLinter | undefined = undefined; @@ -369,13 +369,14 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { } }; - const buildStart = async (ctx: Rollup.PluginContext) => { - debug(`buildStart()`, opts.buildMode, opts.scope, opts.target); - const optimizer = getOptimizer(); + let optimizer: Optimizer; + const buildStart = async (_ctx: Rollup.PluginContext) => { + debug(`buildStart()`, opts.buildMode, opts.scope, opts.target, opts.rootDir, opts.srcDir); + optimizer = getOptimizer(); if (optimizer.sys.env === 'node' && opts.target === 'ssr' && opts.lint) { try { linter = await createLinter(optimizer.sys, opts.rootDir, opts.tsconfigFileNames); - } catch (err) { + } catch { // Nothing } } @@ -391,7 +392,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { }; return relInput; }); - debug(`buildStart() opts.srcInputs (${opts.srcInputs.length})`); + debug(`buildStart() opts.srcInputs (${opts.srcInputs.length} files)`); } debug(`transformedOutputs.clear()`); @@ -403,159 +404,144 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { return devServer ? !!viteOpts?.ssr : opts.target === 'ssr' || opts.target === 'test'; }; - const getParentId = (id: string, isServer: boolean) => { - const transformedOutputs = isServer ? serverTransformedOutputs : clientTransformedOutputs; - const segment = transformedOutputs.get(id); - if (segment) { - return segment[1]; - } - const hash = getSymbolHash(id); - return foundQrls.get(hash); - }; - let resolveIdCount = 0; - /** This resolves special names and QRL segments/entries. All the rest falls through */ - const resolveId = async ( + /** + * This resolves virtual names and QRL segments/entries. All the rest falls through. We must + * always return a value for QRL segments because they don't exist on disk. + */ + const resolveId = ( ctx: Rollup.PluginContext, id: string, importerId: string | undefined, resolveOpts?: Parameters>[2] ) => { - const count = resolveIdCount++; - const isServer = getIsServer(resolveOpts); - debug(`resolveId(${count})`, 'Start', id, { - from: importerId, - for: isServer ? 'server' : 'client', - }); if (id.startsWith('\0')) { return; } + const count = resolveIdCount++; + const isServer = getIsServer(resolveOpts); + debug(`resolveId(${count})`, `begin ${id} | ${isServer ? 'server' : 'client'} | ${importerId}`); + + /** + * During development, the QRL filenames will be of the form `${parentId}_${name}_${hash}.js`, + * and we might get requests for QRLs from the client before the parent was built. + * + * Furthermore, the client requests come in via HTTP and they are encoded in a lossy way. + * + * So, first we need to recover the real requested id, then we need to make it an absolute path, + * and then we can start matching. + */ + const parsedImporterId = importerId && parseId(importerId); + importerId = parsedImporterId && normalizePath(parsedImporterId.pathId); + const path = getPath(); + const importerDir = parsedImporterId && path.dirname(parsedImporterId.pathId); + + /** + * A request possibly from the browser. It could be our own QRLs requests, which we uri encode, + * or an import generated by vite. So we have to be careful. + */ + if (devServer && id.startsWith('/') && importerId?.endsWith('.html')) { + const maybeQrl = decodeURIComponent(id); + // We encode absolute paths like this, due to e.g. pnpm linking + if (maybeQrl.startsWith('/@fs/')) { + id = maybeQrl.slice(5); + } else { + /** + * This path could still be absolute, when encoded by Vite. If the first path segment is the + * same as that of the importer dir, we assume it's absolute. + */ + if (!maybeQrl.startsWith(importerDir!.slice(0, importerDir!.indexOf('/', 1)))) { + id = path.join(importerDir!, maybeQrl); + } + } + // Now we hopefully removed the influence of the http encoding + } - if (opts.target === 'lib' && id.startsWith(QWIK_CORE_ID)) { - // For library code, we must retain the qwik imports as-is. They all start with /qwik. - return { - external: true, - id, - }; + // Relative paths must be resolved vs the importer + if (id.startsWith('.') && importerDir) { + id = path.resolve(importerDir, id); } - if (opts.resolveQwikBuild && id.endsWith(QWIK_BUILD_ID)) { - debug(`resolveId(${count})`, 'Resolved', QWIK_BUILD_ID); - return { - id: normalizePath(getPath().resolve(opts.rootDir, QWIK_BUILD_ID)), + // Split query, remove windows path encoding etc + const parsedId = parseId(id); + const pathId = normalizePath(parsedId.pathId); + + let result: ResolveIdResult; + + // During regular builds, we'll encounter parents before QRLs, so this will match + if (parentIds.get(pathId)) { + debug(`resolveId(${count}) Resolved already known ${pathId}`); + result = { + id: pathId + parsedId.query, moduleSideEffects: false, }; - } - - if (id.endsWith(QWIK_CLIENT_MANIFEST_ID)) { - debug(`resolveId(${count})`, 'Resolved', QWIK_CLIENT_MANIFEST_ID); - if (opts.target === 'lib') { - return { - id: id, - external: true, + } else if ( + // We test with endsWith because the dev server might add a / + pathId.endsWith(QWIK_BUILD_ID) + ) { + /** + * Now we're in the case where we have a QRL segment that hasn't been transformed yet or one + * of the virtual modules. + */ + if (opts.resolveQwikBuild) { + debug(`resolveId(${count})`, 'Resolved', QWIK_BUILD_ID); + result = { + // We use / because \0 gives errors + id: `/${QWIK_BUILD_ID}`, moduleSideEffects: false, }; } - - const firstInput = opts.input && Object.values(opts.input)[0]; - return { - id: normalizePath(getPath().resolve(firstInput, QWIK_CLIENT_MANIFEST_ID)), + } else if (pathId.endsWith(QWIK_CLIENT_MANIFEST_ID)) { + debug(`resolveId(${count})`, 'Resolved', QWIK_CLIENT_MANIFEST_ID); + result = { + id: `/${QWIK_CLIENT_MANIFEST_ID}`, moduleSideEffects: false, }; - } - const optimizer = getOptimizer(); - const path = getPath(); - - // Requests originating from another file, or the browser - if (importerId) { - const looksLikePath = id.startsWith('.') || id.startsWith('/'); - if (!looksLikePath) { - // Rollup can ask us to resolve imports from QRL segments - // It seems like importers need to exist on disk for this to work automatically, - // so for segments we resolve via the parent instead - debug(`resolveId(${count})`, 'falling back to default resolver'); - const parentId = getParentId(importerId, isServer); - if (parentId) { - return ctx.resolve(id, parentId, { skipSelf: true }); - } - return; - } - importerId = normalizePath(importerId); - const parsedImporterId = parseId(importerId); - const dir = path.dirname(parsedImporterId.pathId); - const outputs = isServer ? serverTransformedOutputs : clientTransformedOutputs; - if ( - // vite dev mode - devServer && - // client code - !isServer && - // browser requests - importerId.endsWith('.html') && - // looks like a url pathname - id.startsWith('/') && - // not a known output - !outputs.has(id) - ) { - // This is a request from a dev-mode browser - // we uri-encode chunk paths in dev mode, and other imported files don't have % in their paths (hopefully) - // These will be individual source files and their QRL segments - id = decodeURIComponent(id); - // Support absolute paths for qrl segments, due to e.g. pnpm linking - if (id.startsWith('/@fs/')) { - // remove `/@fs/` prefix for Windows - // remove `/@fs` prefix for Unix - id = id.slice(isWin(optimizer.sys.os) ? 5 : 4); - } else { - // Now paths could be either relative or absolute, we're not sure. - // If the first path segment is the same as that of the importer dir, we assume it's absolute - if (!id.startsWith(dir.slice(0, dir.indexOf('/', 1)))) { - id = path.join(dir, id); + } else { + /** + * If this looks like a dev qrl filename, it doesn't matter who imports, we have the parentId + * embedded. + */ + const match = /^(.*\.[mc]?[jt]sx?)_([^/]+)\.js($|\?)/.exec(pathId); + if (match) { + const [, parentId, name] = match; + return ctx.resolve(parentId, importerId, { skipSelf: true }).then((resolved) => { + if (resolved) { + debug(`resolveId(${count})`, `resolved to QRL ${name} of ${parentId}`); + // Save for quick lookup + parentIds.set(pathId, resolved.id); + return { + id: pathId + parsedId.query, + // QRL segments can't have side effects. Probably never useful, but it's here for consistency + moduleSideEffects: false, + }; + } else { + debug(`resolveId(${count})`, `${parentId} does not exist`); } - } - id = normalizePath(id); - // Check for parent passed via QRL - const match = /^([^?]*)\?_qrl_parent=(.*)/.exec(id); - if (match) { - id = match[1]; - // The parent is in the same directory as the requested segment - const parentId = id.slice(0, id.lastIndexOf('/') + 1) + match[2]; - const hash = getSymbolHash(id); - // Register the parent in case we don't have it (restart etc) - foundQrls.set(hash, parentId); - } - } - const parsedId = parseId(id); - let importeePathId = normalizePath(parsedId.pathId); - const ext = path.extname(importeePathId).toLowerCase(); - if (ext in RESOLVE_EXTS) { - // resolve relative paths - importeePathId = normalizePath(path.resolve(dir, importeePathId)); - const parentId = getParentId(importeePathId, isServer); - if (parentId) { - debug(`resolveId(${count}) Resolved ${importeePathId} from transformedOutputs`); - return { - id: importeePathId + parsedId.query, - }; + }); + } else if (importerId) { + /** + * When we get here it's neither a virtual module nor a QRL segment. However, Rollup can ask + * us to resolve imports from QRL segments. It seems like importers need to exist on disk + * for this to work automatically, so for segments we resolve via the parent instead. + * + * Note that when a this happens, the segment was already resolved and transformed, so we + * know about it. + */ + const importerParentId = parentIds.get(importerId); + if (importerParentId) { + debug(`resolveId(${count})`, `resolving via ${importerParentId}`); + // This returns a promise that we can't await because of deadlocking + return ctx.resolve(id, importerParentId, { skipSelf: true }); } } - } else if (path.isAbsolute(id)) { - const parsedId = parseId(id); - const importeePathId = normalizePath(parsedId.pathId); - const ext = path.extname(importeePathId).toLowerCase(); - if (ext in RESOLVE_EXTS && getParentId(importeePathId, isServer)) { - debug( - `resolveId(${count}) Resolved ${importeePathId} from transformedOutputs (no importer)` - ); - return { - id: importeePathId + parsedId.query, - }; - } } - // We don't (yet) know this id - debug(`resolveId(${count})`, 'Not resolved', id, importerId); - return null; + + debug(`resolveId(${count}) end`, (result as any)?.id || result); + return result; }; + let loadCount = 0; const load = async ( ctx: Rollup.PluginContext, id: string, @@ -564,62 +550,58 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { if (id.startsWith('\0') || id.startsWith('/@fs/')) { return; } + const count = loadCount++; const isServer = getIsServer(loadOpts); - if (opts.resolveQwikBuild && id.endsWith(QWIK_BUILD_ID)) { - debug(`load()`, QWIK_BUILD_ID, opts.buildMode); + + // Virtual modules + if (opts.resolveQwikBuild && id === `/${QWIK_BUILD_ID}`) { + debug(`load(${count})`, QWIK_BUILD_ID, opts.buildMode); return { moduleSideEffects: false, code: getQwikBuildModule(isServer, opts.target), }; } - - if (id.endsWith(QWIK_CLIENT_MANIFEST_ID)) { - debug(`load()`, QWIK_CLIENT_MANIFEST_ID, opts.buildMode); + if (id === `/${QWIK_CLIENT_MANIFEST_ID}`) { + debug(`load(${count})`, QWIK_CLIENT_MANIFEST_ID, opts.buildMode); return { moduleSideEffects: false, code: await getQwikServerManifestModule(isServer), }; } + + // QRL segments const parsedId = parseId(id); - const path = getPath(); id = normalizePath(parsedId.pathId); - const outputs = isServer ? serverTransformedOutputs : clientTransformedOutputs; if (devServer && !outputs.has(id)) { // in dev mode, it could be that the id is a QRL segment that wasn't transformed yet - const parentId = getParentId(id, isServer); + const parentId = parentIds.get(id); if (parentId) { // building here via ctx.load doesn't seem to work (no transform), instead we use the devserver directly - debug(`load()`, 'transforming QRL parent', parentId); + debug(`load(${count})`, 'transforming QRL parent', parentId); // We need to encode it as an absolute path - await devServer.transformRequest(`/@fs${parentId.startsWith('/') ? '' : '/'}${parentId}`); + await devServer.transformRequest(`/@fs${parentId}`); // The QRL segment should exist now + if (!outputs.has(id)) { + debug(`load(${count})`, `QRL segment ${id} not found in ${parentId}`); + return null; + } } } const transformedModule = outputs.get(id); if (transformedModule) { - debug(`load()`, 'Found', id); - let { code } = transformedModule[0]; - const { map, segment } = transformedModule[0]; - const firstInput = opts.input && Object.values(opts.input)[0]; - - if (devServer && firstInput) { - // doing this because vite will not use resolveId() when "noExternal" is false - // so we need to turn the @qwik-client-manifest import into a relative import - code = code.replace( - /@qwik-client-manifest/g, - normalizePath(path.resolve(firstInput, QWIK_CLIENT_MANIFEST_ID)) - ); - } + debug(`load(${count})`, 'Found', id); + const { code, map, segment } = transformedModule[0]; return { code, map, meta: { segment } }; } - debug('load()', 'Not found', id); + debug(`load(${count})`, 'Not a QRL or virtual module', id); return null; }; + let transformCount = 0; const transform = async function ( ctx: Rollup.PluginContext, code: string, @@ -629,6 +611,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { if (id.startsWith('\0')) { return; } + const count = transformCount++; const isServer = getIsServer(transformOpts); const currentOutputs = isServer ? serverTransformedOutputs : clientTransformedOutputs; if (currentOutputs.has(id)) { @@ -649,7 +632,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { const strip = opts.target === 'client' || opts.target === 'ssr'; const normalizedID = normalizePath(pathId); debug( - `transform()`, + `transform(${count})`, `Transforming ${id} (for: ${isServer ? 'server' : 'client'}${strip ? ', strip' : ''})` ); @@ -703,14 +686,6 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { const newOutput = optimizer.transformModulesSync(transformOpts); const module = newOutput.modules.find((mod) => !isAdditionalFile(mod))!; - if (devServer && isServer) { - // we're in dev mode. All QRLs that might be emitted in SSR HTML are defined here. - // register them so that they can be resolved by the dev server - const matches = module.code.matchAll(/_([a-zA-Z0-9]{11,11})['"][,)]/g); - for (const [, symbol] of matches) { - foundQrls.set(symbol, id); - } - } // uncomment to show transform results // debug({ isServer, strip }, transformOpts, newOutput); @@ -728,7 +703,8 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { for (const mod of newOutput.modules) { if (mod !== module) { const key = normalizePath(path.join(srcDir, mod.path)); - debug(`transform()`, `segment ${key}`, mod.segment?.displayName); + debug(`transform(${count})`, `segment ${key}`, mod.segment!.displayName); + parentIds.set(key, id); currentOutputs.set(key, [mod, id]); deps.add(key); if (opts.target === 'client') { @@ -770,7 +746,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { }; } - debug(`transform()`, 'Not transforming', id); + debug(`transform(${count})`, 'Not transforming', id); return null; }; @@ -848,7 +824,7 @@ export function createPlugin(optimizerOptions: OptimizerOptions = {}) { const normalizePath = (id: string) => lazyNormalizePath(id); - function getQwikBuildModule(isServer: boolean, target: QwikBuildTarget) { + function getQwikBuildModule(isServer: boolean, _target: QwikBuildTarget) { const isDev = opts.buildMode === 'development'; return `// @builder.io/qwik/build export const isServer = ${JSON.stringify(isServer)}; @@ -877,14 +853,17 @@ export const manifest = ${JSON.stringify(manifest)};\n`; debug('handleHotUpdate()', `invalidate ${id}`); serverResults.delete(id); clientResults.delete(id); - } - for (const dep of mod.info?.meta?.qwikdeps || []) { - debug('handleHotUpdate()', `invalidate segment ${dep}`); - serverTransformedOutputs.delete(dep); - clientTransformedOutputs.delete(dep); - const mod = ctx.server.moduleGraph.getModuleById(dep); - if (mod) { - ctx.server.moduleGraph.invalidateModule(mod); + for (const outputs of [clientTransformedOutputs, serverTransformedOutputs]) { + for (const [key, [_, parentId]] of outputs) { + if (parentId === id) { + debug('handleHotUpdate()', `invalidate ${id} segment ${key}`); + outputs.delete(key); + const mod = ctx.server.moduleGraph.getModuleById(key); + if (mod) { + ctx.server.moduleGraph.invalidateModule(mod); + } + } + } } } } @@ -919,7 +898,6 @@ export const manifest = ${JSON.stringify(manifest)};\n`; transform, validateSource, setSourceMapSupport, - foundQrls, configureServer, handleHotUpdate, manualChunks, @@ -963,13 +941,8 @@ export function parseId(originalId: string) { }; } -export function getSymbolHash(symbolName: string) { - const index = symbolName.lastIndexOf('_'); - if (index > -1) { - return symbolName.slice(index + 1); - } - return symbolName; -} +export const getSymbolHash = (symbolName: string) => + /_([a-z0-9]+)($|\.js($|\?))/.exec(symbolName)?.[1]; const TRANSFORM_EXTS = { '.jsx': true, @@ -977,15 +950,6 @@ const TRANSFORM_EXTS = { '.tsx': true, } as const; -const RESOLVE_EXTS = { - '.tsx': true, - '.ts': true, - '.jsx': true, - '.js': true, - '.mjs': true, - '.cjs': true, -} as const; - /** * Any file that matches this needs to be processed by Qwik to extract QRL segments etc. Used in * libraries. diff --git a/packages/qwik/src/optimizer/src/plugins/plugin.unit.ts b/packages/qwik/src/optimizer/src/plugins/plugin.unit.ts index 360e41fe5ad..1547bbb06fe 100644 --- a/packages/qwik/src/optimizer/src/plugins/plugin.unit.ts +++ b/packages/qwik/src/optimizer/src/plugins/plugin.unit.ts @@ -1,5 +1,5 @@ import path, { resolve } from 'node:path'; -import { assert, test } from 'vitest'; +import { assert, describe, expect, test } from 'vitest'; import type { QwikManifest } from '../types'; import { ExperimentalFeatures, createPlugin } from './plugin'; import { normalizePath } from '../../../testing/util'; @@ -218,12 +218,80 @@ test('experimental[]', async () => { assert.deepEqual(opts.experimental, { [flag]: true } as any); }); -async function mockPlugin() { +describe('resolveId', () => { + test('qrls', async () => { + const plugin = await mockPlugin(); + expect(plugin.resolveId(null!, 'foo', undefined)).toBeFalsy(); + const ctx = { resolve: async () => ({ id: 'Yey' }) } as any; + await expect( + plugin.resolveId( + ctx, + '/root/src/routes/layout.tsx_layout_component_usetask_1_7xk04rim0vu.js', + undefined + ) + ).resolves.toHaveProperty( + 'id', + '/root/src/routes/layout.tsx_layout_component_usetask_1_7xk04rim0vu.js' + ); + expect( + await plugin.resolveId(ctx, '/root/src/routes/layout.tsx_s_7xk04rim0vu.js', undefined) + ).toHaveProperty('id', '/root/src/routes/layout.tsx_s_7xk04rim0vu.js'); + expect(plugin.resolveId(null!, './foo', '/root/src/routes/layout.tsx')).toBeFalsy(); + expect( + await plugin.resolveId( + ctx, + './layout.tsx_layout_component_usetask_1_7xk04rim0vu.js', + '/root/src/routes/layout.tsx' + ) + ).toHaveProperty('id', '/root/src/routes/layout.tsx_layout_component_usetask_1_7xk04rim0vu.js'); + // this uses the already populated id we created above + expect( + await plugin.resolveId( + { + resolve: (id: string, importer: string) => { + expect(id).toBe('/root/src/routes/foo'); + expect(importer).toBe('Yey'); + return { id: 'hi' }; + }, + } as any, + './foo', + '/root/src/routes/layout.tsx_layout_component_usetask_1_7xk04rim0vu.js' + ) + ).toEqual({ id: 'hi' }); + }); + test('win32', async () => { + const plugin = await mockPlugin('win32'); + expect( + await plugin.resolveId( + { resolve: async () => 'Yey' } as any, + 'C:\\src\\routes\\layout.tsx_s_7xk04rim0vu.js', + undefined + ) + ).toHaveProperty('id', 'C:/src/routes/layout.tsx_s_7xk04rim0vu.js'); + }); + test('libs', async () => { + const plugin = await mockPlugin(); + expect(plugin.resolveId(null!, '@builder.io/qwik/build', undefined)).toHaveProperty( + 'id', + '/@builder.io/qwik/build' + ); + expect(plugin.resolveId(null!, '/@builder.io/qwik/build', undefined)).toHaveProperty( + 'id', + '/@builder.io/qwik/build' + ); + expect(plugin.resolveId(null!, '@qwik-client-manifest', '/foo/bar')).toHaveProperty( + 'id', + '/@qwik-client-manifest' + ); + }); +}); + +async function mockPlugin(os = process.platform) { const plugin = createPlugin({ sys: { cwd: () => process.cwd(), env: 'node', - os: process.platform, + os, dynamicImport: async (path) => import(path), strictDynamicImport: async (path) => import(path), path: path as any, diff --git a/packages/qwik/src/optimizer/src/plugins/vite-dev-server.ts b/packages/qwik/src/optimizer/src/plugins/vite-dev-server.ts index 04cafa4b542..fc2dcfafa58 100644 --- a/packages/qwik/src/optimizer/src/plugins/vite-dev-server.ts +++ b/packages/qwik/src/optimizer/src/plugins/vite-dev-server.ts @@ -5,14 +5,9 @@ import type { IncomingMessage, ServerResponse } from 'http'; import type { Connect, ViteDevServer } from 'vite'; import type { OptimizerSystem, Path, QwikManifest, SymbolMapper, SymbolMapperFn } from '../types'; -import { - type NormalizedQwikPluginOptions, - parseId, - getSymbolHash, - makeNormalizePath, -} from './plugin'; +import { type NormalizedQwikPluginOptions, parseId, makeNormalizePath } from './plugin'; import type { QwikViteDevResponse } from './vite'; -import { formatError, isWin } from './vite-utils'; +import { formatError } from './vite-utils'; import { VITE_ERROR_OVERLAY_STYLES } from './vite-error'; import imageDevTools from './image-size-runtime.html?raw'; import clickToComponent from './click-to-component.html?raw'; @@ -34,8 +29,13 @@ function getOrigin(req: IncomingMessage) { // We must encode the chunk so that e.g. + doesn't get converted to space etc const encode = (url: string) => - encodeURIComponent(url).replaceAll('%2F', '/').replaceAll('%40', '@').replaceAll('%3A', ':'); - + encodeURIComponent(url) + .replaceAll('%2F', '/') + .replaceAll('%40', '@') + .replaceAll('%3A', ':') + .replaceAll('%5B', '[') + .replaceAll('%5D', ']') + .replaceAll('%2C', ','); function createSymbolMapper( base: string, opts: NormalizedQwikPluginOptions, @@ -45,21 +45,13 @@ function createSymbolMapper( const normalizePath = makeNormalizePath(sys); return ( symbolName: string, - mapper: SymbolMapper | undefined, + _mapper: SymbolMapper | undefined, parent: string | undefined ): [string, string] => { if (symbolName === SYNC_QRL) { return [symbolName, '']; } - const hash = getSymbolHash(symbolName); if (!parent) { - console.warn( - `qwik vite-dev-server symbolMapper: parent not provided for ${symbolName}, falling back to mapper.` - ); - const chunk = mapper && mapper[hash]; - if (chunk) { - return [chunk[0], chunk[1]]; - } console.error( 'qwik vite-dev-server symbolMapper: unknown qrl requested without parent:', symbolName @@ -67,13 +59,12 @@ function createSymbolMapper( return [symbolName, `${base}${symbolName.toLowerCase()}.js`]; } // on windows, absolute paths don't start with a slash - const maybeSlash = isWin(sys.os) ? '/' : ''; const parentPath = normalizePath(path.dirname(parent)); const parentFile = path.basename(parent); const qrlPath = parentPath.startsWith(opts.rootDir) ? normalizePath(path.relative(opts.rootDir, parentPath)) - : `@fs${maybeSlash}${parentPath}`; - const qrlFile = `${encode(qrlPath)}/${parentFile.toLowerCase()}_${symbolName.toLowerCase()}.js?_qrl_parent=${encode(parentFile)}`; + : `@fs/${parentPath}`; + const qrlFile = encode(`${qrlPath}/${parentFile.toLowerCase()}_${symbolName.toLowerCase()}.js`); return [symbolName, `${base}${qrlFile}`]; }; } diff --git a/packages/qwik/src/optimizer/src/plugins/vite.ts b/packages/qwik/src/optimizer/src/plugins/vite.ts index d5c809b42cd..158188f6836 100644 --- a/packages/qwik/src/optimizer/src/plugins/vite.ts +++ b/packages/qwik/src/optimizer/src/plugins/vite.ts @@ -392,6 +392,14 @@ export function qwikVite(qwikViteOpts: QwikVitePluginOptions = {}): any { } else if (opts.target === 'lib') { // Library Build updatedViteConfig.build!.minify = false; + updatedViteConfig.build!.rollupOptions.external = [ + QWIK_CORE_ID, + QWIK_CORE_SERVER, + QWIK_JSX_RUNTIME_ID, + QWIK_JSX_DEV_RUNTIME_ID, + QWIK_BUILD_ID, + QWIK_CLIENT_MANIFEST_ID, + ]; } else { // Test Build updatedViteConfig.define = { From 6d706256336768b87ccbecd1b39cf612a18e41a5 Mon Sep 17 00:00:00 2001 From: Wout Mertens Date: Tue, 15 Oct 2024 18:25:08 +0200 Subject: [PATCH 24/28] fix(ci): update playwright Nix now supports playwright 1.47.0, and the old version broke CI --- flake.lock | 12 +-- package.json | 4 +- pnpm-lock.yaml | 247 ++++++++++++++++++++++--------------------------- 3 files changed, 121 insertions(+), 142 deletions(-) diff --git a/flake.lock b/flake.lock index a1e73124bbe..0594f4d0447 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1721138476, - "narHash": "sha256-+W5eZOhhemLQxelojLxETfbFbc19NWawsXBlapYpqIA=", + "lastModified": 1728888510, + "narHash": "sha256-nsNdSldaAyu6PE3YUA+YQLqUDJh+gRbBooMMekZJwvI=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ad0b5eed1b6031efaed382844806550c3dcb4206", + "rev": "a3c0b3b21515f74fd2665903d4ce6bc4dc81c77c", "type": "github" }, "original": { @@ -43,11 +43,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1721355572, - "narHash": "sha256-I4TQ2guV9jTmZsXeWt5HMojcaqNZHII4zu0xIKZEovM=", + "lastModified": 1728959392, + "narHash": "sha256-fp4he1QQjE+vasDMspZYeXrwTm9otwEqLwEN6FKZ5v0=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "d5bc7b1b21cf937fb8ff108ae006f6776bdb163d", + "rev": "4c6e317300f05b8871f585b826b6f583e7dc4a9b", "type": "github" }, "original": { diff --git a/package.json b/package.json index ab488d85ac9..e424719a072 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "dependencies": [ "@playwright/test" ], - "pinVersion": "1.40.0" + "pinVersion": "1.47.0" }, { "label": "Undici should always be * until we remove it", @@ -109,7 +109,7 @@ "@napi-rs/triples": "1.2.0", "@node-rs/helper": "1.6.0", "@octokit/action": "6.1.0", - "@playwright/test": "1.40.0", + "@playwright/test": "1.47.0", "@types/brotli": "1.3.4", "@types/bun": "1.1.6", "@types/cross-spawn": "6.0.6", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fe46a781c5c..08dce889bdd 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -68,8 +68,8 @@ importers: specifier: 6.1.0 version: 6.1.0 '@playwright/test': - specifier: 1.40.0 - version: 1.40.0 + specifier: 1.47.0 + version: 1.47.0 '@types/brotli': specifier: 1.3.4 version: 1.3.4 @@ -1162,9 +1162,11 @@ packages: '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-kit/esm-loader@2.6.5': resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-plugins/node-globals-polyfill@0.2.3': resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} @@ -2148,8 +2150,8 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@eslint-community/regexpp@4.11.0': - resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} + '@eslint-community/regexpp@4.11.1': + resolution: {integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} '@eslint/eslintrc@2.1.4': @@ -2924,9 +2926,9 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@playwright/test@1.40.0': - resolution: {integrity: sha512-PdW+kn4eV99iP5gxWNSDQCbhMaDVej+RXL5xr6t04nbKLCBwYtA046t7ofoczHOm8u6c+45hpDKQVZqtqwkeQg==} - engines: {node: '>=16'} + '@playwright/test@1.47.0': + resolution: {integrity: sha512-SgAdlSwYVpToI4e/IH19IHHWvoijAYH5hu2MWSXptRypLSnzj51PcGD+rsOXFayde4P9ZLi+loXVwArg6IUkCA==} + engines: {node: '>=18'} hasBin: true '@pnpm/config.env-replace@1.1.0': @@ -3260,9 +3262,6 @@ packages: '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - '@types/mime@3.0.4': - resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==} - '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} @@ -3299,11 +3298,11 @@ packages: '@types/prompts@2.4.9': resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==} - '@types/prop-types@15.7.12': - resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} + '@types/prop-types@15.7.13': + resolution: {integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==} - '@types/qs@6.9.11': - resolution: {integrity: sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==} + '@types/qs@6.9.16': + resolution: {integrity: sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A==} '@types/range-parser@1.2.7': resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} @@ -3329,8 +3328,8 @@ packages: '@types/send@0.17.4': resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} - '@types/serve-static@1.15.5': - resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==} + '@types/serve-static@1.15.7': + resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} '@types/set-cookie-parser@2.4.10': resolution: {integrity: sha512-GGmQVGpQWUe5qglJozEjZV/5dyxbOOZ0LHe/lqyWssB88Y4svNfst0uqBVscdDeIKl5Jy5+aPSvy7mI9tYRguw==} @@ -4516,8 +4515,8 @@ packages: supports-color: optional: true - debug@4.3.6: - resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -5155,21 +5154,22 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint-visitor-keys@4.0.0: - resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} + eslint-visitor-keys@4.1.0: + resolution: {integrity: sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true esniff@2.0.1: resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} engines: {node: '>=0.10'} - espree@10.1.0: - resolution: {integrity: sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==} + espree@10.2.0: + resolution: {integrity: sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} espree@9.6.1: @@ -5978,8 +5978,8 @@ packages: resolution: {integrity: sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} image-meta@0.2.0: @@ -6568,6 +6568,7 @@ packages: libsql@0.3.18: resolution: {integrity: sha512-lvhKr7WV3NLWRbXkjn/MeKqXOAqWKU0PX9QYrvDh7fneukapj+iUQ4qgJASrQyxcCrEsClXCQiiK5W6OoYPAlA==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] light-my-request@5.11.1: @@ -7260,8 +7261,8 @@ packages: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} - node-gyp-build@4.8.1: - resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==} + node-gyp-build@4.8.2: + resolution: {integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==} hasBin: true node-releases@2.0.14: @@ -7736,14 +7737,14 @@ packages: pkg-types@1.0.3: resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} - playwright-core@1.40.0: - resolution: {integrity: sha512-fvKewVJpGeca8t0ipM56jkVSU6Eo0RmFvQ/MaCQNDYm+sdvKkMBBWTE1FdeMqIdumRaXXjZChWHvIzCGM/tA/Q==} - engines: {node: '>=16'} + playwright-core@1.47.0: + resolution: {integrity: sha512-1DyHT8OqkcfCkYUD9zzUTfg7EfTd+6a8MkD/NWOvjo0u/SCNd5YmY/lJwFvUZOxJbWNds+ei7ic2+R/cRz/PDg==} + engines: {node: '>=18'} hasBin: true - playwright@1.40.0: - resolution: {integrity: sha512-gyHAgQjiDf1m34Xpwzaqb76KgfzYrhK7iih+2IzcOCoZWr/8ZqmdBw+t0RU85ZmfJMgtgAiNtBQ/KS2325INXw==} - engines: {node: '>=16'} + playwright@1.47.0: + resolution: {integrity: sha512-jOWiRq2pdNAX/mwLiwFYnPHpEZ4rM+fRSQpRHwEwZlP2PUANvL3+aJOF/bvISMhFD30rqMxUB4RJx9aQbfh4Ww==} + engines: {node: '>=18'} hasBin: true possible-typed-array-names@1.0.0: @@ -8012,10 +8013,6 @@ packages: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} - qs@6.11.2: - resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} - engines: {node: '>=0.6'} - qs@6.13.0: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} @@ -8482,16 +8479,11 @@ packages: shikiji-core@0.9.19: resolution: {integrity: sha512-AFJu/vcNT21t0e6YrfadZ+9q86gvPum6iywRyt1OtIPjPFe25RQnYJyxHQPMLKCCWA992TPxmEmbNcOZCAJclw==} - deprecated: Shikiji is merged back to Shiki v1.0, please migrate over to get the latest updates shikiji@0.9.19: resolution: {integrity: sha512-Kw2NHWktdcdypCj1GkKpXH4o6Vxz8B8TykPlPuLHOGSV8VkhoCLcFOH4k19K4LXAQYRQmxg+0X/eM+m2sLhAkg==} deprecated: Shikiji is merged back to Shiki v1.0, please migrate over to get the latest updates - side-channel@1.0.5: - resolution: {integrity: sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==} - engines: {node: '>= 0.4'} - side-channel@1.0.6: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} @@ -9190,8 +9182,8 @@ packages: unenv-nightly@1.10.0-1717606461.a117952: resolution: {integrity: sha512-u3TfBX02WzbHTpaEfWEKwDijDSFAHcgXkayUZ+MVDrjhLFvgAJzFGTSTmwlEhwWi2exyRQey23ah9wELMM6etg==} - unenv@1.9.0: - resolution: {integrity: sha512-QKnFNznRxmbOF1hDgzpqrlIf6NC5sbZ2OJ+5Wl3OX8uM+LUJXbj4TXvLJCtwbPTmbMHCLIz6JLKNinNsMShK9g==} + unenv@1.10.0: + resolution: {integrity: sha512-wY5bskBQFL9n3Eca5XnhH6KbUo/tfvkwm9OpcdCvLaeA7piBNbavbOKJySEwQ1V0RH6HvNlSAFRTpvTqgKRQXQ==} unicorn-magic@0.1.0: resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} @@ -10835,15 +10827,15 @@ snapshots: eslint: 8.57.0 eslint-visitor-keys: 3.4.3 - '@eslint-community/regexpp@4.11.0': {} + '@eslint-community/regexpp@4.11.1': {} '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) espree: 9.6.1 globals: 13.24.0 - ignore: 5.3.1 + ignore: 5.3.2 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -10854,10 +10846,10 @@ snapshots: '@eslint/eslintrc@3.1.0': dependencies: ajv: 6.12.6 - debug: 4.3.6(supports-color@9.4.0) - espree: 10.1.0 + debug: 4.3.7(supports-color@9.4.0) + espree: 10.2.0 globals: 14.0.0 - ignore: 5.3.1 + ignore: 5.3.2 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -10925,7 +10917,7 @@ snapshots: '@humanwhocodes/config-array@0.11.14': dependencies: '@humanwhocodes/object-schema': 2.0.2 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -11147,7 +11139,7 @@ snapshots: '@mapbox/node-pre-gyp@1.0.11(supports-color@9.4.0)': dependencies: - detect-libc: 2.0.2 + detect-libc: 2.0.3 https-proxy-agent: 5.0.1(supports-color@9.4.0) make-dir: 3.1.0 node-fetch: 2.7.0 @@ -11333,7 +11325,7 @@ snapshots: dependencies: '@babel/runtime': 7.23.9 '@mui/types': 7.2.15(@types/react@18.3.3) - '@types/prop-types': 15.7.12 + '@types/prop-types': 15.7.13 clsx: 2.1.1 prop-types: 15.8.1 react: 18.3.1 @@ -11875,9 +11867,9 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@playwright/test@1.40.0': + '@playwright/test@1.47.0': dependencies: - playwright: 1.40.0 + playwright: 1.47.0 '@pnpm/config.env-replace@1.1.0': {} @@ -11897,7 +11889,7 @@ snapshots: '@puppeteer/browsers@2.2.4': dependencies: - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) extract-zip: 2.0.1 progress: 2.0.3 proxy-agent: 6.4.0 @@ -12170,7 +12162,7 @@ snapshots: '@types/express-serve-static-core@4.17.43': dependencies: '@types/node': 20.14.11 - '@types/qs': 6.9.11 + '@types/qs': 6.9.16 '@types/range-parser': 1.2.7 '@types/send': 0.17.4 @@ -12178,8 +12170,8 @@ snapshots: dependencies: '@types/body-parser': 1.19.5 '@types/express-serve-static-core': 4.17.43 - '@types/qs': 6.9.11 - '@types/serve-static': 1.15.5 + '@types/qs': 6.9.16 + '@types/serve-static': 1.15.7 '@types/geojson@7946.0.14': {} @@ -12223,8 +12215,6 @@ snapshots: '@types/mime@1.3.5': {} - '@types/mime@3.0.4': {} - '@types/ms@0.7.34': {} '@types/node-fetch@2.6.11': @@ -12261,9 +12251,9 @@ snapshots: '@types/node': 20.14.11 kleur: 3.0.3 - '@types/prop-types@15.7.12': {} + '@types/prop-types@15.7.13': {} - '@types/qs@6.9.11': {} + '@types/qs@6.9.16': {} '@types/range-parser@1.2.7': {} @@ -12277,7 +12267,7 @@ snapshots: '@types/react@18.3.3': dependencies: - '@types/prop-types': 15.7.12 + '@types/prop-types': 15.7.13 csstype: 3.1.3 '@types/refractor@3.4.1': @@ -12293,11 +12283,11 @@ snapshots: '@types/mime': 1.3.5 '@types/node': 20.14.11 - '@types/serve-static@1.15.5': + '@types/serve-static@1.15.7': dependencies: '@types/http-errors': 2.0.4 - '@types/mime': 3.0.4 '@types/node': 20.14.11 + '@types/send': 0.17.4 '@types/set-cookie-parser@2.4.10': dependencies: @@ -12338,7 +12328,7 @@ snapshots: '@typescript-eslint/eslint-plugin@7.16.1(@typescript-eslint/parser@7.16.1(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)': dependencies: - '@eslint-community/regexpp': 4.11.0 + '@eslint-community/regexpp': 4.11.1 '@typescript-eslint/parser': 7.16.1(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/scope-manager': 7.16.1 '@typescript-eslint/type-utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5) @@ -12346,7 +12336,7 @@ snapshots: '@typescript-eslint/visitor-keys': 7.16.1 eslint: 8.57.0 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 natural-compare: 1.4.0 ts-api-utils: 1.3.0(typescript@5.4.5) optionalDependencies: @@ -12360,7 +12350,7 @@ snapshots: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) '@typescript-eslint/visitor-keys': 7.16.1 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) eslint: 8.57.0 optionalDependencies: typescript: 5.4.5 @@ -12394,7 +12384,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 7.16.1(typescript@5.4.5) '@typescript-eslint/utils': 7.16.1(eslint@8.57.0)(typescript@5.4.5) - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) eslint: 8.57.0 ts-api-utils: 1.3.0(typescript@5.4.5) optionalDependencies: @@ -12412,7 +12402,7 @@ snapshots: dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.3 @@ -12426,7 +12416,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.16.1 '@typescript-eslint/visitor-keys': 7.16.1 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -12441,7 +12431,7 @@ snapshots: dependencies: '@typescript-eslint/types': 7.8.0 '@typescript-eslint/visitor-keys': 7.8.0 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.4 @@ -12525,7 +12515,7 @@ snapshots: glob: 7.2.3 graceful-fs: 4.2.11 micromatch: 4.0.5 - node-gyp-build: 4.8.1 + node-gyp-build: 4.8.2 resolve-from: 5.0.0 transitivePeerDependencies: - encoding @@ -12686,13 +12676,13 @@ snapshots: agent-base@6.0.2(supports-color@9.4.0): dependencies: - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color agent-base@7.1.0: dependencies: - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -12953,7 +12943,7 @@ snapshots: dependencies: '@fastify/error': 3.4.1 archy: 1.0.0 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) fastq: 1.17.1 transitivePeerDependencies: - supports-color @@ -13138,7 +13128,7 @@ snapshots: bufferutil@4.0.8: dependencies: - node-gyp-build: 4.8.1 + node-gyp-build: 4.8.2 builtin-modules@3.3.0: {} @@ -13199,7 +13189,7 @@ snapshots: capnp-ts@0.7.0: dependencies: - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) tslib: 2.6.2 transitivePeerDependencies: - supports-color @@ -13672,9 +13662,9 @@ snapshots: dependencies: ms: 2.1.2 - debug@4.3.6(supports-color@9.4.0): + debug@4.3.7(supports-color@9.4.0): dependencies: - ms: 2.1.2 + ms: 2.1.3 optionalDependencies: supports-color: 9.4.0 @@ -14123,7 +14113,7 @@ snapshots: esbuild-register@3.5.0(esbuild@0.19.12): dependencies: - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) esbuild: 0.19.12 transitivePeerDependencies: - supports-color @@ -14374,12 +14364,12 @@ snapshots: eslint-visitor-keys@3.4.3: {} - eslint-visitor-keys@4.0.0: {} + eslint-visitor-keys@4.1.0: {} eslint@8.57.0: dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.11.0 + '@eslint-community/regexpp': 4.11.1 '@eslint/eslintrc': 2.1.4 '@eslint/js': 8.57.0 '@humanwhocodes/config-array': 0.11.14 @@ -14389,7 +14379,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 @@ -14403,7 +14393,7 @@ snapshots: glob-parent: 6.0.2 globals: 13.24.0 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 @@ -14426,11 +14416,11 @@ snapshots: event-emitter: 0.3.5 type: 2.7.2 - espree@10.1.0: + espree@10.2.0: dependencies: acorn: 8.12.1 acorn-jsx: 5.3.2(acorn@8.12.1) - eslint-visitor-keys: 4.0.0 + eslint-visitor-keys: 4.1.0 espree@9.6.1: dependencies: @@ -14652,7 +14642,7 @@ snapshots: extract-zip@2.0.1: dependencies: - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) get-stream: 5.2.0 yauzl: 2.10.0 optionalDependencies: @@ -15041,7 +15031,7 @@ snapshots: dependencies: basic-ftp: 5.0.4 data-uri-to-buffer: 6.0.2 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) fs-extra: 11.2.0 transitivePeerDependencies: - supports-color @@ -15127,7 +15117,7 @@ snapshots: array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.3.2 - ignore: 5.3.1 + ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0 @@ -15135,7 +15125,7 @@ snapshots: dependencies: dir-glob: 3.0.1 fast-glob: 3.3.2 - ignore: 5.3.1 + ignore: 5.3.2 merge2: 1.4.1 slash: 4.0.0 @@ -15143,7 +15133,7 @@ snapshots: dependencies: '@sindresorhus/merge-streams': 2.3.0 fast-glob: 3.3.2 - ignore: 5.3.1 + ignore: 5.3.2 path-type: 5.0.0 slash: 5.1.0 unicorn-magic: 0.1.0 @@ -15195,7 +15185,7 @@ snapshots: radix3: 1.1.0 ufo: 1.5.4 uncrypto: 0.1.3 - unenv: 1.9.0 + unenv: 1.10.0 hanji@0.0.5: dependencies: @@ -15399,7 +15389,7 @@ snapshots: http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -15433,14 +15423,14 @@ snapshots: https-proxy-agent@5.0.1(supports-color@9.4.0): dependencies: agent-base: 6.0.2(supports-color@9.4.0) - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color https-proxy-agent@7.0.5: dependencies: agent-base: 7.1.0 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color @@ -15466,7 +15456,7 @@ snapshots: dependencies: minimatch: 9.0.4 - ignore@5.3.1: {} + ignore@5.3.2: {} image-meta@0.2.0: {} @@ -15588,13 +15578,13 @@ snapshots: dependencies: es-errors: 1.3.0 hasown: 2.0.1 - side-channel: 1.0.5 + side-channel: 1.0.6 ioredis@5.3.2: dependencies: '@ioredis/commands': 1.2.0 cluster-key-slot: 1.1.2 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) denque: 2.1.0 lodash.defaults: 4.2.0 lodash.isarguments: 3.1.0 @@ -16777,7 +16767,7 @@ snapshots: micromark@4.0.0: dependencies: '@types/debug': 4.1.12 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.0 @@ -17122,7 +17112,7 @@ snapshots: node-fetch: 3.3.2 omit.js: 2.0.2 p-wait-for: 4.1.0 - qs: 6.11.2 + qs: 6.13.0 netmask@2.0.2: {} @@ -17156,7 +17146,7 @@ snapshots: node-forge@1.3.1: {} - node-gyp-build@4.8.1: {} + node-gyp-build@4.8.2: {} node-releases@2.0.14: {} @@ -17517,7 +17507,7 @@ snapshots: dependencies: '@tootallnate/quickjs-emscripten': 0.23.0 agent-base: 7.1.0 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) get-uri: 6.0.3 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 @@ -17686,11 +17676,11 @@ snapshots: mlly: 1.6.1 pathe: 1.1.2 - playwright-core@1.40.0: {} + playwright-core@1.47.0: {} - playwright@1.40.0: + playwright@1.47.0: dependencies: - playwright-core: 1.40.0 + playwright-core: 1.47.0 optionalDependencies: fsevents: 2.3.2 @@ -17750,7 +17740,7 @@ snapshots: prebuild-install@7.1.1: dependencies: - detect-libc: 2.0.2 + detect-libc: 2.0.3 expand-template: 2.0.3 github-from-package: 0.0.0 minimist: 1.2.8 @@ -17826,7 +17816,7 @@ snapshots: dependencies: execa: 5.1.1 find-up: 5.0.0 - ignore: 5.3.1 + ignore: 5.3.2 mri: 1.2.0 picocolors: 1.0.1 picomatch: 3.0.1 @@ -17881,7 +17871,7 @@ snapshots: proxy-agent@6.4.0: dependencies: agent-base: 7.1.0 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.5 lru-cache: 7.18.3 @@ -17917,7 +17907,7 @@ snapshots: dependencies: '@puppeteer/browsers': 2.2.4 chromium-bidi: 0.6.1(devtools-protocol@0.0.1299070) - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) devtools-protocol: 0.0.1299070 ws: 8.18.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) transitivePeerDependencies: @@ -17941,11 +17931,7 @@ snapshots: qs@6.11.0: dependencies: - side-channel: 1.0.5 - - qs@6.11.2: - dependencies: - side-channel: 1.0.5 + side-channel: 1.0.6 qs@6.13.0: dependencies: @@ -18490,7 +18476,7 @@ snapshots: sharp@0.32.6: dependencies: color: 4.2.3 - detect-libc: 2.0.2 + detect-libc: 2.0.3 node-addon-api: 6.1.0 prebuild-install: 7.1.1 semver: 7.6.3 @@ -18551,13 +18537,6 @@ snapshots: dependencies: shikiji-core: 0.9.19 - side-channel@1.0.5: - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - object-inspect: 1.13.1 - side-channel@1.0.6: dependencies: call-bind: 1.0.7 @@ -18620,7 +18599,7 @@ snapshots: socks-proxy-agent@8.0.2: dependencies: agent-base: 7.1.0 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) socks: 2.8.1 transitivePeerDependencies: - supports-color @@ -18935,7 +18914,7 @@ snapshots: tabtab@3.0.2: dependencies: - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) es6-promisify: 6.1.1 inquirer: 6.5.2 minimist: 1.2.8 @@ -19284,7 +19263,7 @@ snapshots: pathe: 1.1.2 ufo: 1.5.4 - unenv@1.9.0: + unenv@1.10.0: dependencies: consola: 3.2.3 defu: 6.1.4 @@ -19419,7 +19398,7 @@ snapshots: utf-8-validate@5.0.10: dependencies: - node-gyp-build: 4.8.1 + node-gyp-build: 4.8.2 util-deprecate@1.0.2: {} @@ -19488,7 +19467,7 @@ snapshots: vite-node@0.32.4(@types/node@20.14.11)(terser@5.31.3): dependencies: cac: 6.7.14 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) mlly: 1.6.1 pathe: 1.1.2 picocolors: 1.0.1 @@ -19506,7 +19485,7 @@ snapshots: vite-node@2.0.5(@types/node@20.14.11)(terser@5.31.3): dependencies: cac: 6.7.14 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) pathe: 1.1.2 tinyrainbow: 1.2.0 vite: 5.3.5(@types/node@20.14.11)(terser@5.31.3) @@ -19525,7 +19504,7 @@ snapshots: '@microsoft/api-extractor': 7.43.0(@types/node@20.14.11) '@rollup/pluginutils': 5.1.0(rollup@4.19.0) '@vue/language-core': 1.8.27(typescript@5.4.5) - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) kolorist: 1.8.0 magic-string: 0.30.11 typescript: 5.4.5 @@ -19541,7 +19520,7 @@ snapshots: dependencies: '@antfu/utils': 0.7.10 '@rollup/pluginutils': 5.1.0(rollup@4.19.0) - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) error-stack-parser-es: 0.1.5 fs-extra: 11.2.0 open: 10.1.0 @@ -19563,7 +19542,7 @@ snapshots: vite-tsconfig-paths@4.3.2(typescript@5.4.5)(vite@5.3.5(@types/node@20.14.11)(terser@5.31.3)): dependencies: - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) globrex: 0.1.2 tsconfck: 3.0.3(typescript@5.4.5) optionalDependencies: @@ -19602,7 +19581,7 @@ snapshots: '@vitest/spy': 2.0.5 '@vitest/utils': 2.0.5 chai: 5.1.1 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) execa: 8.0.1 magic-string: 0.30.11 pathe: 1.1.2 @@ -19644,7 +19623,7 @@ snapshots: dependencies: chalk: 4.1.2 commander: 9.5.0 - debug: 4.3.6(supports-color@9.4.0) + debug: 4.3.7(supports-color@9.4.0) transitivePeerDependencies: - supports-color From bf4b330cba2a3989102f6b146ea07abfcee5f996 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C5=A1ko=20Hevery?= Date: Tue, 15 Oct 2024 21:24:16 -0400 Subject: [PATCH 25/28] fix(insights): add query limits to prevent render timeout (#6980) --- packages/insights/src/db/query.ts | 2 +- packages/insights/src/db/sql-manifest.ts | 3 +++ packages/insights/src/db/sql-routes.ts | 3 +++ packages/insights/src/db/sql-user.ts | 2 ++ .../insights/src/routes/api/v1/[publicApiKey]/post/index.tsx | 4 +++- .../src/routes/api/v1/[publicApiKey]/post/manifest/index.tsx | 1 + .../insights/src/routes/app/[publicApiKey]/errors/index.tsx | 1 + packages/insights/src/routes/app/index.tsx | 2 +- 8 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/insights/src/db/query.ts b/packages/insights/src/db/query.ts index 55308c45348..5799cd51eb5 100644 --- a/packages/insights/src/db/query.ts +++ b/packages/insights/src/db/query.ts @@ -47,7 +47,7 @@ export async function getEdges( .from(edgeTable) .where(where) .groupBy(edgeTable.from, edgeTable.to) - .limit(limit || 10_000); // TODO: The 10_000 limit is due to Turso serialization format not being efficient, upgrade this once Turso is fixed. + .limit(limit || 5_000); // TODO: The 5_000 limit is due to Turso serialization format not being efficient, upgrade this once Turso is fixed. const rows = await query.all(); return rows.map((e) => ({ from: e.from, diff --git a/packages/insights/src/db/sql-manifest.ts b/packages/insights/src/db/sql-manifest.ts index f1bcb8d9d35..7b09b32cd75 100644 --- a/packages/insights/src/db/sql-manifest.ts +++ b/packages/insights/src/db/sql-manifest.ts @@ -12,6 +12,7 @@ export async function dbGetManifests( .from(manifestTable) .where(and(eq(manifestTable.publicApiKey, publicApiKey))) .orderBy(sql`${manifestTable.timestamp} DESC`) + .limit(1000) .all(); return manifests; } @@ -37,6 +38,7 @@ export async function dbGetManifestStats( .where(and(eq(manifestTable.publicApiKey, publicApiKey))) .groupBy(manifestTable.hash) .orderBy(sql`${manifestTable.timestamp} DESC`) + .limit(1000) .all(); return manifests.map((manifest) => { return { @@ -94,6 +96,7 @@ export async function dbGetManifestHashes( .where(and(eq(manifestTable.publicApiKey, publicApiKey))) .groupBy(manifestTable.hash) .orderBy(sql`${manifestTable.timestamp} DESC`) + .limit(1000) .all(); const hashes: string[] = []; let sum = 0; diff --git a/packages/insights/src/db/sql-routes.ts b/packages/insights/src/db/sql-routes.ts index 565cd15c068..1a3162006b2 100644 --- a/packages/insights/src/db/sql-routes.ts +++ b/packages/insights/src/db/sql-routes.ts @@ -30,6 +30,7 @@ export async function getRoutes( .where(where) .groupBy(routesTable.route, routesTable.symbol) .orderBy(sql`${routesTable.route}`, desc(sumTimelineCount)) + .limit(1000) .all(); return query.map((row) => ({ route: row.route, @@ -63,6 +64,7 @@ export async function getRouteNames( .where(where) .groupBy(routesTable.route) .orderBy(sql`${routesTable.route}`) + .limit(1000) .all(); return query.map((row) => ({ route: row.route, @@ -99,6 +101,7 @@ export async function getRouteTimeline( .where(where) .groupBy(routesTable.route, routesTable.symbol) .orderBy(sql`${routesTable.route}`, desc(sumTimelineCount)) + .limit(1000) .all(); return query.map((row) => ({ route: row.route, diff --git a/packages/insights/src/db/sql-user.ts b/packages/insights/src/db/sql-user.ts index 4e1da01865b..d7f18fb985a 100644 --- a/packages/insights/src/db/sql-user.ts +++ b/packages/insights/src/db/sql-user.ts @@ -40,6 +40,7 @@ export const dbGetInsightUser = async (email: string): Promise => .leftJoin(userApplicationMap, eq(usersTable.id, userApplicationMap.userId)) .leftJoin(applicationTable, eq(applicationTable.id, userApplicationMap.applicationId)) .where(eq(usersTable.email, email)) + .limit(1000) .all(); if (users.length === 0) { const insert = await db @@ -72,6 +73,7 @@ export const dbGetUsersForApplication = async (publicApiKey: string) => { .leftJoin(applicationTable, eq(applicationTable.id, userApplicationMap.applicationId)) .where(eq(applicationTable.publicApiKey, publicApiKey)) .orderBy(usersTable.email) + .limit(1000) .all(); return users.map((user) => user.email); }; diff --git a/packages/insights/src/routes/api/v1/[publicApiKey]/post/index.tsx b/packages/insights/src/routes/api/v1/[publicApiKey]/post/index.tsx index 8d4f072787f..51e3622449c 100644 --- a/packages/insights/src/routes/api/v1/[publicApiKey]/post/index.tsx +++ b/packages/insights/src/routes/api/v1/[publicApiKey]/post/index.tsx @@ -9,7 +9,9 @@ export const onPost: RequestHandler = async ({ exit, json, request, params }) => const payloadJson = await request.json(); migrate1(payloadJson); // publicApiKey is always part of the URL as route parameter. - payloadJson.publicApiKey = params.publicApiKey; + if (!payloadJson.publicApiKey) { + payloadJson.publicApiKey = params.publicApiKey; + } const payload = InsightsPayload.parse(payloadJson); // console.log('API: POST: symbol', payload); exit(); diff --git a/packages/insights/src/routes/api/v1/[publicApiKey]/post/manifest/index.tsx b/packages/insights/src/routes/api/v1/[publicApiKey]/post/manifest/index.tsx index b8f0ec2f9dc..47a6093914b 100644 --- a/packages/insights/src/routes/api/v1/[publicApiKey]/post/manifest/index.tsx +++ b/packages/insights/src/routes/api/v1/[publicApiKey]/post/manifest/index.tsx @@ -22,6 +22,7 @@ export const onPost: RequestHandler = async ({ exit, json, request, params }) => eq(symbolDetailTable.manifestHash, manifestHash) ) ) + .limit(1000) .all(); const existingMap = new Map(); existing.forEach((row) => existingMap.set(row.hash, row)); diff --git a/packages/insights/src/routes/app/[publicApiKey]/errors/index.tsx b/packages/insights/src/routes/app/[publicApiKey]/errors/index.tsx index e1ed77aa04b..d1a030f53f0 100644 --- a/packages/insights/src/routes/app/[publicApiKey]/errors/index.tsx +++ b/packages/insights/src/routes/app/[publicApiKey]/errors/index.tsx @@ -13,6 +13,7 @@ export const useErrors = routeLoader$(async ({ params }) => { .where(eq(errorTable.publicApiKey, params.publicApiKey)) .limit(1000) .orderBy(sql`${errorTable.timestamp} DESC`) + .limit(1000) .all(); return errors; }); diff --git a/packages/insights/src/routes/app/index.tsx b/packages/insights/src/routes/app/index.tsx index e746a631c3c..410d317e5d3 100644 --- a/packages/insights/src/routes/app/index.tsx +++ b/packages/insights/src/routes/app/index.tsx @@ -21,7 +21,7 @@ export const useApps = routeLoader$(async ({ sharedMap }) => { // The user has nothing attached to it. return []; } - return query.all(); + return query.limit(1000).all(); }); export default component$(() => { From cc253b5fb6d46c8953048c1dc4e121537d977acf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mi=C5=A1ko=20Hevery?= Date: Tue, 15 Oct 2024 21:28:56 -0400 Subject: [PATCH 26/28] Pr insights sql fix (#6981) * fix(insights): add query limits to prevent render timeout * fix(insights): add query limits to prevent render timeout From 7e5b7a3dd1b5419c284d793cd3d4554c29a7c787 Mon Sep 17 00:00:00 2001 From: Varixo Date: Thu, 17 Oct 2024 15:59:24 +0200 Subject: [PATCH 27/28] fix insights build --- .../src/routes/api/v1/[publicApiKey]/post/index.tsx | 6 +++--- .../insights/src/routes/app/[publicApiKey]/errors/index.tsx | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/insights/src/routes/api/v1/[publicApiKey]/post/index.tsx b/packages/insights/src/routes/api/v1/[publicApiKey]/post/index.tsx index 51e3622449c..78fb608f58b 100644 --- a/packages/insights/src/routes/api/v1/[publicApiKey]/post/index.tsx +++ b/packages/insights/src/routes/api/v1/[publicApiKey]/post/index.tsx @@ -47,10 +47,10 @@ export const onPost: RequestHandler = async ({ exit, json, request, params }) => } }; -function cleanupSymbolName(symbolName?: string | null) { - if (!symbolName) return; +function cleanupSymbolName(symbolName?: string | null): string | null { + if (!symbolName) return null; const shortName = symbolName.substring(symbolName.lastIndexOf('_') + 1 || 0); - if (shortName == 'hW') return; + if (shortName == 'hW') return null; return shortName; } function migrate1(payloadJson: any) { diff --git a/packages/insights/src/routes/app/[publicApiKey]/errors/index.tsx b/packages/insights/src/routes/app/[publicApiKey]/errors/index.tsx index d1a030f53f0..9c1123546a7 100644 --- a/packages/insights/src/routes/app/[publicApiKey]/errors/index.tsx +++ b/packages/insights/src/routes/app/[publicApiKey]/errors/index.tsx @@ -11,7 +11,6 @@ export const useErrors = routeLoader$(async ({ params }) => { .select() .from(errorTable) .where(eq(errorTable.publicApiKey, params.publicApiKey)) - .limit(1000) .orderBy(sql`${errorTable.timestamp} DESC`) .limit(1000) .all(); From 1bce01b9463daea4a1933dd718954f4f2917f664 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harris=20Brakmi=C4=87?= Date: Sat, 19 Oct 2024 19:15:01 +0200 Subject: [PATCH 28/28] docs: clarify wording (#6990) clarify wording The original text wrongly implied that Qwik's tools increase JavaScript, which goes against what Qwik is all about. I reworded it to clarify that the issue applies to general tools, not Qwik's. --- .../docs/src/routes/docs/(qwik)/concepts/think-qwik/index.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docs/src/routes/docs/(qwik)/concepts/think-qwik/index.mdx b/packages/docs/src/routes/docs/(qwik)/concepts/think-qwik/index.mdx index 0fb4d6def86..4b4f22001a2 100644 --- a/packages/docs/src/routes/docs/(qwik)/concepts/think-qwik/index.mdx +++ b/packages/docs/src/routes/docs/(qwik)/concepts/think-qwik/index.mdx @@ -56,7 +56,7 @@ The solution to the above problem is both obvious and hard: Ship less JavaScript The obvious part is that sites with less JavaScript will perform better. -The hard part is our tools don't help us to get there. The majority of Qwik's tools solve problems in a way that makes shipping less JavaScript hard. These tools are designed to solve a specific problem without thinking about the amount of JavaScript they generate. +The hard part is that our tools don't help us achieve this. Most of them solve problems in a way that makes shipping less JavaScript hard. These tools are designed to address specific issues without considering how much JavaScript they produce. Do you need to solve rendering, styling, animation, A/B testing, analytics, etc.? There is a tool for that. Just import or add a `